1.还需消抖

可以看到我们在第6讲和第7讲的按键不支持连按代码中,死循环都有“delay_ms(2);”,因为大多数时候主循环都要做很多事,所以我们认为这2ms的延时是很多复杂程序要执行所消耗的时间,而正是因为这个延时函数的存在把按键的物理抖动给滤掉了,误导了我们以为这样的不支持连按代码是合格的。如果我们还是用这种写法去实现不支持连按功能,那么请把下面的代码下载进开发板通过快按和慢按K4,观察数码管的显示。

 

2.缺陷代码

#include <reg52.h> 
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;
unsigned char code LedChar[16]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E};//数码管状态值初始化
unsigned char LedBuff[6]={0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
unsigned char cnt=0;//可以在SEG_task()和main()中使用的全局变量
 
void SEG_task()//数码管显示函数
{
    static unsigned char i=0;
    LedBuff[0]= LedChar[cnt%10];   
    if(cnt>=10) LedBuff[1]= LedChar[(cnt/10)%10]; //cnt没到达10之前不更新LedBuff[1]的初始值
    if(cnt>=100)LedBuff[2]= LedChar[(cnt/100)%10];//cnt没到达100之前不更新LedBuff[2]的初始值
    if(cnt==0){ LedBuff[1]=0xFF;LedBuff[2]=0XFF; }//cnt到达255之后再加1就溢出变为0了,这时候要再次熄灭这两个数码管
  
    P0=0xFF;
    switch(i)
    {
        case 0:
        ADDR2 = 0;ADDR1 = 0;ADDR0 = 0;P0=LedBuff[0];i++;break;
        case 1:
        ADDR2 = 0;ADDR1 = 0;ADDR0 = 1;P0=LedBuff[1];i++;break;     
        case 2:
        ADDR2 = 0;ADDR1 = 1;ADDR0 = 0;P0=LedBuff[2];i=0;break;  
    }  
}

void main()
{  
    unsigned char key_up=1;//定义记录按键状态值的变量,初始值为1避免程序一开始就进入了“if(key_up==0)”
    unsigned int  times=0; //用来记录进入过按键判断语句的次数
    ADDR3 = 1;//使能三八译码器
    ENLED = 0;// 
  
    ADDR2 = 1;//**************************
    ADDR1 = 1;//让三八译码器的IO6输出低电平
    ADDR0 = 0;//**************************
    P2 = 0xF7;//让K4能具备有被拉低的条件先
  
    while(1)
    { 
        SEG_task();//数码管显示任务
   
        //按键功能部分
        if(key_up==0)
        {      
            if(KEY4==1)//按键已弹起
            {
                cnt++; //执行功能代码
            }
        }
        key_up=KEY4;   //如果不松手,key_up就会等于0    
    }
}

我们多按几次,会发现有时抬起之后cnt就被加2了,也就是在一次按键的动作里“cnt++;”被执行了两次,这是因为“SEG_task();”的执行时间太短没有滤掉按键的抖动,大家再次对照下图自己分析

按键12


3.改善

有了“支持连按”的代码思路,实现消抖还是很容易的,我们同样用上times记录按键IO端口进入低电平的时间,只要times大于500证明抖动的时间已经过去,此时再判断按键是否抬起就可以决定该不该执行功能代码了。

把按键功能代码部分改为如下代码即可完善出最终的不支持连按模式的代码

//按键功能部分
if(key_up==0)
{      
    times++;     
    if(times>=500&&KEY4==1)//低电平持续够一定的时间了,证明抖动时间已经过去了,如果现在按键已经抬起就执行功能代码
    {
        times=0;
        cnt++;//执行功能代码  
    }
}
key_up=KEY4; //如果不松手,key_up就会等于0

笔者用串口测试过按下抬起的动作无论多快,这个times一般都在500以上(串口后面再学),如果我们一直按着不放,times就会一直累加,如果累加到溢出之后,times又从0开始累加,当times小于500的时候刚好松手,这样是无法执行功能代码的,

因为不满足“times>=500”的判断,所以只要大家不刻意去做这样长按不放的动作,这种情况很少发生,就算发生,概率也只有500/65536=0.0076,我们的代码还算是很实用的。

点赞(0)

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

Dotcpp在线编译      (登录可减少运行等待时间)