FPGA中的單獨按鍵消抖
項目名稱:單獨按鍵消抖
具體要求:消除按鍵按下以及抬起時所帶來的抖動。
項目分析:
1. 按鍵電路

2.?抖動的產(chǎn)生
通常的按鍵所用開關(guān)為機械彈性開關(guān),當機械觸點斷開、閉合時,由于機械觸點的彈性作用,一個按鍵開關(guān)在閉合時不會馬上穩(wěn)定地接通,在斷開時也不會一下子斷開。因而在閉合及斷開的瞬間均伴隨有一連串的抖動。

3.?按鍵抖動帶來的危害? ?
鍵抖動會引起一次按鍵被誤讀多次。為確保 CPU 對鍵的一次閉合僅作一次處理,必須去除鍵抖動。在鍵閉合穩(wěn)定時讀取鍵的狀態(tài),并且必須判別到鍵釋放穩(wěn)定后再作處理。
4.?抖動的一些參數(shù)
抖動時間的長短由按鍵的機械特性決定,一般為 5ms~10ms。這是一個很重要的時間參數(shù),在很多場合都要用到。按鍵穩(wěn)定閉合時間的長短則是由操作人員的按鍵動作決定的,一般為零點幾秒至數(shù)秒。
5.?解決辦法
一是延時重采樣;二是持續(xù)采樣。從理論上來說,延時(如10ms)重采樣的準確率肯定低于持續(xù)采樣。筆者采用持續(xù)采樣。
架構(gòu)圖如下:

key_n:帶有抖動的低電平有效的按鍵輸入(按鍵按下為低電平)
click_n:濾除抖動之后的低電平有效的按鍵波形
系統(tǒng)設計:
1.?工程的名稱:key_filter
2.?狀態(tài)轉(zhuǎn)移圖如下:

MASK_TIME : 持續(xù)采樣的時間(選擇為 10ms)
設計代碼如下:
/*
模塊名稱:key_filter ?
模塊功能:消除按鍵按下以及抬起時所帶來的抖動。?
*/
module key_filter (clk, rst_n, key_n, click_n);
????????input clk;
????????input rst_n;
????????input key_n;
????????output reg click_n;
????????parameter MASK_TIME = 500_000;//驅(qū)動時鐘為 50M,10ms
?????????????????????????????????????????????????????????????????//為 500_000 個周期
????????reg [18:0] cnt;
????????reg state;
????????localparam s0 = 1'b0,
????????????????????????????s1 = 1'b1;
????????always @ (posedge clk or negedge rst_n)
????????????begin
????????????????if (!rst_n)
????????????????????begin
????????????????????????click_n <= 1'b1;
????????????????????????cnt <= 19'd0;
????????????????????????state <= s0;
????????????????????end
????????????????else
????????????????????begin
????????????????????????case (state)
????????????????????????????s0 : begin
????????????????????????????????if (key_n == 1'b0)
????????????????????????????????????begin
????????????????????????????????????????if (cnt < MASK_TIME - 1)
????????????????????????????????????????????begin
????????????????????????????????????????????????cnt <= cnt + 1'b1;
????????????????????????????????????????????end
????????????????????????????????????????else
????????????????????????????????????????????begin
????????????????????????????????????????????????state <= s1;
????????????????????????????????????????????????cnt <= 19'd0;
????????????????????????????????????????????????click_n <= 1'b0;
????????????????????????????????????????????end
????????????????????????????????????????end
????????????????????????????????????else
????????????????????????????????????????begin
????????????????????????????????????????????click_n <= 1'b1;
????????????????????????????????????????????cnt <= 19'd0;
????????????????????????????????????????????state <= s0;
????????????????????????????????????????end
????????????????????????????????????end
????????????????????????????s1 : begin
????????????????????????????????????if (key_n == 1'b1)
????????????????????????????????????????begin
????????????????????????????????????????????if (cnt < MASK_TIME - 1)
????????????????????????????????????????????????begin
????????????????????????????????????????????????????cnt <= cnt + 1'b1;
????????????????????????????????????????????????end
????????????????????????????????????????????else
????????????????????????????????????????????????begin
????????????????????????????????????????????????????click_n <= 1'b1;
????????????????????????????????????????????????????state <= s0;
????????????????????????????????????????????????????cnt <= 19'd0;
????????????????????????????????????????????????end
????????????????????????????????????????????end
????????????????????????????????????????else
????????????????????????????????????????????begin
????????????????????????????????????????????????click_n <= 1'b0;
????????????????????????????????????????????????cnt <= 19'd0;
????????????????????????????????????????????????state <= s1;
????????????????????????????????????????????end
????????????????????????????????????????end
????????????????????????????????????default : state <= s0;
????????????????????????????endcase
????????????????????????end
????????????????end
endmodule
激勵代碼如下:
/*
模塊名稱:key_filter_tb
模塊功能:為 key_filter 模塊提供激勵信號
*/
`timescale 1ns/1ps
module key_filter_tb;
????????reg clk;
????????reg rst_n;
????????reg key_n;
????????wire click_n;
????????initial begin?
????????????clk = 1;
????????????key_n = 1;
????????????rst_n = 0;
????????????#200.1
????????????rst_n = 1;
????????????#200
????????????key_n = 0;
????????????#10
????????????key_n = 1;//模仿按鍵按下時的抖動
????????????#20
????????????key_n = 0;
????????????#80
????????????key_n = 1;
????????????#200
????????????key_n = 0;
????????????#400//按下的時間超過濾除抖動的時間
????????????key_n = 1;
????????????#10
????????????key_n = 0;//模仿按鍵抬起時的抖動
????????????#20
????????????key_n = 1;
????????????#80
????????????key_n = 0;
????????????key_n = 1;
????????????#800 $stop;
????????end
????????always #10 clk = ~clk;//本地晶振為 50MHz
????????key_filter
????????????#(
????????????.MASK_TIME(5)//仿真時,將濾除抖動的時間改成 5 個時鐘周期
????????????????)
????????????????key_filter_dut(
????????????????????.clk(clk),
????????????????????.rst_n(rst_n),
????????????????????.key_n(key_n),
????????????????????.click_n(click_n)
????????????????);
endmodule
解析:
模仿按鍵抖動時,抖動的時間(低電平或者高電平的持續(xù)時間)一定不要超過,否則將會被認為按鍵按下或者抬起。模仿按鍵真正按下或者真正抬起時,給予的時間一定要超過抖動(低電平或者高電平的持續(xù)時間)的時間。
仿真波形如下:

本次設計成功地將按鍵按下以及抬起時的抖動濾除。