此加法计算器很简单,且有很多不完善的地方,但逻辑性很强
此函数主要分为两部分:
1、 主函数部分:主函数的作用主要是识别哪一个按键被按下,并且根据被按下的按键,执行相应的状态!比如按下等号键就把两次加数累加起来显示出来
首先主函数调用KeyDriver函数进行判断是否有按键被按下,并检测哪一个按键被按下,
然后接着调用KeyAction函数,判断哪一个按键被按下,并执行该按键所对应的功能
然后再把KeyAction函数中所得到的数值,发送到ShowNumber函数中,将得到的数值进行分离,并存储到数码管缓冲区LedBuff中去!
2、 中断函数部分:
中断函数主要进行数码管的刷新和按键状态的检验!
主要是按键状态函数难理解:其实这里包含一个按键消抖的算法。就是一毫秒检验一列四个按键的状态,连续四毫秒就把所有按键全都检验一遍他们的状态,并把按键状态存到状态缓冲区keybuff中去,然后连续四个四毫秒就把每一个按键都检验四遍。
如果连续检验四遍发现某个按键一直保持为0状态,说明它一直被按下,则可以确定这个按键一直被按下。如果连续检验四遍发现某个按键一直保持为1状态,说明它一直弹起,则可以确定这个按键一直弹起。
如果连续四次发现某个按键状态又有0又有1,说明按键处于抖动状态!(关于按键抖动自行百度。。。)如果这时候判断按键的状态,即这段代码:
for(i=0;i<4;i++)
{
if((keybuff[col][i]&0x0f)==0x00)//假如连续四毫秒内发现某个按键一直保持0状态,说明此按键被按下,给此按键当前状态赋值为0
{
keysta[col][i]=0;//keysta这个数组是为了保存按键的当前状态
}
elseif((keybuff[col][i]&0x0f)==0x0f)//假如连续四毫秒内发现按键一直保持1状态,说明此按键弹起,给此按键当前状态赋值为1
{
keysta[col][i]=1;//检测到此按键弹起,此按键当前状态赋值为1
}
}
现在贴出代码:
#include<reg52.h>
sbit datacs=P2^6;
sbit chipcs=P2^7;
sbit col1=P2^1; //列端口定义
sbit col2=P2^0;
sbit col3=P3^5;
sbit col4=P3^4;
sbit row1=P1^7; //行端口定义
sbit row2=P1^6;
sbit row3=P3^6;
sbit row4=P3^7;
unsigned char key;
unsigned char codetable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
unsigned char LedBuff[8] =
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //数码管更新缓冲区,单片机直接用这里的数据来更新数码管
unsigned char code KeyCodeMap[4][4] = { //矩阵按键编号到标准键盘键码的映射表
{0x31, 0x32, 0x33, 0x26 }, //数字键1、数字键2、数字键3、向上键
{0x34, 0x35, 0x36, 0x25 }, //数字键4、数字键5、数字键6、向左键
{0x37, 0x38, 0x39, 0x28 }, //数字键7、数字键8、数字键9、向下键
{0x30, 0x1B, 0x0D, 0x27 } //数字键0、ESC键、 回车键、向右键
};
unsigned char keysta[4][4]={
{1,1,1,1},
{1,1,1,1},
{1,1,1,1},
{1,1,1,1}
};
void KeyDriver();
void KeyAction(unsigned char keycode);
void ShowNumber(unsigned long num);
void main()
{
datacs = 0;
chipcs= 0;
EA= 1;
TMOD=0X01;
TH0=0XFC;
TL0=0X67;
ET0=1;
TR0=1;
LedBuff[0]=table[0];
while(1)
{
KeyDriver();//检测是否有按键按下,并检验是哪个按键被按下
}
}
void KeyDriver()
{
unsigned char i,j;
staticunsigned char backup[4][4]={ //存储按键上一次的状态
{1,1,1,1},
{1,1,1,1},
{1,1,1,1},
{1,1,1,1}
};
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
if(backup[i][j]!=keysta[i][j]) //当按键上一次状态和当前状态不相等时,说明按键有动作,不是按下就是弹起来
{
if(backup[i][j]!=0)//按键上一次状态为1时,说明当前状态为0,按键刚被按下,用i,j来定位哪个一按键被按下
{
KeyAction(KeyCodeMap[i][j]); //检测到被按下的按键,把按键所对应的数值传到KeyAction()函数中,执行按键所对应的相应动作
}
backup[i][j]=keysta[i][j];
}
}
}
}
void KeyAction(unsigned char keycode)//把接收到的按键所对应的数值,进行转换,执行加或等于或清零等动作
{
staticunsigned long result=0;//存储运算结果
staticunsigned long accend=0;//存储被按下的加数
if((keycode>=0x30)&&(keycode<=0x39))//0到9
{
accend= (accend*10)+(keycode-0x30); //假如加数为125时,这一步做作用就是一次把按下的1,2,5累加起来
ShowNumber(accend);//把得到的数存到数码管缓冲区中,再中断中利用缓冲区显示出来
}
elseif(keycode==0x26)//加号
{
result= result+accend;
accend=0;
ShowNumber(result);
}
elseif(keycode==0x0D) //等于回车键
{
result= result+accend;
accend=0;
ShowNumber(result);
}
elseif(keycode==0x1B)//清零键,ESC
{
result= 0;
accend= 0;
ShowNumber(accend);
}
}
//把传过来的数进行分离,并更新数码管缓冲区的数值,即LedBuff[][]数组的数值
void ShowNumber(unsigned long num)
{
signed char i;
unsignedchar buf[8];//将传进来的num的值进行分离,把每一位分离出来,并存到数组中,b[0]是最低位
for(i=0;i<8;i++)
{
buf[i]=num%10;
num=num/10;
}
for(i=7;i>=1;i--)
{
if(buf[i]==0)
{
LedBuff[i]=0X00;
}
else
break;
}
for(;i>=0;i--)
{
LedBuff[i]=table[buf[i]];
}
}
/*********************中断函数及其所调用的函数**********************************/
void LedScan();
void KeyScan();
//中断函数,每一毫秒进行一次中断函数,中断函数里刷新数码管,并且检验按键此时的状态
void InterruptTimer() interrupt 1
{
TH0=0XFC;
TL0=0X67;
LedScan();//刷新数码管
KeyScan();//检验按键状态
}
void LedScan()
{
static unsigned char i=0;
P0=0XFF;
switch(i)
{
case0:P0=0x7f;chipcs=1;chipcs=0;P0=LedBuff[0];datacs=1;datacs=0;i++;break;
case1:P0=0xbf;chipcs=1;chipcs=0;P0=LedBuff[1];datacs=1;datacs=0;i++;break;
case2:P0=0xdf;chipcs=1;chipcs=0;P0=LedBuff[2];datacs=1;datacs=0;i++;break;
case3:P0=0xef;chipcs=1;chipcs=0;P0=LedBuff[3];datacs=1;datacs=0;i++;break;
case4:P0=0xf7;chipcs=1;chipcs=0;P0=LedBuff[4];datacs=1;datacs=0;i++;break;
case5:P0=0xfb;chipcs=1;chipcs=0;P0=LedBuff[5];datacs=1;datacs=0;i++;break;
case6:P0=0xfd;chipcs=1;chipcs=0;P0=LedBuff[6];datacs=1;datacs=0;i++;break;
case7:P0=0xfe;chipcs=1;chipcs=0;P0=LedBuff[7];datacs=1;datacs=0;i=0;break;
default:break;
}
}
void KeyScan()
{
static unsigned char keybuff[4][4]={//这个二维数组,用来存储连续四毫秒所有按键的状态
{0XFF,0XFF,0XFF,0XFF},
{0XFF,0XFF,0XFF,0XFF},
{0XFF,0XFF,0XFF,0XFF},
{0XFF,0XFF,0XFF,0XFF}
};
staticunsigned char col=0; //列数,静态变量,每隔一毫秒扫描一列,四毫秒扫描四列,即四毫秒扫描完矩阵按键的所有列
unsignedchar i;
//当按键被按下是row被拉为0,看电路图理解这里
keybuff[col][0]=(keybuff[col][0]<<1)|row1;//第col列的第一个按键状态
keybuff[col][1]=(keybuff[col][1]<<1)|row2;//第col列的第二个按键状态
keybuff[col][2]=(keybuff[col][2]<<1)|row3;//第col列的第三个按键状态
keybuff[col][3]=(keybuff[col][3]<<1)|row4;//第col列的第四个按键状态
for(i=0;i<4;i++)
{
if((keybuff[col][i]&0x0f)==0x00)//假如四毫秒内发现按键一直保持0状态,说明此按键被按下,给此按键当前状态赋值为0
{
keysta[col][i]=0;//keysta这个数组是为了保存按键的当前状态
}
elseif((keybuff[col][i]&0x0f)==0x0f)//假如四毫秒内发现按键一直保持1状态,说明此按键弹起,给此按键当前状态赋值为1
{
keysta[col][i]=1;//检测到此按键弹起,此按键当前状态赋值为1
}
}
col++;//切换到下一行
col=col&0x03;//列数col等于四时自动清零
switch(col)//切换到下一行
{
case0:col1=0;col2=1;col3=1;col4=1;break;
case1:col1=1;col2=0;col3=1;col4=1;break;
case2:col1=1;col2=1;col3=0;col4=1;break;
case3:col1=1;col2=1;col3=1;col4=0;break;
default:break;
}
}