1.缺陷
上一讲讲解的“不支持连按”模式贴合了我们在生活中的实际应用,虽然我们仅用“while(KEY4==0);”就把按键模式给切换了,不过这条语句严格来说是有缺陷的。
现在我们编写的都是简单的程序,如果后面还有更多更复杂的程序时,“while(KEY4==0);”就成为BUG了。
如果我们对按键按下不松手,那程序就一直在循环等待,不遇到高电平就不往下执行代码,如果这时有重要的程序要执行,那岂不是因按键而耽误。
还有我们再看下面这些代码while(1)
{
if(KEY4==0)
{
delay_ms(10);//等待抖动过去
if(KEY4==0) //二次判断
{
//这里执行某些功能语句
}
}
}
即使我们不使用“while(KEY4==0);”,只要我们按键不松手,每次都要执行“delay_ms(10);”,这样的代码称不上高效率,我们只能再次完善代码了。
2.改善
首先我们为了让程序做到通用性,我们定义一个key_up为unsigned char类型的变量,而不是像宋老师那样在《手把手教你学51单片机》文档8.4.3节后面的文字内容说到的利用bit类型的变量,毕竟bit类型只适合在51单片机,要是移植到其他单片机里就不适用了,所以我们不打算使用这种变量。
我们新定义的key_up变量是用来记录此时按键IO端口的扫描值,进一步分析,当按键按下不松手时,
此时的key_up等于KEY4(也就是0),当按键松手后,key_up就等于1了。
然后想进入执行功能语句时,先过了“if(key_up==0)”这一关,因为我们一直让key_up在死循环里存取KEY4的值,所以只要没有按键动作,key_up一直等于1,这样连进入功能语句的第一关都没有资格。
当有按键按下时,key_up等于0了,进入了第一关,然后我们再设最后一关,如果通过了最后一关就可以执行功能语句了,最后一关是判断“if(KEY4==1)”,也就是说如果按键没松手,就无法执行功能语句了。没错,我们这次的不支持连按模式是只有按键松手之后才去执行的,上一讲则是按下之后过了10ms就执行代码了。
3.代码#include
sbit ADDR2 = P1^2;
sbit ADDR1 = P1^1;
sbit ADDR0 = P1^0;
sbit ENLED = P1^4;
sbit ADDR3 = P1^3;
sbit LED2 = P0^0;
sbit KEY4 = P2^7;
void delay_ms(unsigned int x)
{
unsigned int i,j;
if(x==1000)
{
for(i=0;i<19601;i++)//延时1s
{
for(j=5;j>0;j--);
}
}
else while(x--)for(j=115;j>0;j--);
}
void main()
{
unsigned char key_up=1;//定义记录按键状态值的变量,初始值为1避免程序一开始就进入了“if(key_up==0)”
unsigned char i=1;
ADDR3 = 1;//使能三八译码器
ENLED = 0;//
ADDR2 = 1;//**************************
ADDR1 = 1;//让三八译码器的IO6输出低电平
ADDR0 = 0;//**************************
P2 = 0xF7;//让K4能具备有被拉低的条件先
P0 = 0xFE;//先点亮LED2
while(1)
{
if(key_up==0)
{
if(KEY4==1)//只要不松手,KEY4就会等于0,只有在按键抬起之后才执行功能代码
{
P0=~(0x01<
i++;
if(i>=8)i=0;
}
}
key_up=KEY4; //如果不松手,key_up就会等于0
delay_ms(2); //假设这部分是要执行的其他程序
}
}
大家可以照着代码分析一下,我们是不是已经解决了上一讲代码的两处缺陷。