久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 32690|回復: 19
打印 上一主題 下一主題
收起左側

按鍵消抖方法與抖動原因分析(狀態機,延時,邏輯關系消抖)單片機源程序

  [復制鏈接]
跳轉到指定樓層
樓主
本人第一次發帖,如果有錯誤,歡迎大家指正!!!有關按鍵消抖的話題已經有很多人提出來了,在這里我把它進行一個總結。希望能幫助到大家!
1.按鍵抖動的原因
       按鍵消抖通常的按鍵所用開關為機械彈性開關,當機械觸點斷開、閉合時,由于機械觸點的彈性作用,一個按鍵開關在閉合時不會馬上穩定地接通,在斷開時也不會一下子斷開。形成以下的波形
   
2.按鍵抖動的原理
      按鍵抖動時間的長短由按鍵的機械特性決定,一般為5ms~10ms。這是一個很重要的時間參數,在很多場合都要用到。按鍵穩定閉合時間的長短則是由操作人員的按鍵動作決定的,一般為零點幾秒至數秒。鍵抖動會引起一次按鍵被誤讀多次。為確保單片機對按鍵的一次閉合僅作一次處理,必須去除鍵抖動。在鍵閉合穩定時讀取鍵的狀態,并且必須判別到按鍵釋放到穩定狀態后再去作處理。
3.按鍵消抖的方法
(1)硬件的消抖
      利用電容的充放電特性來對抖動過程中產生的電壓毛刺進行平滑處理,從而實現消抖。在按鍵的兩端并聯一個0.1uf的電容。如按鍵消抖硬件圖
。
(2)軟件的消抖
     1.延時消抖
        剛接觸單片機的時候,最常用的方法,利用延時,消去抖動。代碼如下:
       if(按鍵是否按下)
       {                        //按鍵按下的條件下
           Deadly_1ms(5); // 延時消去抖動
           if(按鍵是否按下)
          {                   //按鍵再次確認按下
              //執行按鍵功能
             while(按鍵是否松開);
          }
       }
   注:按鍵詳細代碼見工程文件延時消抖
    2.狀態機消抖
      將按鍵的狀態分為三種 是否按下,是否抖動,是否彈起。檢測到按下時,轉向判斷是否抖動,并執行按鍵功能。等按鍵功能執行完了以后直接跳到按鍵是否彈起的狀態。等彈起后,再來判斷是否按下的狀態。
       在按鍵的原理圖中,將1、2相接,則構成的是4*4的矩陣鍵盤,并且矩陣鍵盤與單片機的P3口相接。
       //按鍵原理圖見上傳的圖片
        
//設置按鍵的三種狀態及按鍵接口
#define KEY P3
#define key_state_0  0  //判斷是否按下
#define key_state_1  1 //判斷是否為抖動
#define key_state_2  2 //判斷是否彈起

unsigned char key_read(void)
{
  static char key_state = key_state_0;
  unsigned char key_return=0, key_press;
  unsigned char key1,key2;
        
        KEY=0xf0;   
        key1=KEY&0xf0;
        KEY=0x0f;
        key2=KEY&0x0f;
        key_press =key1|key2;  //讀取矩陣按鍵每個按鍵的狀態,存在key_press里
        
switch (key_state)  // 判斷按鍵狀態
{         
   case key_state_0:    //是否按下
   if (key_press!=0xff) key_state = key_state_1;  //沒有按鍵按下時則讀取出的0xff,若有不同說明有按鍵按下,則跳轉到判斷是否為抖動的狀態
   break;
         
   case key_state_1:     
   if (key_press !=0xff) //再次確認是否按下,防止因單片機的速度過快,導致誤判。
   {   
       switch (key_press)//根據key_press的值來執行相對應的功能
       {
           case 0xee: key_return = 19; //這里的0xee是怎么的來的,簡單來推一下
           case 0xed: key_return = 18; //單片機的P3口初始化輸出的是高電平,先將P3口輸出0xf0,如果有按鍵按下,則P3口中的高四位的某一位的電平會被拉低,此時記錄P3口的狀態(key1)
           case 0xeb: key_return = 17; //讀取了高四位的電平,之后再來讀取低四位的電平(key2) ,之后 | 在一起得到key_press,得到的key_press中一定有兩位是0;
           case 0xe7: key_return = 16;//舉例 : 當我按下s19時,key1 = 0xe0;(即P3^4 = 0,高四位的第一位電平被拉低),key2 = 0x0e;(即P3^0 = 0,低四位的第一位電平被拉低),這樣key_press = key_press =key1|key2  = 0xee;
           case 0xde: key_return = 15;//以此類推
           case 0xdd: key_return = 14;
           case 0xdb: key_return = 13;
           case 0xd7: key_return = 12;
           case 0xbe: key_return = 11;
           case 0xbd: key_return = 10;
           case 0xbb: key_return = 9;
           case 0xb7: key_return = 8;
           case 0x7e: key_return = 7;
           case 0x7d: key_return = 6;
           case 0x7b: key_return = 5;
           case 0x77: key_return = 4;
       }
                        key_state = key_state_2; //這里跳轉到判斷彈起的狀態
   }
   else
                        key_state = key_state_0;  
   break;

   case key_state_2:
   if (key_press==0xff) key_state = key_state_0;  //等待按鍵完全彈起
   break;
}
return key_return;
}
注:具體用法見工程狀態機消抖  

    3.邏輯關系消抖
       將按鍵的原理圖中,將2、3相接,則構成的是獨立鍵盤(s4,s5,s6,s7),并且獨立鍵盤與單片機的P3口的低四位相接,另一端與gnd相接。
    利用邏輯關系 與&、或 | 、非 !、異或 ^,來消除抖動。先貼出源代碼:

    unsigned char ReadData = KEYPORT^0xff;
    Trg = ReadData & (ReadData ^ Cont);      
    Cont = ReadData;

    Trg是判斷那個按鍵按下,Cont用來判斷長按、短按的;
分析:   (1)沒有按鍵按下(初始值 Trg  =  0,Cont  = 0)
                  unsigned char ReadData = P3^0xff;  => ReadData  = 0xff ^0xff = 0x00;
                  Trg = ReadData & (ReadData ^ Cont); =>Trg  =0x00 &  (0x00 ^0x00)  = 0x00;
                  Cont = ReadData;    =>Cont  = 0x00;

                 結果 :
                         ReadData  = 0x00
                        Trg           = 0x00
                        Cont         = 0x00

            (2) s4按下
                  剛按下時
                  unsigned char ReadData = P3^0xff;  => ReadData  = 0xf7 ^0xff = 0x08;
                  Trg = ReadData & (ReadData ^ Cont); =>Trg  =0x08 &  (0x08^0x00)  = 0x08;
                  Cont = ReadData;    =>Cont  = 0x08;

               抖動時
                  unsigned char ReadData = P3^0xff;  => ReadData  = 0xff ^0xff = 0x00;
                  Trg = ReadData & (ReadData ^ Cont); =>Trg  =0x00 &  (0x00^0x08)  = 0x00;
                  Cont = ReadData;    =>Cont  = 0x00;

                 結果 :
                       剛按下時:
                        ReadData  = 0x08
                        Trg           = 0x08
                        Cont         = 0x08

                       抖動時:
                        ReadData  = 0x00
                        Trg           = 0x00
                        Cont         = 0x00


            (3) s4長按
                  unsigned char ReadData = P3^0xff;  => ReadData  = 0xf7 ^0xff = 0x08;
                  Trg = ReadData & (ReadData ^ Cont); =>Trg  =0x08 &  (0x08 ^0x00)  = 0x00;
                  Cont = ReadData;    =>Cont  = 0x08;

                 結果 :
                         ReadData  = 0x08
                        Trg           = 0x00
                        Cont         = 0x08


            (4) s4松開
                  unsigned char ReadData = P3^0xff;  => ReadData  = 0xff ^0xff = 0x00;
                  Trg = ReadData & (ReadData ^ Cont); =>Trg  =0x08 &  (0x08 ^0x00)  = 0x00;
                  Cont = ReadData;    =>Cont  = 0x00;

                 結果 :
                         ReadData  = 0x00
                        Trg           = 0x00
                        Cont         = 0x00


將上面的數據進行匯總、分析
ReadData  Trg           Cont         
沒有按鍵按下 0x00 0x00 0x00
s4剛按下 0x08 0x08 0x08
s4有抖動時 0x00 0x00 0x00
s4長按 0x08 0x00 0x08
  s4松開 0x00 0x00 0x00


Trg只有在按鍵剛按下時有不到等于0的值,因此我們檢測到Trg 不為0時,說明有按鍵按下;
Cont 只要有按鍵按下時,它的值就不為0,因此我們定時一段時間,來檢測Cont,,若不變,則按鍵時長按的狀態。
注:具體用法見工程邏輯關系消抖

          到這里只是簡單的介紹了幾種按鍵消抖,還有很多方法沒有介紹,比如,中斷消抖,門電路消抖,計時消抖…,但萬變不離其中。學會了其中一種,其他的就自然懂了。
         希望這篇帖子能幫助到大家。。!

全部資料51hei下載地址(全部程序源碼):
按鍵.rar (68.28 KB, 下載次數: 171)


評分

參與人數 2黑幣 +105 收起 理由
lakeleeson + 5 很給力!
admin + 100 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏37 分享淘帖 頂7 踩
回復

使用道具 舉報

沙發
ID:391536 發表于 2018-8-31 14:09 | 只看該作者
樓主寫的非常詳細 好資料,51黑有你更精彩!!!
回復

使用道具 舉報

板凳
ID:896842 發表于 2021-3-26 14:36 | 只看該作者
樓主寫的很好,先收藏研究一下
回復

使用道具 舉報

地板
ID:15415 發表于 2023-5-29 16:48 | 只看該作者
非常好的資料,謝謝樓主
回復

使用道具 舉報

5#
ID:202023 發表于 2023-6-21 10:55 | 只看該作者
不錯,萬丈高樓平地起,越是看似簡單的東西,越要用心去學。謝謝樓主分享。
回復

使用道具 舉報

6#
ID:202023 發表于 2023-6-21 11:01 | 只看該作者
樓主是你的資料有問題,還是我的軟件有問題。

error.JPG (50.54 KB, 下載次數: 125)

error.JPG
回復

使用道具 舉報

7#
ID:202023 發表于 2023-6-21 11:03 | 只看該作者
oh,在不解壓下可以打開,解壓了反而打不開了,是我的原因。
回復

使用道具 舉報

8#
ID:423911 發表于 2023-8-13 09:16 | 只看該作者
感謝樓主,非常好的資料,很有用。
回復

使用道具 舉報

9#
ID:34149 發表于 2023-8-15 10:45 | 只看該作者
分析很透徹!好辦法!
回復

使用道具 舉報

10#
ID:224580 發表于 2023-8-17 14:08 | 只看該作者
分析很透,佩服這些大神
回復

使用道具 舉報

11#
ID:1083996 發表于 2023-8-20 09:55 | 只看該作者
很棒的分析,感謝分享。
回復

使用道具 舉報

12#
ID:202023 發表于 2023-8-30 13:19 | 只看該作者

樓主寫的非常詳細 好資料,51黑有你更精彩!!!
回復

使用道具 舉報

13#
ID:227818 發表于 2024-8-14 13:40 | 只看該作者
謝謝大佬
回復

使用道具 舉報

14#
ID:1096929 發表于 2024-8-16 19:18 | 只看該作者
哎呀,你為什么把每個按鍵都定義呢,直接橫掃縱掃不就行了
回復

使用道具 舉報

15#
ID:344848 發表于 2024-8-17 03:04 | 只看該作者
使用硬件去抖動電路:1)RS觸發器去抖動,2)單穩觸發器——74HC221,3)同相器組成的積分去抖動電路。
回復

使用道具 舉報

16#
ID:466250 發表于 2024-8-17 03:09 | 只看該作者
程序啰里啰唆,采樣后僅判斷2次,完全沒這個必要的邏輯,后面的keycode重新賦值也根本沒必要,采樣出來本來已經是按鍵值,沒必要再次轉換。除非還有其他的采樣,要放在一個8位的byte里面去識別。
回復

使用道具 舉報

17#
ID:1130610 發表于 2024-8-17 09:34 | 只看該作者
寫的非常詳細
回復

使用道具 舉報

18#
ID:496636 發表于 2024-8-17 12:16 | 只看該作者
看了一下,你的狀態機消抖,你key_press!=0xff時,表明有鍵按下,賦key_state=1,則執行case=1語句,再判斷key_press!=0xff,就幾條語句,也就幾個微秒而已,延時很短的,這有問題。
還是手把手教你學51單片機 宋學松處理陣列按鍵程序來得好。
它的思路是:采用中斷的形式,1毫秒中斷,在1毫秒中斷中,使某一行為低電平,其它為高電平。然后把這一行中的按鍵狀態緩存在狀態字節數組中(4*4的二維數組中),有四行,則要執行4次,花4毫秒才能把各個按鍵的狀態存儲一遍。存儲的字節先左移一位,然后從最低位移入狀態位(列狀態),1為按鍵沒按下,0表示按下。通過16次,16毫秒掃描,就存儲了四次矩陣按鍵狀態,這樣存儲在字節的低四位中。
假設4次都是1,表明已穩定彈起,假設4次都為0,表明穩定鍵下,如果不全是1或是0,則在按鍵過渡期。只要把這16這字節的數組與0x0f按位與,就能判斷是不是穩定按下,或是穩定彈出,如果是,就返回某按鍵值為1或是0,使代表按鍵消抖狀態的二維數組中的某個數為1或是0
回復

使用道具 舉報

19#
ID:496636 發表于 2024-8-17 12:23 | 只看該作者
貼上宋學松的程序片段:此程序在1毫秒中斷程序中執行
//將一行的 4 個按鍵值移入緩沖區
keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1;
keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2;
keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3;
keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4;
//消抖后更新按鍵狀態
for (i=0; i<4; i++) //每行 4 個按鍵,所以循環 4 次
{
if ((keybuf[keyout][i] & 0x0F) == 0x00)
{ //連續 4 次掃描值為 0,即 4*4ms 內都是按下狀態時,可認為按鍵已穩定的按下
KeySta[keyout][i] = 0;
}
else if ((keybuf[keyout][i] & 0x0F) == 0x0F)
{ //連續 4 次掃描值為 1,即 4*4ms 內都是彈起狀態時,可認為按鍵已穩定的彈起
KeySta[keyout][i] = 1;
}
}
//執行下一次的掃描輸出
keyout++; //輸出索引遞增
keyout = keyout & 0x03; //索引值加到 4 即歸零
switch (keyout) //根據索引,釋放當前輸出引腳,拉低下次的輸出引腳
{
case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0; break;
case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break;
case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break;
case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0; break;
default: break;
}
回復

使用道具 舉報

20#
ID:1129643 發表于 2024-8-31 10:17 | 只看該作者
看了樓主的貼子對按鍵消抖又有了新的理解
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 欧美色综合一区二区三区 | 精品久久久久久中文字幕 | 搞黄视频免费看 | 欧美高清性xxxxhd | 欧美一级片久久 | 日韩欧美网 | 久久不射电影网 | 一区二区高清 | 91视频一区二区三区 | 成人黄色av| 四虎成人免费视频 | 国产免费观看视频 | 亚洲国产成人精品久久久国产成人一区 | 亚洲国产精品第一区二区 | 日韩资源 | 韩日一区二区三区 | 天天干天天爽 | 国产精品theporn | 九九热精品免费 | 久草视频观看 | 欧美片网站免费 | 一区二区日韩精品 | 久久久久国产 | 91精品国产综合久久婷婷香蕉 | av影片在线| 夜夜操av | 国产韩国精品一区二区三区 | 国产一区二区三区日韩 | 精品日韩一区 | 国产婷婷色一区二区三区 | 国产wwwcom | 久久国产亚洲 | 亚洲伊人久久综合 | 天天爽一爽 | 欧美在线a | www.日日操| 欧美日韩在线国产 | 亚洲男人天堂2024 | 91午夜在线 | 在线看成人av | 亚洲一区 中文字幕 |