一.簡介
這是FPGA之旅的第二個設計實例了,按鍵在項目中的作用是非常大的,使用的很頻繁,本例將帶大家設計一個實用的按鍵模塊。
二. 按鍵電路
按鍵為輸入設備,通過電路圖可以知道,當按鍵按下的時候,FPGA會檢測到低電平,按鍵沒有按下的時候,FPGA檢測到的是高電平。
三. Verilog代碼編寫
直接來一段最簡單的按鍵檢測的代碼編寫,都不用仿真。
按鍵按下,LED燈狀態取反。
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
當按鍵按下后,LED的狀態取反,這個在仿真的時候是可以看到變化的,但是實際上板測試的話,是沒有效果的,因為clk的時鐘周期一般為20ns,每次按鍵按下的持續時間可以達到ms以上,所以LED會多次取反,所以這么簡單粗暴是不可以的,需要我們做一些額外處理。此外在按鍵按下的瞬間,電平會出現不穩定的情況,也需要進行處理。解決這些問題,正是這個例程的重點。
四. 解決方案設計
按鍵按下的時候,一共有兩個問題
電平不穩定
短時間內重復檢測
第一個問題可以通過按鍵消抖來解決,第二個問題,可以在按鍵消抖的基礎上,增加一些判斷來解決,于是就有了以下三種模式
模式一,按下生效,釋放,算一次
模式二,按下,釋放生效,算一次
模式三,按下,一段時間算一次
這里通過狀態機的方式來實現,第一步就是要分析一共有幾個狀態。
空閑態:按鍵沒有按下時,所處的狀態。
消抖態: 按鍵按下后,進入消抖態,在此期間,如果按鍵釋放了的話,回到空閑態,否則進入延時態。
延時態:延時,直到按鍵釋放。
釋放態:按鍵釋放,回歸到空閑態。
模式一,可以在消抖態完成后,生效。
模式二,可以在釋放態,生效。
模式三,可以在延時態,生效。
完美,這不就全部都解決了嘛! 代碼如下。
//按鍵消抖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; //按鍵狀態儲存 reg[30:0] delay_cnt; assign neg_key = key1 & (~key0); //判斷按鍵信號的下降沿assignpos_key=(~key1)&key0;//判斷按鍵信號的上升沿//根據模式來判斷按鍵輸出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 //延時計數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這個參數調小一點了,可以設置為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
當當當當!!!完美對應起來,測試通過!
-
FPGA
+關注
關注
1629文章
21748瀏覽量
603956 -
模塊
+關注
關注
7文章
2716瀏覽量
47536 -
led燈
+關注
關注
22文章
1592瀏覽量
108072 -
代碼
+關注
關注
30文章
4791瀏覽量
68699
原文標題:FPGA實現按鍵模塊
文章出處:【微信號:zhuyandz,微信公眾號:FPGA之家】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論