找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

帖子
查看: 3379|回復(fù): 1
收起左側(cè)

單片機(jī)按鍵掃描消抖經(jīng)典算法實(shí)現(xiàn)以及Proteus實(shí)例仿真對(duì)比

[復(fù)制鏈接]
ID:795427 發(fā)表于 2021-9-10 13:21 | 顯示全部樓層 |閱讀模式
按鍵掃描消抖經(jīng)典算法實(shí)現(xiàn)以及Proteus實(shí)例仿真對(duì)比

  • 算法實(shí)現(xiàn)函數(shù):
  1. unsigned char Trg;
  2. unsigned char Cont;
  3. void KeyRead( void )
  4. {
  5.     unsigned char ReadData = P1^0xff;   // 注解1
  6.     Trg = ReadData & (ReadData ^ Cont);   // 注解2
  7.     Cont = ReadData;                      // 注解3
  8. }
復(fù)制代碼
  • Trg(triger) 代表的是觸發(fā),Cont(continue)代表的是連續(xù)按下。

  • 注解1:讀P1的端口數(shù)據(jù),取反,然后送到ReadData 臨時(shí)變量里面保存起來。

  • 注解2:用來計(jì)算觸發(fā)變量的。一個(gè)位與操作,一個(gè)異或操作,我想學(xué)過C語言都應(yīng)該懂吧?Trg為全局變量,其它程序可以直接引用。

  • 注解3:用來計(jì)算連續(xù)變量。
  • 上述實(shí)現(xiàn)算法不僅適用于端口以總線方式來讀取判斷,也同樣適用于獨(dú)立IO口信號(hào)的判斷和處理,具體實(shí)現(xiàn)函數(shù)如下:
    1. unsigned char Trg;
    2. unsigned char Cont;
    3. void KeyRead( void )
    4. {
    5.     unsigned char ReadData = P10^0x01;   //
    6.     Trg = ReadData & (ReadData ^ Cont);   //
    7.     Cont = ReadData;                     /
    8.     }
    復(fù)制代碼

  • 1. 沒有按鍵的時(shí)候
  • 沒有按下時(shí),IO口為高電平,就是P10為0x01,ReadData讀端口并且和0x01進(jìn)行取反,很顯然,P10^0x01的值就是 0x00。
  • Trg = ReadData & (ReadData ^ Cont); (初始狀態(tài)下,Cont也是為0的)很簡(jiǎn)單的數(shù)學(xué)計(jì)算,因?yàn)镽eadData為0,則它和任何數(shù)“相與”,結(jié)果也是為0。
  • Cont = ReadData; 保存Cont 其實(shí)就是等于ReadData為0。
2. 第一次IO口按鍵按下的情況:
  • 端口沒有觸發(fā)時(shí),IO口狀態(tài)為0x01,ReadData讀端口并且取反,很顯然,就是 0x01 。

  • Trg = ReadData & (ReadData ^ Cont); 因?yàn)檫@是第一次按下,所以Cont是上次的值,應(yīng)為為0。那么這個(gè)式子的值也不難算,也就是 Trg = 0x01 & (0x01^0x00) = 0x01。
  • Cont = ReadData = 0x01;
    1. ReadData = 0x01;
    2. Trg = 0x01;//Trg只會(huì)在這個(gè)時(shí)候?qū)?yīng)位的值為1,其它時(shí)候都為0
    3. Cont = 0x01;<span style="background-color: rgb(255, 255, 255); color: rgb(79, 79, 79); font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun; font-weight: normal;"></span>
    復(fù)制代碼

3. IO口按鍵按著不松(長(zhǎng)按鍵)的情況:
  • 端口數(shù)據(jù)為0xfe,ReadData讀端口并且取反是 0x01 。

  • Trg = ReadData & (ReadData ^ Cont); 因?yàn)檫@是連續(xù)按下,所以Cont是上次的值,應(yīng)為為0x01。那么這個(gè)式子就變成了 Trg = 0x01 & (0x01^0x01) = 0x00
Cont = ReadData = 0x01;
  1.         ReadData = 0x01;
  2.         Trg = 0x00;
  3.         Cont = 0x01;
復(fù)制代碼
因?yàn)楝F(xiàn)在按鍵是長(zhǎng)按著,所以MCU會(huì)每個(gè)一定時(shí)間(20ms左右)不斷的執(zhí)行這個(gè)函數(shù),那么下次執(zhí)行的時(shí)候情況會(huì)是怎么樣的呢?

  • ReadData = 0x01;這個(gè)不會(huì)變,因?yàn)榘存I沒有松開.
  • Trg = ReadData & (ReadData ^ Cont) = 0x01 & (0x01 ^ 0x01) = 0 ,只要按鍵沒有松開,這個(gè)Trg值永遠(yuǎn)為 0.
  • Cont = 0x01;只要按鍵沒有松開,這個(gè)值永遠(yuǎn)是0x0.
4. 按鍵松開的情況:端口數(shù)據(jù)為0xff,ReadData讀端口并且取反是 0x00 。
  • Trg = ReadData & (ReadData ^ Cont) = 0x00 & (0x00^0x01) = 0x00;
  • Cont = ReadData = 0x00;
    1.         ReadData = 0x00;
    2.         Trg = 0x00;
    3.         Cont = 0x00;
    復(fù)制代碼
    回到了初始狀態(tài),也就是沒有按鍵按下的狀態(tài).
Proteus仿真
trr.gif

  • 代碼:
    1. #include <REGX52.H>
    2. #include <intrins.h>
    3. sbit KeyValue=P3^7;
    4. unsigned char code segment[]= {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
    5. //定義數(shù)碼管顯示0~9

    6. unsigned char Trg;
    7. unsigned char Cont;
    8.     static char count=1;
    9. void KeyRead( void )
    10. {
    11.     unsigned char ReadData = KeyValue^0x01;   // 注解1
    12.     Trg = ReadData & (ReadData ^ Cont);   // 注解2
    13.     Cont = ReadData;                     // 注解3
    14.         
    15. }

    16. void main() {
    17.                 P3=0XFF;
    18.     P0=segment[0]; //開始運(yùn)行顯示0
    19.     while(1) {
    20.                         KeyRead();
    21.         if(Trg==1) {
    22.             P0=segment[count];
    23.             count++;
    24.             if(count>=10) {  //超過0~9,數(shù)碼管顯示回到0
    25.                 count=0;
    26.             }
    27.         }
    28.     }
    29. }
    30. //void main() {//這是沒有經(jīng)過消抖處理的代碼
    31. //                P3=0XFF;
    32. //    P0=segment[0]; //開始運(yùn)行顯示0
    33. //    while(1) {
    34. //               
    35. //        if(KeyValue==0) {
    36. //            P0=segment[count];
    37. //            count++;
    38. //            if(count>=10) {  //超過0~9,數(shù)碼管顯示回到0
    39. //                count=0;
    40. //            }
    41. //        }
    42. //    }
    43. //}
    復(fù)制代碼
  • 這種算法摒棄了使用延時(shí)的常規(guī)做法。
  • 仿真文件和程序建附件
trr02.gif 51hei.png

全部資料51hei附件下載:
按鍵掃描消抖算法實(shí)現(xiàn).zip (61.47 KB, 下載次數(shù): 33)

評(píng)分

參與人數(shù) 1黑幣 +80 收起 理由
admin + 80 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

回復(fù)

使用道具 舉報(bào)

ID:34149 發(fā)表于 2021-9-11 19:12 | 顯示全部樓層
樓主辛苦了,值得學(xué)習(xí)!
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

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

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

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