1. 程式人生 > >FPGA-09-獨立按鍵的消抖(軟體消抖未用狀態機)

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