FPGA按鍵消抖
KEY_S0:判斷按鍵是否按下,如果是,轉移到狀態 KEY_S1;
KEY_S1:10ms 后再次判斷按鍵是否按下,如果是,轉移狀態到 KEY_S2,否則繼續回到 KEY_S0;
KEY_S2:判斷按鍵是否抬起,如果是,轉移狀態到 KEY_S3
KEY_S1:10ms 后再次判斷按鍵是否抬起,如果是,轉移狀態到 KEY_S0,否則繼續回到 KEY_S2;
將按鍵按下到松開,將整個程序,分成了四個部分,也就是四個狀態,狀態機就是狀態轉化,
由于按鍵經常用,消抖也是個非常重要的部分,為消抖寫個模塊,方便后面用,我們起個名字 super_key.
首先是模塊的輸入輸出,
時鐘輸入,按鍵輸出,按鍵狀態輸出
module super_key(
input clk_i,
input key_i,
output key_cap
);
(mark_debug = “true”)這個東西,標識出要探測的信號,觀察波形才會用(到時候再補),
比如
(mark_debug = “true”) reg [1:0] key_s = 2’b0;
(mark_debug = “true”) reg [1:0] key_s_r = 2’b0;
(mark_debug = “true”) wire en_10ms ;
引數別名
parameter CLK_FREQ = 100000000;
parameter CNT_10MS = (CLK_FREQ/100 - 1’b1);
parameter KEY_S0 = 2’d0;
parameter KEY_S1 = 2’d1;
parameter KEY_S2 = 2’d2;
parameter KEY_S3 = 2’d3;
用來計數 reg [24:0] cnt10ms = 25’d0;
連續賦值
assign en_10ms = (cnt10ms == CNT_10MS);
assign key_cap = (key_sKEY_S2)&&(key_s_rKEY_S1); (下面講)
由原理圖知道 按鍵按下為,低電平,
代碼實作
從上面我們就可以看出來,我們沒10ms判斷一下按鍵狀態,從而實作按鍵狀態改變,
第一部分計時10ms,第二部分 狀態改變
第一部分 十毫秒延時
always @(posedge clk_i)begin
if(cnt10ms < CNT_10MS)
cnt10ms <= cnt10ms + 1’b1;
else
cnt10ms <= 25’d0;
end
非常簡單 時鐘上升沿 cnt10ms ++,擠滿置0,
看上面連續賦值陳述句 10ms計時到的時候,en_10ms會置1,
第二部分 狀態改變
always @(posedge clk_i)begin
key_s_r <= key_s;
end
always @(posedge clk_i)begin
if(en_10ms)begin
case(key_s)
KEY_S0:begin
if(!key_i)
key_s <= KEY_S1;
end
KEY_S1:begin
if(!key_i)
key_s <= KEY_S2;
else
key_s <= KEY_S0;
end
KEY_S2:begin
if(key_i)
key_s <= KEY_S3;
end
KEY_S3:begin
if(key_i)
key_s <= KEY_S0;
else
key_s <= KEY_S2;
end
endcase
end
End
10ms捕獲一次按鍵狀態,滿足對應條件,進入下一個狀態,否則回到最初狀態,
總體代碼 :
`timescale 1ns / 1ps
module super_key(
input clk_i,
input key_i,
output key_cap
);
parameter CLK_FREQ = 100000000;
parameter CNT_10MS = (CLK_FREQ/100 - 1’b1);
parameter KEY_S0 = 2’d0;
parameter KEY_S1 = 2’d1;
parameter KEY_S2 = 2’d2;
parameter KEY_S3 = 2’d3;
reg [24:0] cnt10ms = 25’d0;
(mark_debug = “true”) reg [1:0] key_s = 2’b0;
(mark_debug = “true”) reg [1:0] key_s_r = 2’b0;
(mark_debug = “true”) wire en_10ms ;
assign en_10ms = (cnt10ms == CNT_10MS);
assign key_cap = (key_sKEY_S2)&&(key_s_rKEY_S1);
always @(posedge clk_i)begin
if(cnt10ms < CNT_10MS)
cnt10ms <= cnt10ms + 1’b1;
else
cnt10ms <= 25’d0;
end
always @(posedge clk_i)begin
key_s_r <= key_s;
end
always @(posedge clk_i)begin
if(en_10ms)begin
case(key_s)
KEY_S0:begin
if(!key_i)
key_s <= KEY_S1;
end
KEY_S1:begin
if(!key_i)
key_s <= KEY_S2;
else
key_s <= KEY_S0;
end
KEY_S2:begin
if(key_i)
key_s <= KEY_S3;
end
KEY_S3:begin
if(key_i)
key_s <= KEY_S0;
else
key_s <= KEY_S2;
end
endcase
end
end
endmodule
疑問 1:
always @(posedge clk_i)begin
key_s_r <= key_s;
end
有什么用
疑問2:
assign key_cap = (key_sKEY_S2)&&(key_s_rKEY_S1); (下面講)
always @(posedge clk_i)begin
key_s_r <= key_s;
End
key_s_r <= key_s; ,則(key_sKEY_S2)&&(key_s_rKEY_S1) 必為0
疑問1解答:
我們是當按鍵按下到松下,記一次按鍵按下事件,
疑問2解答:
由問題1我們知道按鍵按下事件 是按鍵從按下到松開整個程序,
由代碼我們可以發現key_s是每十毫秒改變一次,key_s發生,是在下個時鐘上升沿才將值賦給key_s_r,
也就是在莫一個時刻 key_s是現態 key_s_r是上一個狀態,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/244220.html
標籤:AI
