FPGA-09-獨立按鍵的消抖(軟體消抖未用狀態機)
獨立按鍵消抖在微控制器和FPGA中都是個不可避免的問題,首先,解釋一下什麼叫做按鍵抖動,如圖,按鍵在按下和鬆開的那個瞬間存在大概20ms的機械抖動:
下面就是本篇的第一個重點 —— 什麼時候需要按鍵消抖設計?如果是像復位按鍵這樣,短時間內可以多次觸發,就完全不需要設計消抖,但是如果是要設計按下按鍵使LED狀態翻轉,或者按下按鍵計數一次的話,就必須要設計消抖模組,否則就會帶來不可預知的錯誤,因為在按下按鍵的那個時刻,可能已經觸發了少則幾次,多則幾十次,可見按鍵消抖的必要性;
那麼,既然按鍵消抖如此重要,如何來進行消抖呢?
1、硬體消抖 —— 0.1uF電容濾波
這個104的電容就是起高頻濾波的作用,在按鍵不是很多的情況下,可以使用這種設計,但是如果要做專案,會增加大量成本,所以接下來我們講述如何進行軟體消抖;
2、軟體消抖 —— delay
if(key_in == 0)
{
deley(2000);
if(key_in == 0)
{
//按鍵按下,執行相應操作
}
}
在微控制器中用C語言,可以這樣設計按鍵消抖,同樣的思路,在FPGA中,我們依然可以採用這種思想,將按鍵的這20ms抖動“遮蔽”,但是FPGA沒有delay(2000),該如何設計呢?
FPGA中控制延時可以採用計數器,因為工作時鐘是已知的50M,所以要延時20_000_000ns(20ms),只需要對計數1_000_000個clk就可以,這樣延時問題就解決了,按照之前的思路,設計如下:只需要在檢測到key_in變為0,啟動定時器,定時器時間到,再次檢測key_in是否為0,若為0,表明按鍵按下穩定,關閉計數器並清零,然後等待按鍵釋放,也就是key_in出現上升沿,再次啟動定時器,時間到後檢測key_in,若為1,則證明按鍵已釋放,一次完整的按鍵過程結束
module keys(ext_clk_25m,ext_rst_n,led,key_left,key_righ,key_upup,key_down,key_entr
);
input ext_clk_25m;
input ext_rst_n;
input key_down,key_entr,key_left,key_righ,key_upup;
output reg [7:0]led;
抖動判斷邏輯
這裡用4位是為了和取樣頻率和基準時鐘一致
//按鍵抖動判斷邏輯
wire key; //所有的按鍵相與的結果,用於按鍵觸發判斷
reg[3:0]keyr ; //按鍵值key的緩衝暫存器
assign key =key_down & key_entr&key_left&key_righ&key_upup;
[email protected](posedge ext_clk_25m or negedge ext_rst_n)
begin
if(!ext_rst_n)
keyr <=4'b1111;
else
keyr <={keyr[2:0],key};
end
wire key_neg =~keyr[2] &keyr [3];//有按鍵被按下
wire key_pos =keyr[2] &~keyr [3];// 有按鍵被釋放
設定一個計數器定時20ms(這裡是40ms)
//定時器計數邏輯,用於對按鍵的消抖的判斷
reg [19:0] cnt;
[email protected](posedge ext_clk_25m or negedge ext_rst_n)
begin
if(!ext_rst_n)
cnt <=20'd0;
else if(key_pos||key_neg)
cnt <=20'd0;
else if(cnt <20'd999_999)
cnt <= cnt +1'b1;
else
cnt <=20'd0;
end
採集按鍵值
//定時採取按鍵值
[email protected](posedge ext_clk_25m or negedge ext_rst_n)
begin
if(!ext_rst_n)
begin
key_value[0] <=5'b11111;
key_value[1] <=5'b11111;
end
else begin
key_value[1] <=key_value[0];
if(cnt ==20'd999_999)
key_value[0] <={key_left,key_righ,key_upup,key_down,key_entr};
else ;
end
end
wire [4:0]key_press =key_value[1] & ~key_value[0];
控制LED
//LED切換控制
[email protected](posedge ext_clk_25m or negedge ext_rst_n)
begin
if(!ext_rst_n)
led <=8'hff;
else if(key_press[0])
led[0] <=~led[0];
else if(key_press[1])
led[1] <=~led[1];
else if(key_press[2])
led[2] <=~led[2];
else if(key_press[3])
led[3] <=~led[3];
else if(key_press[4])
led[4] <=~led[4];
else ;
end
endmodule