天天看點

Verilog實作按鍵消抖

Verilog實作按鍵消抖

文章目錄

  • ​​Verilog實作按鍵消抖​​
  • ​​一、簡介​​
  • ​​二、消除按鍵抖動的方法​​
  • ​​三、軟體消抖原理​​
  • ​​四、代碼實作​​
  • ​​五、效果展示​​

一、簡介

我們在進行按鍵的時候往往會發生抖動的現象。

通常的按鍵所用開關為機械彈性開關,當機械觸點斷開、閉合時,由于機械觸點的彈性作用,一個按鍵開關在閉合時不會馬上穩定地接通,在斷開時也不會一下子斷開。因而在閉合及斷開的瞬間均伴随有一連串的抖動。這樣的抖動會對我們的按鍵操作産生一些幹擾,比如:有時候按下了一次按鍵,但是會發生很多次的功能的變化,這就是因為抖動的存在。

Verilog實作按鍵消抖

在機械按鍵的觸點閉合和斷開時,都會産生抖動,為了保證系統能正确識别按鍵的開關,就必須對按鍵的抖動進行處理。

按鍵的抖動對于人類來說是感覺不到的,但對單片機來說,則是完全可以感應到的,而且還是一個很“漫長”的過程,因為單片機處理的速度在“微秒”級,而按鍵抖動的時間至少在“毫秒”級。

單片機如果在觸點抖動期間檢測按鍵的通斷狀态,則可能導緻判斷出錯,即按鍵一次按下或釋放被錯誤地認為是多次操作,進而引起誤處理。是以,為了確定單片機對一次按鍵動作隻作—次響應,就必須考慮如何消除按鍵抖動的影響。

二、消除按鍵抖動的方法

按鍵穩定閉合時間長短是由操作人員決定的,通常都會在 100ms 以上,刻意快速按的話能達到 40-50ms 左右,很難再低了。抖動時間是由按鍵的機械特性決定的,一般都會在 10ms以内,為了確定程式對按鍵的一次閉合或者一次斷開隻響應一次,必須進行按鍵的消抖處理。當檢測到按鍵狀态變化時,不是立即去響應動作,而是先等待閉合或斷開穩定後再進行處理。按鍵消抖可分為硬體消抖和軟體消抖。

我們由于是使用Verilog HDL來實作的,是以就是屬于軟體消抖了,是以,我們也重點講述軟體消抖的原理。

三、軟體消抖原理

Verilog實作按鍵消抖

當按鍵較多時,硬體方法将導緻系統硬體電路設計複雜化,硬體消抖将無法勝任,這時常采用軟體方法進行消抖。常用軟體方法去抖,即檢測出鍵閉合後執行一個延時程式,5ms~10ms的延時,讓前沿抖動消失後再一次檢測鍵的狀态,如果仍保持閉合狀态電平,則确認為真正有鍵按下。當檢測到按鍵釋放後,也要給5ms~10ms的延時,待後沿抖動消失後才能轉入該鍵的處理程式。

Verilog實作按鍵消抖

軟體消抖的基本原理是:在檢測到有按鍵按下時,不是立即認定此鍵已被按下,而是執行一個10ms左右(具體時間應視所使用的按鍵進行調整)的延時程式後,再确認該鍵電平是否仍然保持閉合狀态電平,若仍然保持,則确認該鍵真正被按下。

一般來說,軟體消抖的方法是不斷檢測按鍵值,直到按鍵值穩定。實作方法:假設未按鍵時輸入1,按鍵後輸入為0,抖動時不定。可以做以下檢測:檢測到按鍵輸入為0之後,延時5ms~10ms,再次檢測,如果按鍵還為0,那麼就認為有按鍵輸入。延時的5ms~10ms恰好避開了抖動期,進而消除了前沿抖動的影響同理,在檢測到按鍵釋放後,再延時5~10ms,消除後沿抖動,然後再對鍵值進行處理。不過一般情況下,我們通常不對按鍵釋放的後沿進行處理,實踐證明,這樣也能滿足一定的要求。

四、代碼實作

1、、、、、

下面是實作按鍵消抖的子產品的代碼:

// ********************************************************************
// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
// ********************************************************************
// File name    : debounce.v
// Module name  : debounce
// Author       : STEP
// Description  : 
// Web          : www.stepfpga.com
// 
// --------------------------------------------------------------------
// Code Revision History : 
// --------------------------------------------------------------------
// Version: |Mod. Date:   |Changes Made:
// V1.0     |2017/03/02   |Initial ver
// --------------------------------------------------------------------
// Module Function:按鍵消抖
 
module debounce_button (clk,rst,key,key_pulse);
 
        parameter       N  =  1;                      //要消除的按鍵的數量
 
    input             clk;
        input             rst;
        input    [N-1:0]   key;                        //輸入的按鍵                    
    output  [N-1:0]   key_pulse;                  //按鍵動作産生的脈沖    
 
        reg     [N-1:0]   key_rst_pre;                //定義一個寄存器型變量存儲上一個觸發時的按鍵值
        reg     [N-1:0]   key_rst;                    //定義一個寄存器變量儲存儲目前時刻觸發的按鍵值
 
        wire    [N-1:0]   key_edge;                   //檢測到按鍵由高到低變化是産生一個高脈沖
 
        //利用非阻塞指派特點,将兩個時鐘觸發時按鍵狀态存儲在兩個寄存器變量中
        always @(posedge clk  or  negedge rst)
          begin
             if (!rst) begin
                 key_rst <= {N{1'b1}};                //初始化時給key_rst指派全為1,{}中表示N個1
                 key_rst_pre <= {N{1'b1}};
             end
             else begin
                 key_rst <= key;                     //第一個時鐘上升沿觸發之後key的值賦給key_rst,同時key_rst的值賦給key_rst_pre
                 key_rst_pre <= key_rst;             //非阻塞指派。相當于經過兩個時鐘觸發,key_rst存儲的是目前時刻key的值,key_rst_pre存儲的是前一個時鐘的key的值
             end    
           end
 
        assign  key_edge = key_rst_pre & (~key_rst);//脈沖邊沿檢測。當key檢測到下降沿時,key_edge産生一個時鐘周期的高電平
 
        reg    [17:0]      cnt;                       //産生延時所用的計數器,系統時鐘12MHz,要延時20ms左右時間,至少需要18位計數器     
 
        //産生20ms延時,當檢測到key_edge有效是計數器清零開始計數
        always @(posedge clk or negedge rst)
           begin
             if(!rst)
                cnt <= 18'h0;
             else if(key_edge)
                cnt <= 18'h0;
             else
                cnt <= cnt + 1'h1;
             end  
 
        reg     [N-1:0]   key_sec_pre;                //延時後檢測電平寄存器變量
        reg     [N-1:0]   key_sec;                    
 
 
        //延時後檢測key,如果按鍵狀态變低産生一個時鐘的高脈沖。如果按鍵狀态是高的話說明按鍵無效
        always @(posedge clk  or  negedge rst)
          begin
             if (!rst) 
                 key_sec <= {N{1'b1}};                
             else if (cnt==18'h3ffff)
                 key_sec <= key;  
          end
       always @(posedge clk  or  negedge rst)
          begin
             if (!rst)
                 key_sec_pre <= {N{1'b1}};
             else                   
                 key_sec_pre <= key_sec;             
         end      
       assign  key_pulse = key_sec_pre & (~key_sec);      

2、、、、、

然後,我們使用另外的一個測試的子產品來調用以上的按鍵消抖的子產品來實作具體的功能。

// Module Function:進過按鍵消抖後控制led顯示翻轉
 
module debounce (clk,rst,key,led);
 
        input             clk;
        input             rst;
        input              key;                                    
    output   reg      led;        
 
        wire              key_pulse;
 
        //當按鍵按下時産生一個高脈沖,翻轉一次led
        always @(posedge clk  or  negedge rst)
           begin
             if (!rst) 
        led <= 1'b1;
         else if (key_pulse)
        led <= ~led;
         else
                led <= led;
       end    
//      always @(posedge clk)
//           begin
//              if (key_pulse)
//                  led <= ~led;
//            else
//               led <= led;
//       end    
         //例化消抖module,這裡沒有傳遞參數N,采用了預設的N=1     
         debounce_button  u1 (                               
                       .clk (clk),
                       .rst (rst),
                       .key (key),
                       .key_pulse (key_pulse)
                       );      

之後,我們需要設定引腳;

Verilog實作按鍵消抖

然後進行燒錄:

Verilog實作按鍵消抖

五、效果展示

我們來看一下消抖之後的按鍵的效果,我們發現這裡的按鍵已經沒有任何的抖動的現象啦:

繼續閱讀