找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2192|回复: 12
收起左侧

这段网上广为流传的MCU按键消抖程序怎么理解?

  [复制链接]
ID:997026 发表于 2022-2-9 17:15 | 显示全部楼层 |阅读模式
最近在看按键消抖程序,在网上找到流传很广的利用定时器消抖的单片机程序,这段程序我看很多人都在使用,但是有一部分我百思不得其解,特分享出来与大家探讨:

MCU程序如下:

#define const_key_time1  60    /*按键去抖动延时的时间*/
#define const_time_0_25s  200    /*0.25秒钟的时间需要的定时中断次数*/
#define const_time_1s   800     /*1秒钟的时间需要的定时中断次数*/



//定义按键S1
sbit Key_S1 = P0^0;


unsigned char ucKeySec = 0;     //被触发的按键编号
unsigned int  uiKeyTimeCnt1 = 0;   //按键去抖动延时计数器
unsigned char ucKeyLock1 = 0;   //按键触发后自锁的变量标志
unsigned char uiKeyCtntyCnt1=0;   //按键连续触发的间隔延时计数器





void Key_Scan(void)  //按键扫描
{
        /*扫描S1*/
        if(Key_S1 == 1)            //如果按键没有被按下(高电平),将一些标志位及时清零
        {
                ucKeyLock1 = 0;   //自锁标志位清
                uiKeyTimeCnt1 = 0;  //按键去抖动延时计数器清零
                uiKeyCtntyCnt1 = 0;   //连续累加的时间间隔延时计数器清零
        }
        else if(ucKeyLock1 == 0)        //如果有按键按下,且是第一次按下  备注:这里不太理解,为什么ucKeyLock1 == 0可以表示按键按下???
        {
                uiKeyTimeCnt1 ++;
                if(uiKeyTimeCnt1 > const_key_time1)   //判定按下
                {
                        uiKeyTimeCnt1 = 0;
                        ucKeyLock1 = 1;
                        ucKeySec = 1;    // 触发S1
                }
        }
        else if(uiKeyTimeCnt1 < const_time_1s)    //按键已按下,按键去抖动延时计数器自增到1s
        {
                uiKeyTimeCnt1 ++;   
        }
        else                // 按住累加到1秒后仍然不放手,这个时候进入有节奏的连续触发
        {
                uiKeyCtntyCnt1 ++;       //连续触发延时计数器累加
                if(uiKeyCtntyCnt1 > const_time_0_25s)     //按住没松手,每0.25秒就触发一次
                {
                        uiKeyCtntyCnt1 = 0;  
                        ucKeySec = 1;      //触发S1
                }
        }
  }



上面这段程序网上广为流传,很多人都在使用,其中有一段我看了好久没看明白,除了这段,其他地方基本都弄懂了。
就是上面备注红色的地方,为什么用ucKeyLock1 == 0 可以指示按键已经被按下了?因为ucKeyLock1只是定义的一个变量而已,没有和P0这个IO口发生任何关联,为什么这段程序中用ucKeyLock1 == 0 就能指示按键已经被按下了?按键被按下不是应该用Key_S1==0来判断吗?


而且ucKeyLock1这个变量在如下程序中当按键没有按下的时候已经被置0了,上面的程序又以ucKeyLock1 == 0 来指示按键被按下,感觉是自相矛盾的,不太理解,还是有其他妙用?网上很多都这么写,但实在是没理解?希望大家能看懂我在说什么,谁能解释下呢?感谢!


if(Key_S1 == 1)            //如果按键没有被按下(高电平),将一些标志位及时清零
        {
                ucKeyLock1 = 0;   //自锁标志位清
                uiKeyTimeCnt1 = 0;  //按键去抖动延时计数器清零
                uiKeyCtntyCnt1 = 0;   //连续累加的时间间隔延时计数器清零
        }



回复

使用道具 举报

ID:213173 发表于 2022-2-9 22:34 | 显示全部楼层
else if(ucKeyLock1 == 0)        这里else对应上面的if(Key_S1 == 1)表示有按键按下,接着的if(ucKeyLock1 == 0)是判断条件,ucKeyLock1 == 0 才可以执行花括号内语句。也就是按键按下后,CPU要执行61次Key_Scan函数(延时消抖)才能满足条件,ucKeyLock1 = 1;破坏上述条件,按键不松手也不会重复执行这段语句。
回复

使用道具 举报

ID:514254 发表于 2022-2-10 00:28 | 显示全部楼层
找找程序段中其他的地方的ucKeyLock1 = 0
回复

使用道具 举报

ID:161164 发表于 2022-2-10 01:44 | 显示全部楼层
  1. if(Key_S1 == 1)            //如果按键没有被按下(高电平),将一些标志位及时清零
  2.         {
  3.         }else if(ucKeyLock1 == 0)        
复制代码

这样来看会不会清晰一点?
回复

使用道具 举报

ID:276761 发表于 2022-2-10 09:18 | 显示全部楼层
你只要理解if-else if就能明白了,上面if(Key_S1 == 1)只要成立,就不会执行else if(ucKeyLock1 == 0),只要上面if(Key_S1 == 1)不成立了,就执行else if(ucKeyLock1 == 0)
回复

使用道具 举报

ID:997026 发表于 2022-2-10 10:00 | 显示全部楼层
wulin 发表于 2022-2-9 22:34
else if(ucKeyLock1 == 0)        这里else对应上面的if(Key_S1 == 1)表示有按键按下,接着的if(ucKeyLock ...

按我的理解,if-else if-else语句类似条件选择吧,没有所谓某个else if对应哪个吧,满足哪个条件就执行哪个,都不满足就执行最后else里面的,应该是这样的逻辑才对。如果要满足你说的这种判断,我感觉应该用if-else才对,而不是if-else if-else。ucKeyLock1 == 0这个判断条件就像是凭空产生的,不理解
回复

使用道具 举报

ID:997026 发表于 2022-2-10 10:30 | 显示全部楼层
cliang223 发表于 2022-2-10 09:18
你只要理解if-else if就能明白了,上面if(Key_S1 == 1)只要成立,就不会执行else if(ucKeyLock1 == 0),只 ...

谢谢回复,其实你仔细看这其实是一个if-else if-else选择语句,并不是if-esle语句,if-else if-else语句中,会判断每一个if和else if中的表示式,如果满足就执行,不满足就执行最后一个else中的语句,逻辑应该是这样吗?其实我的意思主要是ucKeyLock1 == 0为啥可以用来判断按键被按下了?

Key_S1 == 1中,Key_S1表示的是IO口,可以检测到高低电平,用来判断按键状态,但是ucKeyLock1只是个变量,在上面if(Key_S1 == 1)成立时,已经将ucKeyLock1 == 0清零了,这里怎么又用ucKeyLock1 == 0来表示按键被按下???感觉是矛盾的。
回复

使用道具 举报

ID:213173 发表于 2022-2-10 11:09 | 显示全部楼层
hxdby 发表于 2022-2-10 10:00
按我的理解,if-else if-else语句类似条件选择吧,没有所谓某个else if对应哪个吧,满足哪个条件就执行哪 ...

ucKeyLock1 == 0这个判断条件不是凭空产生的,是按键松手的结果之一。ucKeyLock1为1也不是按键按下的识别标志,是按键按下并经过消抖后才能赋值的自锁标志。在这段代码中只有 if(Key_S1 == 1) 表示松手,对应的3个else都是在按键按下后才顺序判断执行相应语句。
回复

使用道具 举报

ID:997026 发表于 2022-2-10 12:07 | 显示全部楼层
wulin 发表于 2022-2-10 11:09
ucKeyLock1 == 0这个判断条件不是凭空产生的,是按键松手的结果之一。ucKeyLock1为1也不是按键按下的识别 ...

谢谢回复。

如果按键松手,那执行的应该是 if(Key_S1 == 1) 里面的语句,其他都不执行。我的疑问是,如果按键按下,那应该执行哪条语句呢?上面的代码说的是按键按下会执行else if(ucKeyLock1 == 0),但是我不太明白,因为ucKeyLock1没有和P0口发生关联,也不是标志位,为啥这个能表示按键被按下?
回复

使用道具 举报

ID:276761 发表于 2022-2-10 13:59 | 显示全部楼层
hxdby 发表于 2022-2-10 10:30
谢谢回复,其实你仔细看这其实是一个if-else if-else选择语句,并不是if-esle语句,if-else if-else语句 ...

你还是没有明白if,else if,else,你看上面的程序,if(Key_S1 == 1) ,else if(ucKeyLock1 == 0) ,else if(uiKeyTimeCnt1 < const_time_1s) ,else,不管中间有多少个else if,你说的是会判断每一个if和else if中的表达式,但不是满足就执行的,如果前面的if满足了,后面的else if就算满足了都不会执行的,就是一次只能执行一个,先满足的先执行。那么if(Key_S1 == 1),如果满足,表示按键没有按下,那么后面的else if就不会执行了,如果不满足,说明按键按下了,那么就开始判断后面的else if,第一个else if(ucKeyLock1 == 0),是定义的一个变量,是满足的,那么就执行它。下面你就应该明白了吧
回复

使用道具 举报

ID:997026 发表于 2022-2-10 19:45 | 显示全部楼层
cliang223 发表于 2022-2-10 13:59
你还是没有明白if,else if,else,你看上面的程序,if(Key_S1 == 1) ,else if(ucKeyLock1 == 0) ,else ...

非常感谢你的回复。

我确实弄错了else if这个语句,因为比较少用else if, 以为是一个选择语句,其实这个选择是由条件的,就是必须是第一个if条件不满足的时候才会执行后面的语句,其实if-else if-else语句相当于是if else语句的变体,后面的所有else if相当于是嵌套在if -else的else后面的,if满足,永远不会执行后面的else if, if不满足,才会按照后面else if顺序判断执行。

这个程序很精妙,关键在于ucKeyLock这个变量,当按键按下的时候,其实ucKeyLock仍然是为0的,如果此时按一下松手,则触发一个键值输出,程序跳转到Key_S1==1下。如果持续按不松手,则ucKeyLock被赋值1,同时跳转到后面的程序。

经过大家的积极回复,我大概搞懂了,感谢大家的帮助!
回复

使用道具 举报

ID:1063563 发表于 2023-6-4 11:48 | 显示全部楼层
else if(uiKeyTimeCnt1 < const_time_1s)    //按键已按下,按键去抖动延时计数器自增到1s
        {
                uiKeyTimeCnt1 ++;   
        }
这段是什么意思没看懂
回复

使用道具 举报

ID:883242 发表于 2023-6-4 15:55 | 显示全部楼层
芯菲 发表于 2023-6-4 11:48
else if(uiKeyTimeCnt1 < const_time_1s)    //按键已按下,按键去抖动延时计数器自增到1s
        {
   ...

按下1s以内单次按下,按下时间超过1s进入连续按下状态。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表