一.簡介
這是FPGA之旅的第二個設(shè)計實例了,按鍵在項目中的作用是非常大的,使用的很頻繁,本例將帶大家設(shè)計一個實用的按鍵模塊。
二. 按鍵電路
按鍵為輸入設(shè)備,通過電路圖可以知道,當(dāng)按鍵按下的時候,F(xiàn)PGA會檢測到低電平,按鍵沒有按下的時候,F(xiàn)PGA檢測到的是高電平。
三. Verilog代碼編寫
直接來一段最簡單的按鍵檢測的代碼編寫,都不用仿真。
按鍵按下,LED燈狀態(tài)取反。
module KEY( input clk, input rst_n, input key, output reg led); always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) led <= 1'b0; else if(key == 1'b0) led <= ~led; else led <= led; endendmodule
當(dāng)按鍵按下后,LED的狀態(tài)取反,這個在仿真的時候是可以看到變化的,但是實際上板測試的話,是沒有效果的,因為clk的時鐘周期一般為20ns,每次按鍵按下的持續(xù)時間可以達到ms以上,所以LED會多次取反,所以這么簡單粗暴是不可以的,需要我們做一些額外處理。此外在按鍵按下的瞬間,電平會出現(xiàn)不穩(wěn)定的情況,也需要進行處理。解決這些問題,正是這個例程的重點。
四. 解決方案設(shè)計
按鍵按下的時候,一共有兩個問題
電平不穩(wěn)定
短時間內(nèi)重復(fù)檢測
第一個問題可以通過按鍵消抖來解決,第二個問題,可以在按鍵消抖的基礎(chǔ)上,增加一些判斷來解決,于是就有了以下三種模式
模式一,按下生效,釋放,算一次
模式二,按下,釋放生效,算一次
模式三,按下,一段時間算一次
這里通過狀態(tài)機的方式來實現(xiàn),第一步就是要分析一共有幾個狀態(tài)。
空閑態(tài):按鍵沒有按下時,所處的狀態(tài)。
消抖態(tài): 按鍵按下后,進入消抖態(tài),在此期間,如果按鍵釋放了的話,回到空閑態(tài),否則進入延時態(tài)。
延時態(tài):延時,直到按鍵釋放。
釋放態(tài):按鍵釋放,回歸到空閑態(tài)。
模式一,可以在消抖態(tài)完成后,生效。
模式二,可以在釋放態(tài),生效。
模式三,可以在延時態(tài),生效。
完美,這不就全部都解決了嘛! 代碼如下。
//按鍵消抖module btn_dis_shake( input clk, input rst_n, input ikey, //按鍵輸入outputokey//按鍵輸出);//模式//0 按下生效,抬起,算一次//1 按下抬起,算一次//2 按下后,一段時間算一次parameter mode = 2; localparam S_IDLE = 'd0;localparam S_DIS_SHAKE = 'd1;localparam S_DEALY = 'd2;localparam S_UP = 'd3; localparam DIS_SHAKE = 'd6000; //消抖延時localparam DELAY = 'd50000; //模式2中,一段時間 reg[3:0] state , next_state; wire neg_key,pos_key; //按鍵下降沿上升沿reg key0,key1; //按鍵狀態(tài)儲存 reg[30:0] delay_cnt; assign neg_key = key1 & (~key0); //判斷按鍵信號的下降沿assignpos_key=(~key1)&key0;//判斷按鍵信號的上升沿//根據(jù)模式來判斷按鍵輸出assignokey=(mode==0&&state==S_DIS_SHAKE&&delay_cnt==DIS_SHAKE)?1'b1:(mode==1&&state==S_UP)?1'b1:(mode==2&&state==S_DEALY&&delay_cnt==DELAY)?1'b1:1'b0;always@(posedge clk or negedge rst_n)begin if(rst_n == 1'b0) begin key0 <= 1'b1; key1 <= 1'b1; end else begin key0 <= ikey; key1 <= key0; endendalways@(posedge clk or negedge rst_n)begin if(rst_n == 1'b0) state <= S_IDLE; else state <= next_state;end always@(*)begin case(state) S_IDLE: if(neg_key == 1'b1) next_state <= S_DIS_SHAKE; else next_state <= S_IDLE; S_DIS_SHAKE: //按下消抖 if(delay_cnt == DIS_SHAKE) next_state <= S_DEALY; else if(pos_key == 1'b1) next_state <= S_IDLE; else next_state <= S_DIS_SHAKE; S_DEALY: //延時 if(delay_cnt == DELAY && pos_key == 1'b1) next_state <= S_UP; else if( pos_key == 1'b1) next_state <= S_UP; else next_state <= S_DEALY; S_UP: next_state <= S_IDLE; default: next_state <= S_IDLE; endcaseend //延時計數(shù)always@(posedge clk or negedge rst_n)begin if(rst_n == 1'b0) delay_cnt <= 'd0; else if(state != next_state) delay_cnt <= 'd0; else if(state == S_DIS_SHAKE) delay_cnt <= delay_cnt + 1'b1; else if(state == S_DEALY && delay_cnt == DELAY) delay_cnt <= 'd0; else if(state == S_DEALY) delay_cnt <= delay_cnt + 1'b1; else delay_cnt <= 'd0;end endmodule
代碼是寫完了,對不對呢 ? 上仿真!!!仿真的時候別忘記了將DIS_SHAKE這個參數(shù)調(diào)小一點了,可以設(shè)置為2就可以了,否則,你可以試試哦,就只對模式一進行仿真,其他的模式,也可以自行嘗試喔!
`timescale 1ns/1psmodule testbeach(); reg clk; reg rst_n; reg ikey; wire okey; always#50clk<=?~clk;?????initial?begin clk = 1'b0; rst_n = 1'b1; ikey = 1'b1; #100 rst_n = 1'b0; #100 rst_n = 1'b1; ikey = 1'b0; //按下 #400 ikey = 1'b1; //釋放 #200 ikey = 1'b0; //按下 #600????????ikey?=?1'b1;??//釋放 end btn_dis_shake #(.mode(0))btn_dis_shakeHP( .clk (clk), .rst_n (rst_n), .ikey (ikey), //按鍵輸入 .okey (okey) //按鍵輸出); endmodule
當(dāng)當(dāng)當(dāng)當(dāng)!!!完美對應(yīng)起來,測試通過!
-
FPGA
+關(guān)注
關(guān)注
1642文章
21920瀏覽量
612006 -
模塊
+關(guān)注
關(guān)注
7文章
2771瀏覽量
49053 -
led燈
+關(guān)注
關(guān)注
22文章
1593瀏覽量
109172 -
代碼
+關(guān)注
關(guān)注
30文章
4880瀏覽量
70000
原文標題:FPGA實現(xiàn)按鍵模塊
文章出處:【微信號:zhuyandz,微信公眾號:FPGA之家】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
介紹一個事件驅(qū)動型按鍵驅(qū)動模塊MultiButton
【BPI-Pico-RP2040 開發(fā)板】+GPIO口的使用
標記的用法,用一個按鍵控制1個LED燈的亮滅,按鍵去抖

使用51單片機和nRF24L01無線模塊用4個不同的按鍵控制點亮4個不同的燈

單片機獨立按鍵模塊(含短按,長按,連發(fā)功能)

評論