新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > Lattice MXO2: 按鍵消抖

        Lattice MXO2: 按鍵消抖

        作者: 時間:2023-11-08 來源:電子森林 收藏

        按鍵


        在之前的實驗中我們學習了如何用按鍵作為的輸入控制,在本實驗中將學習如何進行按鍵,用按鍵完成更多的功能。

        本文引用地址:http://www.104case.com/article/202311/452611.htm

        硬件說明


        按鍵是一種常用的電子開關,電子設計中不可缺少的輸入設備。當按下時使開關導通,松開時則開關斷開,內部結構是靠金屬彈片來實現通斷。

        按鍵抖動的原理

        抖動原理

        • 抖動的產生 :通常的按鍵所用的開關為機械彈性開關,當機械觸點斷開、閉合時,由于機械觸點的彈性作用,一個按鍵開關在閉合時不會馬上穩定地接通,在斷開時也不會一下子斷開。因而在閉合及斷開的瞬間均伴隨有一連串的抖動,為了不產生這種現象而作的措施就是按鍵。
        • 消除抖動的措施:一般我們采用軟件方法消抖。即檢測到按鍵按下動作之后進行10ms~20ms左右的延時,當前沿的抖動消失之后再一次檢測按鍵的狀態。如果仍然是按下的電平狀態,則認為這是一次真正的按鍵按下;同樣檢測到按鍵釋放,也要做10ms~20ms延時,檢測到后沿抖動消失后認為是一個完整的按鍵彈起過程。
        • 消抖的好處:執行按鍵消抖有兩個好處,
          • 消除誤觸發:我們想通過按鍵來翻轉信號(例如按下一次led亮,在按一次led滅),如果沒有進行消抖,則會產生很多誤觸發造成不必要的翻轉。
          • 記錄按鍵次數:執行按鍵消抖可以讓我們記錄按鍵動作的次數,在很多應用里這非常有用。

        在點亮LED實驗中我們知道了板子上按鍵的設計,當按鍵未被按下時,連接到管腳認為是高電平;當按鍵被按下時,連接到管腳認為是低電平。

        要消除按鍵的抖動,我們需要去掃描按鍵,也就是不斷的去采集按鍵的狀態。軟件消抖時我們一般只考慮按鍵按下時的抖動,而放棄對釋放時抖動的消除。用系統時鐘(頻率較高)去采集按鍵狀態,當檢測到按下時用計數器延時20ms,再去檢測按鍵狀態,如果這時仍為按下狀態,確認是一次按下動作,否側的話認為無按鍵按下。如何檢測按鍵狀態變化就需要用到脈沖邊沿檢測的方法。

        脈沖邊沿檢測

        檢測按鍵按下時要用到脈沖邊沿檢測的方法,捕捉信號的突變、捕捉時鐘的上升下降沿等經常會用到這種方法。簡單地說就是用一個頻率更高的時鐘去觸發要檢測的信號,用兩個寄存器去儲存相鄰兩個時鐘采集到的值,然后進行異或運算,如果不為零,代表發生了上升沿或者下降沿。

        在按鍵消抖的過程中,同樣運用了脈沖邊沿檢測。用兩個寄存器儲存相鄰時鐘采集的值(例如datapre,data),然后將data取反與前一個值相與(state=datapre&(~data)),如果為1,則判斷有下降沿既按鍵按下由高到低;否則無變化。
        將一個信號由連續時鐘采集,相鄰兩個鐘觸發的值存入兩個寄存器。理解verilog實現這個過程要充分了解其中的非阻塞賦值。


        Verilog代碼


        本實驗主要通過按鍵來控制led的翻轉,當按下一次led變亮,再按下一次led變暗。首先我們做個試驗,對按鍵不做處理通過按鍵來控制led翻轉。

        // ********************************************************************
        // >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
        // ********************************************************************
        // File name    : top.v
        // Module name  : top
        // Author       : STEP
        // Description  : control led through the button
        // 
        // --------------------------------------------------------------------
        // Code Revision History : 
        // --------------------------------------------------------------------
        // Version: |Mod. Date:   |Changes Made:
        // V1.0     |2017/03/02   |Initial ver
        // --------------------------------------------------------------------
        // Module Function:按鍵控制led翻轉,未做消抖 
        module top(
        		key,          //按鍵輸入
        		rst,          //復位輸入
        		led           //led輸出
        		); 	input key,rst;
        	output reg led; 	always @(key or rst)
        		if (!rst)             //復位時led熄滅
        			led = 1;
        		else if(key == 0)     
        			led = ~led;   //按鍵按下時led翻轉
        		else
        			led = led;
        			endmodule

        未經過消抖的程序下載到上會發現按鍵有時不能夠控制led翻轉,這是因為按鍵的抖動造成了led狀態變化不可控,所以我們必須將抖動消除。下面是一種延時去抖的程序

        // ********************************************************************
        // >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
        // ********************************************************************
        // File name    : debounce.v
        // Module name  : debounce
        // Author       : STEP
        // Description  : 
        // 
        // --------------------------------------------------------------------
        // Code Revision History : 
        // --------------------------------------------------------------------
        // Version: |Mod. Date:   |Changes Made:
        // V1.0     |2017/03/02   |Initial ver
        // --------------------------------------------------------------------
        // Module Function:按鍵消抖 
        module debounce (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);      
               endmodule

        以上就是一個N位按鍵的消抖程序,如果有按鍵按下會輸出一個時鐘周期的高脈沖。下面我們可以試試用這個按鍵消抖的輸出來觸發LED的顯示,既按鍵一次LED翻轉。你也可以不加按鍵消抖試試用按鍵來控制LED(按一次變亮,再按一次滅掉)。

        下面的程序是例化調用debounce模塊來控制LED

        // ********************************************************************
        // >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
        // ********************************************************************
        // File name    : top.v
        // Module name  : top
        // Author       : STEP
        // Description  :  
        // 
        // --------------------------------------------------------------------
        // Code Revision History : 
        // --------------------------------------------------------------------
        // Version: |Mod. Date:   |Changes Made:
        // V1.0     |2017/03/02   |Initial ver
        // --------------------------------------------------------------------
        // Module Function:進過按鍵消抖后控制led顯示翻轉 
        module top (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    
                 //例化消抖module,這里沒有傳遞參數N,采用了默認的N=1     
                 debounce  u1 (                               
                               .clk (clk),
                               .rst (rst),
                               .key (key),
                               .key_pulse (key_pulse)
                               );
         endmodule

        引腳分配


        設置好復位鍵可消抖的按鍵,編譯完成后下載,通過按鍵就可以翻轉LED。你也可以定義多個按鍵控制多個LED,還可以比較不加按鍵消抖情況下實際的效果對比如何。

        信號引腳
        clkC1
        rstL14
        keyN14
        ledN13

        小結


        在本實驗學習了如何進行按鍵的消抖。在很多應用情況下我們必須采取消抖才能更好地控制邏輯。在下一個實驗計時控制中我們將學習計時的顯示和控制,在這里我們要用到按鍵的消抖以及數碼管,我們甚至可以用做一個計時器甚至電子表。



        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 旌德县| 颍上县| 错那县| 黎城县| 沽源县| 博罗县| 海安县| 稻城县| 科技| 长垣县| 贵州省| 区。| 武城县| 富平县| 吴堡县| 怀来县| 西贡区| 麻江县| 徐水县| 永昌县| 深泽县| 麻栗坡县| 巧家县| 湖北省| 广饶县| 武强县| 马尔康县| 林州市| 甘谷县| 万安县| 贡山| 颍上县| 隆子县| 乌兰察布市| 达尔| 玉环县| 沾化县| 华宁县| 泾川县| 昭苏县| 太原市|