我已经调试了好多天了,因为白天上班,晚上才有时间,但是连续4,5个晚上都发现不了原因,目前已经可以做到加法了,但是我只要一按键,比如按1,按一下马上弹起,就会有N个1出现在8位数码管上,出现多少根据按的时间决定,求好心人帮帮我。。我仿佛是知道因为程序记录了我多次进行了按1的操作,可是我在按键检测的时候用了if(keysta[j]==0),相当于按键弹起的时候才显示1。我用的两个74HC573接的8位数码管,DUAN WEI两个IO扣控制锁存器的,拜谢了。。拜谢了。。
单片机源程序:
- #include<reg52.h>
- sbit L0=P1^0; //定义L0-L7小灯IO口
- sbit L1=P1^1;
- sbit L2=P1^2;
- sbit L3=P1^3;
- sbit L4=P1^4;
- sbit L5=P1^5;
- sbit L6=P1^6;
- sbit L7=P1^7;
- sbit o4=P3^0; //定义矩阵键盘IO口
- sbit o1=P3^1;
- sbit o2=P3^2;
- sbit o3=P3^3;
- sbit i1=P3^4;
- sbit i2=P3^5;
- sbit i3=P3^6;
- sbit i4=P3^7;
- sbit DUAN=P2^0; //定义段选开关
- sbit WEI=P2^1; //定义位选开关
- unsigned char ledbuff[8]={ //数码管显示缓冲区
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
- unsigned char duanma[]={ //定义单个数码管段位,显示0-F
- 0x3f,0x06,0x5b,0x4f,
- 0x66,0x6d,0x7d,0x07,
- 0x7f,0x6f,0x77,0x7c,
- 0x39,0x5e,0x79,0x71
- };
- unsigned char weima[]={ //定义单个数码管位,显示第几个数码管
- 0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe
- };
- unsigned char keysta[4][4]={ //定义矩阵按键的当前状态
- {1,1,1,1},
- {1,1,1,1},
- {1,1,1,1},
- {1,1,1,1}
- };
- 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键、 等号、 除号
- };
- void keydriver();
- unsigned char o=0;
- unsigned char cnt=0;
- void main()
- {
- TMOD=0x01; //计时器模式选择为01,16位计时器
- TH0=0xfc; //为T0赋初值0xFC67,定时1ms
- TL0=0x67;
- TR0=1; //打开计时器
- EA=1; //打开中断总开关
- ET0=1; //打开中断T0
- ledbuff[0]=duanma[0];
- while(1)
- {
- keydriver(); //调用按键驱动函数
- }
- }
- void shownumber(unsigned long num) /* 将一个无符号长整型的数字显示到数码管上,num-待显示数字 */
- {
- signed char i;
- unsigned char buf[8];
- for(i=0;i<8;i++)
- {
- buf[i]=num%10;
- num=num/10;
- }
- L1=1;
- for(i=7;i>=1;i--) //从最高位起,遇到0转换为空格,遇到非0则退出循环
- {
- if(buf[i]==0x00)
- {
- ledbuff[i]=0x00;
- }
- else
- break;
- }
- for(;i>=0;i--) //剩余低位都如实转换为数码管显示字符
- {
- ledbuff[i]=duanma[buf[i]];
- }
- }
- void keyaction(unsigned char keycode)
- {
- static unsigned long result=0; //用于保存运算结果
- static unsigned long addend=0; //用于保存输入的加数
- if((keycode>=0x30)&&(keycode<=0x39)) //输入0-9的数字
- {
- addend=(addend*10)+(keycode-0x30); //整体十进制左移,新数字进入个位
- shownumber(addend); //运算结果显示到数码管
- }
- else if(keycode==0x26) //按下加号
- {
- result+=addend;
- addend=0;
- shownumber(result);
- }
- else if(keycode==0x0d) //按下等号
- {
- result+=addend;
- addend=0;
- shownumber(result);
- }
- else if(keycode==0x1b) //按下ESC
- {
- addend=0;
- result=0;
- shownumber(addend);
- }
- }
- void keydriver()
- {
- unsigned char i,j;
- unsigned 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++) //循环检测4*4的矩阵按键
- {
- for(j=0;j<4;j++)
- {
- if(keysta[i][j]!=backup[i][j]) //检测按键动作
- { //按键按下时执行动作
- if(keysta[i][j]==0)
- {
- keyaction(keycodemap[i][j]); //调用按键动作函数
- }
- backup[i][j]=keysta[i][j]; //刷新前一次的备份值
- }
- }
- }
- }
- void keyscan() //键盘消抖,检测键盘是否按下
- {
- static unsigned char keyout=0;
- unsigned char j;
- static unsigned char keybuf[4][4]={
- {0xff,0xff,0xff,0xff},
- {0xff,0xff,0xff,0xff},
- {0xff,0xff,0xff,0xff},
- {0xff,0xff,0xff,0xff}
- };
- keybuf[keyout][0]=(keybuf[keyout][0]<<1)|i1; //消抖功能,对第一列键盘将keybuf[][]赋值为1111 1111或者0000 0000
- keybuf[keyout][1]=(keybuf[keyout][1]<<1)|i2;
- keybuf[keyout][2]=(keybuf[keyout][2]<<1)|i3;
- keybuf[keyout][3]=(keybuf[keyout][3]<<1)|i4;
- for(j=0;j<4;j++)
- {
- if((keybuf[keyout][j])==0x00) //如果keybuf为0000 0000 则视为按下按键
- {
- keysta[keyout][j]=0;
- }
- else if((keybuf[keyout][j])==0xff) //如果keybuf为1111 1111 则视为弹起按键
- {
- keysta[keyout][j]=1;
- }
- }
- switch(keyout) //对键盘进行行扫描
- {
- case 0:o4=1;o1=0;break;
- case 1:o1=1;o2=0;break;
- case 2:o2=1;o3=0;break;
- case 3:o3=1;o4=0;break;
- default:break;
- }
- keyout++;
- keyout=keyout&0x03; //keyout到4清0
-
- }
- void ledscan() //键盘显示函数
- {
- static unsigned char i = 0; //动态扫描的索引
- P0 = 0xFF; //显示消隐
- switch(i)
- {
- case 0:
- WEI=1;P0=weima[0];WEI=0;DUAN=1;P0=ledbuff[0];i++;DUAN=0;break; //显示个位
- case 1:
- WEI=1;P0=weima[1];WEI=0;DUAN=1;P0=ledbuff[1];i++;DUAN=0;break; //显示十位
- case 2:
- WEI=1;P0=weima[2];WEI=0;DUAN=1;P0=ledbuff[2];i++;DUAN=0;break; //显示百位
- case 3:
- WEI=1;P0=weima[3];WEI=0;DUAN=1;P0=ledbuff[3];i++;DUAN=0;break;
- case 4:
- WEI=1;P0=weima[4];WEI=0;DUAN=1;P0=ledbuff[4];i++;DUAN=0;break;
- case 5:
- WEI=1;P0=weima[5];WEI=0;DUAN=1;P0=ledbuff[5];i++;DUAN=0;break;
- case 6:
- WEI=1;P0=weima[6];WEI=0;DUAN=1;P0=ledbuff[6];i++;DUAN=0;break;
- case 7:
- WEI=1;P0=weima[7];WEI=0;DUAN=1;P0=ledbuff[7];i++;DUAN=0;break;
- default:i=0;break;
- }
- }
- void interrupttimer0() interrupt 1 //定时中断检测键盘,刷新数码管
- {
- TH0=0xfc;
- TL0=0x67;
- keyscan(); //调用按键扫描函数
- ledscan(); //调用数码管显示扫描函数
- }
复制代码 |