1.今日使用到的键盘与数码管和期望达到的控制目标:
用到的键盘数目为3个,key1(与单片机P3.0口相接)、key2(与单片机P3.1口相接)、key3(与单片机P3.2口相接)。
数码管1位:显示0-9的数据(初始值为0)。
期望达到的控制目标:
key1按下时数码管数码管显示数据加1;
key2按下时数码管数码管显示数据减1;
key3按下时数码管复位为初始状态0。
2.程序分析:
使第一位数码管显示为0–9,需要使位选锁存器的输出始终保持在0x01;段选锁存器输出依次应为:0X3F、0X06、0X5B、0X4F、0X66、0X6D、0X7D、0X07、0X7F、0X6F。
可以看到0-9的显示对应到锁存器输出时并不是连续的数据,为了能够在按下按键后对以上数据有顺序的增减,考虑将以上数据依次放入数组中,那么按键可以通过控制地址来间接控制输出的数据。
按照上述分析,编写代码如下:
#include<reg52.h>
sbit WE=P2^7; //数码管位选
sbit DU=P2^6; //数码管段选
sbit key1=P3^0;
sbit key2=P3^1;
sbit key3=P3^2;
int i=0;
unsigned char smg[]={0X3F,0X06,0X5B,0X4F,0X66,0X6D,0X7D,0X07,0X7F,0X6F};
void main()
{
WE=1;//打开位选锁存器
P0=0XFE;//11111110,即让第一位数码管亮
WE=0;//锁存位选数据
DU=1;//打开段选锁存器
P0=smg[0];//初始化为0
DU=0;
while(1)
{
if(key1==0)
{
if(i<9)
i++;
else
i=9;
DU=1;//打开段选锁存器
P0=smg[i];
DU=0;
} //key1摁下一次显示数目加一,上限为9
if(key2==0)
{
if(i>0)
i--;
else
i=0;
DU=1;//打开段选锁存器
P0=smg[i];
DU=0;
} //key2摁下一次显示数目减一,下限为0
if(key3==0)
{
i=0;
DU=1;//打开段选锁存器
P0=smg[i];
DU=0;
} //key3复位
}
}
理论上来说没有问题,但是将程序烧录到单片机中,初始值显示为0,摁下key1直接变为9;热后摁下key2或者key3会变为0。
3.结果分析与与程序修正:
在无所不能的互联网上我找到了失败的罪魁祸首–按键的机械抖动!!!
理想情况下,按键被按下一次应该输出一个方波,但实际情况下,无论在按下按键还是松开按键都会产生机械抖动从而输出一个许多波动的波形,这使得一次按键动作输出了许多高低电平。也就是说,key1按下一次的实际结果是if(key0)执行许多次使得i到达最大值9;key2同理。
所以,怎么解决这个问题呢?
对于这个情况,我们可以再判断if(key0)成立后延时一小段时间再次判断是否成立这样可以吗?
然后进行延时10ms,发现有效果,但是仍然会一次增加到7或者8。接着对延时时间修改,直到40ms发现对于一次正常的按键动作才不会出现错误。同时,对于非正常按键动作,比如一直摁住,则会连续增加直到松手。
那么,对于连续按键的情况又该怎么处理呢,可以在if语句末尾加上while(!key1);这样连续按住则while不断循环直到松手。
修改后的程序如下:
#include<reg52.h>
sbit WE=P2^7; //数码管位选
sbit DU=P2^6; //数码管段选
sbit key1=P3^0;
sbit key2=P3^1;
sbit key3=P3^2;
int i=0;
unsigned char smg[]={0X3F,0X06,0X5B,0X4F,0X66,0X6D,0X7D,0X07,0X7F,0X6F};
int x,y;
void delay(int t)
{
for(x=0;x<114;x++)
for(y=0;y<t;y++);
}
//定义一个延时函数
void main()
{
WE=1;//打开位选锁存器
P0=0XFE;//11111110,即让第一位数码管亮
WE=0;//锁存位选数据
DU=1;//打开段选锁存器
P0=smg[0];//初始化为0
DU=0;
while(1)
{
if(key1==0)
{
delay(5);//消除抖动影响
if(key1==0)
{
if(i<9)
i++;
else
i=9;
DU=1;//打开段选锁存器
P0=smg[i];
DU=0;
while(!key1);//松开按键才会跳出循环,避免一直按住会i不断增加的情况
}
} //key1摁下一次显示数目加一,上限为9
if(key2==0)
{
delay(5);//消除抖动影响
if(key2==0)
{
if(i>0)
i--;
else
i=0;
DU=1;//打开段选锁存器
P0=smg[i];
DU=0;
while(!key2);
}
} //key2摁下一次显示数目减一,下限为0
if(key3==0)
{
i=0;
DU=1;//打开段选锁存器
P0=smg[i];
DU=0;
} //key3复位
}
}