找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2992|回復(fù): 12
收起左側(cè)

這段網(wǎng)上廣為流傳的MCU按鍵消抖程序怎么理解?

  [復(fù)制鏈接]
ID:997026 發(fā)表于 2022-2-9 17:15 | 顯示全部樓層 |閱讀模式
最近在看按鍵消抖程序,在網(wǎng)上找到流傳很廣的利用定時器消抖的單片機(jī)程序,這段程序我看很多人都在使用,但是有一部分我百思不得其解,特分享出來與大家探討:

MCU程序如下:

#define const_key_time1  60    /*按鍵去抖動延時的時間*/
#define const_time_0_25s  200    /*0.25秒鐘的時間需要的定時中斷次數(shù)*/
#define const_time_1s   800     /*1秒鐘的時間需要的定時中斷次數(shù)*/



//定義按鍵S1
sbit Key_S1 = P0^0;


unsigned char ucKeySec = 0;     //被觸發(fā)的按鍵編號
unsigned int  uiKeyTimeCnt1 = 0;   //按鍵去抖動延時計數(shù)器
unsigned char ucKeyLock1 = 0;   //按鍵觸發(fā)后自鎖的變量標(biāo)志
unsigned char uiKeyCtntyCnt1=0;   //按鍵連續(xù)觸發(fā)的間隔延時計數(shù)器





void Key_Scan(void)  //按鍵掃描
{
        /*掃描S1*/
        if(Key_S1 == 1)            //如果按鍵沒有被按下(高電平),將一些標(biāo)志位及時清零
        {
                ucKeyLock1 = 0;   //自鎖標(biāo)志位清
                uiKeyTimeCnt1 = 0;  //按鍵去抖動延時計數(shù)器清零
                uiKeyCtntyCnt1 = 0;   //連續(xù)累加的時間間隔延時計數(shù)器清零
        }
        else if(ucKeyLock1 == 0)        //如果有按鍵按下,且是第一次按下  備注:這里不太理解,為什么ucKeyLock1 == 0可以表示按鍵按下???
        {
                uiKeyTimeCnt1 ++;
                if(uiKeyTimeCnt1 > const_key_time1)   //判定按下
                {
                        uiKeyTimeCnt1 = 0;
                        ucKeyLock1 = 1;
                        ucKeySec = 1;    // 觸發(fā)S1
                }
        }
        else if(uiKeyTimeCnt1 < const_time_1s)    //按鍵已按下,按鍵去抖動延時計數(shù)器自增到1s
        {
                uiKeyTimeCnt1 ++;   
        }
        else                // 按住累加到1秒后仍然不放手,這個時候進(jìn)入有節(jié)奏的連續(xù)觸發(fā)
        {
                uiKeyCtntyCnt1 ++;       //連續(xù)觸發(fā)延時計數(shù)器累加
                if(uiKeyCtntyCnt1 > const_time_0_25s)     //按住沒松手,每0.25秒就觸發(fā)一次
                {
                        uiKeyCtntyCnt1 = 0;  
                        ucKeySec = 1;      //觸發(fā)S1
                }
        }
  }



上面這段程序網(wǎng)上廣為流傳,很多人都在使用,其中有一段我看了好久沒看明白,除了這段,其他地方基本都弄懂了。
就是上面?zhèn)渥⒓t色的地方,為什么用ucKeyLock1 == 0 可以指示按鍵已經(jīng)被按下了?因為ucKeyLock1只是定義的一個變量而已,沒有和P0這個IO口發(fā)生任何關(guān)聯(lián),為什么這段程序中用ucKeyLock1 == 0 就能指示按鍵已經(jīng)被按下了?按鍵被按下不是應(yīng)該用Key_S1==0來判斷嗎?


而且ucKeyLock1這個變量在如下程序中當(dāng)按鍵沒有按下的時候已經(jīng)被置0了,上面的程序又以ucKeyLock1 == 0 來指示按鍵被按下,感覺是自相矛盾的,不太理解,還是有其他妙用?網(wǎng)上很多都這么寫,但實在是沒理解?希望大家能看懂我在說什么,誰能解釋下呢?感謝!


if(Key_S1 == 1)            //如果按鍵沒有被按下(高電平),將一些標(biāo)志位及時清零
        {
                ucKeyLock1 = 0;   //自鎖標(biāo)志位清
                uiKeyTimeCnt1 = 0;  //按鍵去抖動延時計數(shù)器清零
                uiKeyCtntyCnt1 = 0;   //連續(xù)累加的時間間隔延時計數(shù)器清零
        }



回復(fù)

使用道具 舉報

ID:213173 發(fā)表于 2022-2-9 22:34 | 顯示全部樓層
else if(ucKeyLock1 == 0)        這里else對應(yīng)上面的if(Key_S1 == 1)表示有按鍵按下,接著的if(ucKeyLock1 == 0)是判斷條件,ucKeyLock1 == 0 才可以執(zhí)行花括號內(nèi)語句。也就是按鍵按下后,CPU要執(zhí)行61次Key_Scan函數(shù)(延時消抖)才能滿足條件,ucKeyLock1 = 1;破壞上述條件,按鍵不松手也不會重復(fù)執(zhí)行這段語句。
回復(fù)

使用道具 舉報

ID:514254 發(fā)表于 2022-2-10 00:28 | 顯示全部樓層
找找程序段中其他的地方的ucKeyLock1 = 0
回復(fù)

使用道具 舉報

ID:161164 發(fā)表于 2022-2-10 01:44 | 顯示全部樓層
  1. if(Key_S1 == 1)            //如果按鍵沒有被按下(高電平),將一些標(biāo)志位及時清零
  2.         {
  3.         }else if(ucKeyLock1 == 0)        
復(fù)制代碼

這樣來看會不會清晰一點?
回復(fù)

使用道具 舉報

ID:276761 發(fā)表于 2022-2-10 09:18 | 顯示全部樓層
你只要理解if-else if就能明白了,上面if(Key_S1 == 1)只要成立,就不會執(zhí)行else if(ucKeyLock1 == 0),只要上面if(Key_S1 == 1)不成立了,就執(zhí)行else if(ucKeyLock1 == 0)
回復(fù)

使用道具 舉報

ID:997026 發(fā)表于 2022-2-10 10:00 | 顯示全部樓層
wulin 發(fā)表于 2022-2-9 22:34
else if(ucKeyLock1 == 0)        這里else對應(yīng)上面的if(Key_S1 == 1)表示有按鍵按下,接著的if(ucKeyLock ...

按我的理解,if-else if-else語句類似條件選擇吧,沒有所謂某個else if對應(yīng)哪個吧,滿足哪個條件就執(zhí)行哪個,都不滿足就執(zhí)行最后else里面的,應(yīng)該是這樣的邏輯才對。如果要滿足你說的這種判斷,我感覺應(yīng)該用if-else才對,而不是if-else if-else。ucKeyLock1 == 0這個判斷條件就像是憑空產(chǎn)生的,不理解
回復(fù)

使用道具 舉報

ID:997026 發(fā)表于 2022-2-10 10:30 | 顯示全部樓層
cliang223 發(fā)表于 2022-2-10 09:18
你只要理解if-else if就能明白了,上面if(Key_S1 == 1)只要成立,就不會執(zhí)行else if(ucKeyLock1 == 0),只 ...

謝謝回復(fù),其實你仔細(xì)看這其實是一個if-else if-else選擇語句,并不是if-esle語句,if-else if-else語句中,會判斷每一個if和else if中的表示式,如果滿足就執(zhí)行,不滿足就執(zhí)行最后一個else中的語句,邏輯應(yīng)該是這樣嗎?其實我的意思主要是ucKeyLock1 == 0為啥可以用來判斷按鍵被按下了?

Key_S1 == 1中,Key_S1表示的是IO口,可以檢測到高低電平,用來判斷按鍵狀態(tài),但是ucKeyLock1只是個變量,在上面if(Key_S1 == 1)成立時,已經(jīng)將ucKeyLock1 == 0清零了,這里怎么又用ucKeyLock1 == 0來表示按鍵被按下???感覺是矛盾的。
回復(fù)

使用道具 舉報

ID:213173 發(fā)表于 2022-2-10 11:09 | 顯示全部樓層
hxdby 發(fā)表于 2022-2-10 10:00
按我的理解,if-else if-else語句類似條件選擇吧,沒有所謂某個else if對應(yīng)哪個吧,滿足哪個條件就執(zhí)行哪 ...

ucKeyLock1 == 0這個判斷條件不是憑空產(chǎn)生的,是按鍵松手的結(jié)果之一。ucKeyLock1為1也不是按鍵按下的識別標(biāo)志,是按鍵按下并經(jīng)過消抖后才能賦值的自鎖標(biāo)志。在這段代碼中只有 if(Key_S1 == 1) 表示松手,對應(yīng)的3個else都是在按鍵按下后才順序判斷執(zhí)行相應(yīng)語句。
回復(fù)

使用道具 舉報

ID:997026 發(fā)表于 2022-2-10 12:07 | 顯示全部樓層
wulin 發(fā)表于 2022-2-10 11:09
ucKeyLock1 == 0這個判斷條件不是憑空產(chǎn)生的,是按鍵松手的結(jié)果之一。ucKeyLock1為1也不是按鍵按下的識別 ...

謝謝回復(fù)。

如果按鍵松手,那執(zhí)行的應(yīng)該是 if(Key_S1 == 1) 里面的語句,其他都不執(zhí)行。我的疑問是,如果按鍵按下,那應(yīng)該執(zhí)行哪條語句呢?上面的代碼說的是按鍵按下會執(zhí)行else if(ucKeyLock1 == 0),但是我不太明白,因為ucKeyLock1沒有和P0口發(fā)生關(guān)聯(lián),也不是標(biāo)志位,為啥這個能表示按鍵被按下?
回復(fù)

使用道具 舉報

ID:276761 發(fā)表于 2022-2-10 13:59 | 顯示全部樓層
hxdby 發(fā)表于 2022-2-10 10:30
謝謝回復(fù),其實你仔細(xì)看這其實是一個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中的表達(dá)式,但不是滿足就執(zhí)行的,如果前面的if滿足了,后面的else if就算滿足了都不會執(zhí)行的,就是一次只能執(zhí)行一個,先滿足的先執(zhí)行。那么if(Key_S1 == 1),如果滿足,表示按鍵沒有按下,那么后面的else if就不會執(zhí)行了,如果不滿足,說明按鍵按下了,那么就開始判斷后面的else if,第一個else if(ucKeyLock1 == 0),是定義的一個變量,是滿足的,那么就執(zhí)行它。下面你就應(yīng)該明白了吧
回復(fù)

使用道具 舉報

ID:997026 發(fā)表于 2022-2-10 19:45 | 顯示全部樓層
cliang223 發(fā)表于 2022-2-10 13:59
你還是沒有明白if,else if,else,你看上面的程序,if(Key_S1 == 1) ,else if(ucKeyLock1 == 0) ,else ...

非常感謝你的回復(fù)。

我確實弄錯了else if這個語句,因為比較少用else if, 以為是一個選擇語句,其實這個選擇是由條件的,就是必須是第一個if條件不滿足的時候才會執(zhí)行后面的語句,其實if-else if-else語句相當(dāng)于是if else語句的變體,后面的所有else if相當(dāng)于是嵌套在if -else的else后面的,if滿足,永遠(yuǎn)不會執(zhí)行后面的else if, if不滿足,才會按照后面else if順序判斷執(zhí)行。

這個程序很精妙,關(guān)鍵在于ucKeyLock這個變量,當(dāng)按鍵按下的時候,其實ucKeyLock仍然是為0的,如果此時按一下松手,則觸發(fā)一個鍵值輸出,程序跳轉(zhuǎn)到Key_S1==1下。如果持續(xù)按不松手,則ucKeyLock被賦值1,同時跳轉(zhuǎn)到后面的程序。

經(jīng)過大家的積極回復(fù),我大概搞懂了,感謝大家的幫助!
回復(fù)

使用道具 舉報

ID:1063563 發(fā)表于 2023-6-4 11:48 | 顯示全部樓層
else if(uiKeyTimeCnt1 < const_time_1s)    //按鍵已按下,按鍵去抖動延時計數(shù)器自增到1s
        {
                uiKeyTimeCnt1 ++;   
        }
這段是什么意思沒看懂
回復(fù)

使用道具 舉報

ID:883242 發(fā)表于 2023-6-4 15:55 | 顯示全部樓層
芯菲 發(fā)表于 2023-6-4 11:48
else if(uiKeyTimeCnt1 < const_time_1s)    //按鍵已按下,按鍵去抖動延時計數(shù)器自增到1s
        {
   ...

按下1s以內(nèi)單次按下,按下時間超過1s進(jìn)入連續(xù)按下狀態(tài)。
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表