一.簡(jiǎn)介
這是FPGA之旅的第二個(gè)設(shè)計(jì)實(shí)例了,按鍵在項(xiàng)目中的作用是非常大的,使用的很頻繁,本例將帶大家設(shè)計(jì)一個(gè)實(shí)用的按鍵模塊。
二. 按鍵電路
按鍵為輸入設(shè)備,通過電路圖可以知道,當(dāng)按鍵按下的時(shí)候,F(xiàn)PGA會(huì)檢測(cè)到低電平,按鍵沒有按下的時(shí)候,F(xiàn)PGA檢測(cè)到的是高電平。
三. Verilog代碼編寫
直接來一段最簡(jiǎn)單的按鍵檢測(cè)的代碼編寫,都不用仿真。
按鍵按下,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)取反,這個(gè)在仿真的時(shí)候是可以看到變化的,但是實(shí)際上板測(cè)試的話,是沒有效果的,因?yàn)閏lk的時(shí)鐘周期一般為20ns,每次按鍵按下的持續(xù)時(shí)間可以達(dá)到ms以上,所以LED會(huì)多次取反,所以這么簡(jiǎn)單粗暴是不可以的,需要我們做一些額外處理。此外在按鍵按下的瞬間,電平會(huì)出現(xiàn)不穩(wěn)定的情況,也需要進(jìn)行處理。解決這些問題,正是這個(gè)例程的重點(diǎn)。
四. 解決方案設(shè)計(jì)
按鍵按下的時(shí)候,一共有兩個(gè)問題
電平不穩(wěn)定
短時(shí)間內(nèi)重復(fù)檢測(cè)
第一個(gè)問題可以通過按鍵消抖來解決,第二個(gè)問題,可以在按鍵消抖的基礎(chǔ)上,增加一些判斷來解決,于是就有了以下三種模式
模式一,按下生效,釋放,算一次
模式二,按下,釋放生效,算一次
模式三,按下,一段時(shí)間算一次
這里通過狀態(tài)機(jī)的方式來實(shí)現(xiàn),第一步就是要分析一共有幾個(gè)狀態(tài)。
空閑態(tài):按鍵沒有按下時(shí),所處的狀態(tài)。
消抖態(tài): 按鍵按下后,進(jìn)入消抖態(tài),在此期間,如果按鍵釋放了的話,回到空閑態(tài),否則進(jìn)入延時(shí)態(tài)。
延時(shí)態(tài):延時(shí),直到按鍵釋放。
釋放態(tài):按鍵釋放,回歸到空閑態(tài)。
模式一,可以在消抖態(tài)完成后,生效。
模式二,可以在釋放態(tài),生效。
模式三,可以在延時(shí)態(tài),生效。
完美,這不就全部都解決了嘛! 代碼如下。
//按鍵消抖module btn_dis_shake( input clk, input rst_n, input ikey, //按鍵輸入outputokey//按鍵輸出);//模式//0 按下生效,抬起,算一次//1 按下抬起,算一次//2 按下后,一段時(shí)間算一次parameter mode = 2; localparam S_IDLE = 'd0;localparam S_DIS_SHAKE = 'd1;localparam S_DEALY = 'd2;localparam S_UP = 'd3; localparam DIS_SHAKE = 'd6000; //消抖延時(shí)localparam DELAY = 'd50000; //模式2中,一段時(shí)間 reg[3:0] state , next_state; wire neg_key,pos_key; //按鍵下降沿上升沿reg key0,key1; //按鍵狀態(tài)儲(chǔ)存 reg[30:0] delay_cnt; assign neg_key = key1 & (~key0); //判斷按鍵信號(hào)的下降沿assignpos_key=(~key1)&key0;//判斷按鍵信號(hào)的上升沿//根據(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: //延時(shí) 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í)計(jì)數(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
代碼是寫完了,對(duì)不對(duì)呢 ? 上仿真?。?!仿真的時(shí)候別忘記了將DIS_SHAKE這個(gè)參數(shù)調(diào)小一點(diǎn)了,可以設(shè)置為2就可以了,否則,你可以試試哦,就只對(duì)模式一進(jìn)行仿真,其他的模式,也可以自行嘗試喔!
`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)?。。⊥昝缹?duì)應(yīng)起來,測(cè)試通過!
-
FPGA
+關(guān)注
關(guān)注
1630文章
21759瀏覽量
604291 -
模塊
+關(guān)注
關(guān)注
7文章
2721瀏覽量
47566 -
led燈
+關(guān)注
關(guān)注
22文章
1592瀏覽量
108112 -
代碼
+關(guān)注
關(guān)注
30文章
4802瀏覽量
68743
原文標(biāo)題:FPGA實(shí)現(xiàn)按鍵模塊
文章出處:【微信號(hào):zhuyandz,微信公眾號(hào):FPGA之家】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論