这是网上一个人写的程序,我给加了注释,对于大家理解程序很有帮助,但是始终不明到两个操作数是怎样传递给Tmp1和Tmp2的!
/*
* Easy calculator
*
* K4:+ K8:- K12:* K16:/ K14:Clear K15:=
*
* Made by Kingst-刚哥
* date: 2010.12.21
*/
#include <reg52.h>
typedef unsigned char uint8;
typedef unsigned int uint16;
typedef unsigned long uint32;
typedef char int8;
typedef int int16;
typedef long int32;
sbit KeyIn1 = P2^4;
sbit KeyIn2 = P2^5;
sbit KeyIn3 = P2^6;
sbit KeyIn4 = P2^7;
sbit KeyOut1 = P2^3;
sbit KeyOut2 = P2^2;
sbit KeyOut3 = P2^1;
sbit KeyOut4 = P2^0;
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit BUZZ = P1^6; //蜂鸣器控制位
#define FADD 10
#define FSUB 11
#define FMUL 12
#define FDIV 13
#define FRES 14
#define FEQU 15
#define KEY_DELAY 300 //延时常数
#define BUZ_DELAY 80
code uint8 Ledcode[13]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf,0x86};
uint8 Led_n=0; //co为0,f9为1,类推
uint8 Led_buf[6]; //定义Led_buf[6]数?
float Tmp1=0, Tmp2=0; //用于存储输入的两个变量
int8 C_flag=0;
/*
* 延时
*/
void delay(uint16 n)
{
while (n--);
}
/*
* 蜂鸣器发声
*/
void buzzer_sound(void)
{
uint16 i;
for (i=0; i<BUZ_DELAY; i++)
{
BUZZ = ~BUZZ; //BUZZ初始状态为高电平,蜂鸣器熄灭
delay(100);
}
BUZZ = 1;
}
/*
* 按键扫描
*/
int8 scan_key(void)
{
int8 val=-1; //此处未初始化val,val为按键的标志位
//当没有按键时,val的值为-1
KeyOut1 = 0;
KeyOut2 = 1;
KeyOut3 = 1;
KeyOut4 = 1;
if (KeyIn1 == 0)
{
delay(KEY_DELAY);
if (KeyIn1 == 0)
val = 1;
}
if (KeyIn2 == 0)
{
delay(KEY_DELAY);
if (KeyIn2 == 0)
val = 2;
}
if (KeyIn3 == 0)
{
delay(KEY_DELAY);
if (KeyIn3 == 0)
val = 3;
}
if (KeyIn4 == 0)
{
delay(KEY_DELAY);
if (KeyIn4 == 0)
val = FADD; //FADD此处为10
}
while ((KeyIn1 == 0)||(KeyIn2 == 0)||(KeyIn3 == 0)||(KeyIn4 == 0));
/*此处只要有一个按键被按下,就在此处循环*/
KeyOut1 = 1;
KeyOut2 = 0;
KeyOut3 = 1;
KeyOut4 = 1;
if (KeyIn1 == 0)
{
delay(KEY_DELAY); //KEY_DELAY为300
if (KeyIn1 == 0)
val = 4;
}
if (KeyIn2 == 0)
{
delay(KEY_DELAY);
if (KeyIn2 == 0)
val = 5;
}
if (KeyIn3 == 0)
{
delay(KEY_DELAY);
if (KeyIn3 == 0)
val = 6;
}
if (KeyIn4 == 0)
{
delay(KEY_DELAY);
if (KeyIn4 == 0)
val = FSUB; //此处FSUB为11
}
while ((KeyIn1 == 0)||(KeyIn2 == 0)||(KeyIn3 == 0)||(KeyIn4 == 0));
/*此处只要有一个按键被按下,就在此处循环*/
KeyOut1 = 1;
KeyOut2 = 1;
KeyOut3 = 0;
KeyOut4 = 1;
if (KeyIn1 == 0)
{
delay(KEY_DELAY);
if (KeyIn1 == 0)
val = 7;
}
if (KeyIn2 == 0)
{
delay(KEY_DELAY);
if (KeyIn2 == 0)
val = 8;
}
if (KeyIn3 == 0)
{
delay(KEY_DELAY);
if (KeyIn3 == 0)
val = 9;
}
if (KeyIn4 == 0)
{
delay(KEY_DELAY);
if (KeyIn4 == 0)
val = FMUL; //此处FMUL为12
}
while ((KeyIn1 == 0)||(KeyIn2 == 0)||(KeyIn3 == 0)||(KeyIn4 == 0));
KeyOut1 = 1;
KeyOut2 = 1;
KeyOut3 = 1;
KeyOut4 = 0;
if (KeyIn1 == 0)
{
delay(KEY_DELAY);
if (KeyIn1 == 0)
val = 0;
}
if (KeyIn2 == 0)
{
delay(KEY_DELAY);
if (KeyIn2 == 0)
val = FRES; //FRES 14
}
if (KeyIn3 == 0)
{
delay(KEY_DELAY);
if (KeyIn3 == 0)
val = FEQU; //FEQU 15
}
if (KeyIn4 == 0)
{
delay(KEY_DELAY);
if (KeyIn4 == 0)
val = FDIV; //此处FDIV为13
}
while ((KeyIn1 == 0)||(KeyIn2 == 0)||(KeyIn3 == 0)||(KeyIn4 == 0));
if (val > 0) // 此处为当有按键按下时,蜂鸣器响起,根据val的值判断
buzzer_sound();
return val;
}
/*
* 验证数据有效性
*/
bit check_num(float f_num)
{
if (f_num >= 100000)
return 1;
return 0; //返回值为位0
}
/*
* 制作数码管错误标志
*/
void make_led_error(void)
{
int8 i;
for (i=0; i<5; i++)
Led_buf[i] = Ledcode[10]; //Ledcode[10]为0xf为小灯全部熄灭
Led_buf[5] = Ledcode[12]; //Ledcode[12]为0x86此处为字符E
}
/*
* 制作数码管整数数据
*/
void make_led_inumber(int32 i_num) //函数参数传递i_num的值为0
{
bit s_flag=0;
int16 sit;
int8 i;
if (i_num < 0)
{
s_flag = 1;
i_num = -i_num;
}
ET0 = 0; //禁止T0溢出中断
for (i=4, sit=10000; i>=1; i--, sit/=10) //当sit为1
{
if (i_num >= sit)
break;
Led_buf[i] = Ledcode[10]; //Ledcode[10]为0xf为小灯全部熄灭
i_num -= i_num/sit*sit;
}
for (;i>=1; i--, sit/=10)
{
Led_buf[i] = Ledcode[i_num/sit];
i_num -= i_num/sit*sit;
}
Led_buf[0] = Ledcode[i_num] & 0x7F;
if (s_flag)
Led_buf[5] = Ledcode[11];
else
Led_buf[5] = Ledcode[10];
ET0 = 1;
}
/*
* 制作数码管浮点数据
*/
void make_led_fnumber(float f_num)
{
bit s_flag=0;
int32 num;
int16 sit;
int8 i, decimal, dot_sit=0;
if (f_num < 0)
{
s_flag = 1; //如果计算结果f_num <0 ; 则s_flag的值则为1
f_num = -f_num; //把f_num的值按整数计算
}
num = (int32)(f_num*10000+0.5); //把计算结果乘以10000,再加0.5,然后强制取整
for (decimal=4; decimal>0; decimal--) //对于10取余,直到余数不等于0,跳出循环体
{
if (num % 10 != 0)
break;
num /= 10;
}
dot_sit = decimal; // decimal为小数点位数
if (f_num >= 10000) //如果f_num的值大于10000,怎小数点位数为0
dot_sit = 0;
else if (f_num >= 1000) //如果此数大于1000,且小数点位数多于以为,则取一位小数
if (decimal >= 1) //因为数码管的显示范围
dot_sit = 1;
else if (f_num >= 100)
if (decimal >= 2)
dot_sit = 2;
else if (f_num >= 10)
if (decimal >= 3)
dot_sit = 3;
for (i=0; i<dot_sit; i++)
f_num *= 10;
num = (int32)(f_num+0.5);
ET0 = 0; //禁止T0溢出中断
/* 此分为两步分别讨论
1 第一步,把此数用不到的各位的数码管分别熄灭
2 第二步,把有数位分别赋值到数码管上去 */
for (i=4, sit=10000; i>=1; i--, sit/=10)
{
if (num >= sit)
break; //如果此数大于10000,或者小数点位数为4位,则跳出,同理
if (i == dot_sit)
break;
Led_buf[i] = Ledcode[10]; //Ledcode[10]为0xf为小灯全部熄灭
num -= num/sit*sit; //此处为不断的获取书num上以后各位的数值大小
}
/*此处的for语句用于不断的给数组Led_buf[i]赋上计算结果的各位*/
for (;i>=1; i--, sit/=10)
{
Led_buf[i] = Ledcode[num/sit]; //利用Ledcode[]直接给Led_buf[i]依此赋值
num -= num/sit*sit; //此处为不断的获取书num上以后各位的数值大小
}
Led_buf[0] = Ledcode[num]; //赋上个位的数值
Led_buf[dot_sit] &= 0x7F; //与上0111,1111,点亮小数点
if (s_flag)
Led_buf[5] = Ledcode[11]; //如果计算结果小于0,则Led_buf[5]则为0xbf为“-”
else
Led_buf[5] = Ledcode[10]; //Ledcode[10]为0xff为小灯全部熄灭 ,不显示
ET0 = 1; //允许T0溢出中断
}
/*
* 数码管显示
*/
void show_num(uint8 *buf)
{
ENLED = 1;
switch (Led_n)
{
case 0:
ADDR0 = 0;
ADDR1 = 0;
ADDR2 = 0;
P0 = buf[0];
break;
case 1:
ADDR0 = 1;
ADDR1 = 0;
ADDR2 = 0;
P0 = buf[1];
break;
case 2:
ADDR0 = 0;
ADDR1 = 1;
ADDR2 = 0;
P0 = buf[2];
break;
case 3:
ADDR0 = 1;
ADDR1 = 1;
ADDR2 = 0;
P0 = buf[3];
break;
case 4:
ADDR0 = 0;
ADDR1 = 0;
ADDR2 = 1;
P0 = buf[4];
break;
case 5:
ADDR0 = 1;
ADDR1 = 0;
ADDR2 = 1;
P0 = buf[5];
break;
}
ENLED = 0;
if (Led_n >= 5)
Led_n = 0;
else
Led_n++;
}
/*
* 计算程序
*/
void calculate(int8 key_val) //键盘输入的按键标识符key_val
{
float ans;
bit err=0;
if ((key_val >= FADD) && (key_val <= FDIV)) //判断输入的值是否为运算符
{
C_flag = key_val; //如果运算符是四则运算符,则C_flag的值等于key_val
}
else if (key_val == FEQU) //FEQU为等于号
{
switch (C_flag)
{
case FADD: ans = Tmp1+Tmp2; break; //ans为浮点数值
case FSUB: ans = Tmp1-Tmp2; break;
case FMUL: ans = Tmp1*Tmp2; break;
case FDIV: if (Tmp2 == 0)
{
err = 1; //如果输入除数为零,则错误
break;
}
else
{
ans = Tmp1/Tmp2;
break;
}
}
if (check_num(ans)) //如果数据发生溢出,则报错
err = 1;
if (err)
make_led_error(); //如果发生错误,则显示错误
else
make_led_fnumber(ans);
C_flag = 0;
Tmp1 = 0;
Tmp2 = 0;
}
//此处与第一个if语句相对应
else if (key_val == FRES) //如果按下复位键
{
make_led_fnumber(0);
C_flag = 0;
Tmp1 = 0;
Tmp2 = 0;
}
else
{
if (C_flag == 0)
{
ans = Tmp1;
ans *= 10;
ans += key_val;
if (check_num(ans))
return;
else
Tmp1 = ans;
make_led_inumber(Tmp1);
}
else
{
ans = Tmp2;
ans *= 10;
ans += key_val;
if (check_num(ans))
return;
else
Tmp2 = ans;
make_led_inumber(Tmp2); //制作数码管整数数据
}
}
}
/*此处为主函数*/
main()
{
int8 key_val;
ADDR3 = 1;
ENLED = 0;
make_led_inumber(0); // 在按键之前先显示制作数码管整数数据
TMOD = 0x01; //使用T0的16为定时器方式
TH0 = 0xF8; //使用T0的时间为1.84sec
TL0 = 0xCC;
TR0 = 1; //启动定时器T0
ET0 = 1; //允许定时器T0溢出中断
EA = 1; //打开中断总开关,允许中断
while (1)
{
key_val = scan_key(); //根据val,确定按键的值
if (key_val == -1)
con
tinue;
calculate(key_val); //计算数值
}
}
void time0() interrupt 1 //中断程序使用定时器T0
{
TR0 = 0;
TH0 = 0xF8;
TL0 = 0xCC;
show_num(Led_buf);
TR0 = 1;
}
一周热门 更多>