按鍵消抖


按鍵消抖原因

使用機械彈性開關,當機械觸點閉合/斷開時,由於機械觸點的彈性作用,一個按鍵開關在閉合時不會馬上穩定的接通,在斷開時也不會馬上斷開。而是會在閉合/斷開的瞬間伴隨一連串的抖動,為避免這種現象帶來的問題,需要進行按鍵消抖。

硬件消抖

按鍵個數較少時可以使用硬件方法消除抖動。下圖所示為使用RS觸發器進行硬件消抖,當按鍵未按下時,輸出為0;當按鍵按下時,輸出為1。此時,即使按鍵因為彈性抖動而產生瞬時斷開(抖動從B跳開),只要按鍵不回到原始狀態A,雙穩態觸發器的狀態也不會改變(保持為0),從而不產生抖動的波形。

軟件消抖

原理

按鍵數量較多的情況下,通常采用軟件方法進行消抖。在檢測到按鍵閉合后開始執行一個延時程序,根據抖動的時間通常為5~10ms,去產生一個20ms的延時,讓前沿抖動消失后再一次檢測按鍵的狀態。如果仍保持閉合狀態電平,則認定為真正有鍵按下。

消抖過程中的問題

1、消除機械抖動導致的毛刺影響

由於機械抖動關系,在按鍵按下和松開過程中會出現按鍵抖動現象,從而導致計數器技術時間難以確定。

 

解決方法:計數器的開始由最后一次低電平(按鍵信號)決定。若按鍵信號key_in在到達產生flag之前置高,則將前一次脈沖認為是抖動,計數器清零,在下一次key_in置低后計數器再開始計數。換言之就是:系統檢測到key_in為低電平的時候開始計數,檢測到高電平時計數器清零。

2、按鍵時間過久導致出現多個flag信號的現象

假設使用50MHz的晶振進行計算,計數器計數20ms需要計數999_999個周期,當計數器計滿后習慣清零,從而導致flag信號到達999_999后產生1個時鍾周期寬度的flag信號,同時計數器歸零。當按鍵時間過久,可能導致計數器存在多個0→999_999→0狀態,同時,每次到達999_999后會產生一個按鍵被按下的flag,從而導致出現多個flag的脈沖。

解決方法:計數器的歸零由按鍵信號決定,當按鍵信號為高電平(表示按鍵被松開)時,計數器才從999_999歸零。

同時為確保flag信號僅保持一個周期,當計數器為999_998時,產生flag信號。否則flag會一直保持高電平直到計數器歸零。

 

按鍵消抖代碼

 1 module key_fileter #(parameter CNT_MAX=20'd999_999)(
 2     input        sys_clk        ,    // 系統時鍾50MHz
 3     input        sys_rst_n    ,    // 全局復位
 4     input        key_in        ,    // 按鍵輸入信號
 5     output    reg    key_flag        // 為1時表示消抖后檢測到按鍵被按下,為0表示沒有檢測到被按下
 6 );
 7     reg    [19:0]    cnt_20ms;
 8     // cnt_20ms:如果時鍾的上升沿檢測到外部按鍵輸入的值為低電平時,開始計數
 9     always @(posedge sys_clk or negedge sys_rst_n)
10         if(!sys_rst_n)
11             cnt_20ms <= 20'b0;
12         else if(key_in)
13             cnt_20ms <= 20'b0;
14         else if(cnt_20ms==CNT_MAX && key_in)
15             cnt_20ms <= cnt_20ms;
16         else
17             cnt_20ms <= cnt_20ms + 1'b1;
18     
19     // key_flag:當計數滿20ms后產生按鍵有效標志位,且key_flag在999_999時拉高,維持一個周期的高電平
20     always @(posedge sys_clk or negedge sys_rst_n)
21         if(!sys_rst_n)
22             key_flag <= 1'b0;
23         else if(cnt_20ms== CNT_MAX-1'b1)
24             key_flag <= 1'b1;
25         else
26             key_flag <= 1'b0;
27             
28 endmodule
key_filter

按鍵消抖testbench

 1 `timescale 1ns/1ns
 2 
 3 module tb_key_filter();
 4     // I/O port
 5     reg            sys_clk;
 6     reg            sys_rst_n;
 7     reg            key_in;
 8     wire        key_flag;
 9     
10     reg    [21:0]    tb_cnt;
11     
12     // 為縮短仿真時間,將參數化的時間值改小,但位寬定參數名的寬度
13     parameter    CNT_1MS = 20'd19;
14     parameter    CNT_11MS = 21'd69;
15     parameter    CNT_41MS = 22'd149;
16     parameter    CNT_51MS = 22'd199;
17     parameter    CNT_60MS = 22'd249;
18                     
19     // 初始化系統時鍾、復位信號和輸入信號
20     initial
21         begin
22             sys_clk     <= 1'b1;
23             sys_rst_n     <= 1'b0;
24             key_in         <= 1'b0;
25             #20
26             sys_rst_n    <= 1'b1;
27         end
28     
29     // 定義系統時鍾,50MHz
30     always #10 sys_clk = ~sys_clk;
31     
32     // tb_cnt: 按鍵過程計數器,用於模擬按鍵抖動過程
33     always @(posedge sys_clk or negedge sys_rst_n)
34         if(!sys_rst_n)
35             tb_cnt <= 22'b0;
36         else if(tb_cnt==CNT_60MS)    // 計數器計到60MS是完成一次按鍵從按下到釋放的過程
37             tb_cnt <= 22'b0;
38         else
39             tb_cnt <= tb_cnt + 1'b1;
40             
41     // key_in:產生輸入隨機數,模擬按鍵情況
42     always @(posedge sys_clk or negedge sys_rst_n)
43         if(!sys_rst_n)
44             key_in <= 1'b1;            // 按鍵未按下時的狀態為高電平
45         else if((tb_cnt>=CNT_1MS && tb_cnt<=CNT_11MS) || (tb_cnt>=CNT_41MS && tb_cnt<=CNT_51MS))
46             key_in <= {$random} % 2;
47         else if(tb_cnt>=CNT_11MS && tb_cnt<=CNT_41MS)
48             key_in <= 1'b0;
49         else
50             key_in <= 1'b1;
51             
52     //--------------------key_filter_inst------------------------------
53     key_fileter #(
54     .CNT_MAX        (20'd24            )
55     )
56     key_fileter_inst(
57         .sys_clk    (sys_clk        ),
58         .sys_rst_n    (sys_rst_n        ),
59         .key_in        (key_in            ),
60         .key_flag    (key_flag        )
61     );
62     
63 endmodule
tb_key_filter

波形圖

時鍾頻率為50MHz,當key_in保持24個周期的低電平時,產生一個周期的key_flag脈沖。波形圖如下圖所示。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM