一、設(shè)計(jì)需求
設(shè)計(jì)一個(gè)按鍵控制led的功能模塊,即一個(gè)按鍵控制一個(gè)led。隨著每一次按鍵的按下,led就按照亮、滅交替顯示。
二、設(shè)計(jì)思路
本次使用的按鍵為機(jī)械彈性開關(guān)按鍵,但由于機(jī)械觸點(diǎn)的彈性作用,按鍵閉合時(shí)并不能馬上接通,同樣按鍵斷開時(shí)也不能馬上斷開,故在按鍵閉合和斷開的瞬間均伴隨著一連串的抖動(dòng),如圖1所示。而抖動(dòng)的時(shí)間由按鍵的機(jī)械特性決定,一般為5ms~10ms。為了避免由于按鍵抖動(dòng)而引起的誤操作,需要對(duì)按鍵進(jìn)行消抖。
圖1 按鍵抖動(dòng)
按鍵消抖包括硬件消抖和軟件消抖。當(dāng)按鍵數(shù)目較少時(shí),可采用硬件消抖如RS觸發(fā)器,否則將占大面積的PCB;當(dāng)按鍵數(shù)目較多時(shí),采用軟件消抖,利用程序避開按鍵的抖動(dòng)期。
本設(shè)計(jì)采用軟件消抖的方案,即檢測(cè)按鍵是否按下,當(dāng)檢測(cè)到按鍵按下時(shí),延時(shí)10ms,再檢測(cè)按鍵是否真的按下了,若不是真的按下則返回繼續(xù)檢測(cè)按鍵是否按下,若是真的按下了則進(jìn)行按鍵按下處理,接著檢測(cè)按鍵是否松開,當(dāng)檢測(cè)到按鍵松開時(shí),延時(shí)10ms,再檢測(cè)按鍵是否真的松開了,若不是真的松開則返回繼續(xù)檢測(cè)按鍵是否松開,若是真的松開了則進(jìn)行按鍵松開處理,接著再返回檢測(cè)按鍵是否按下,就這樣不斷的判斷按鍵按下與否和松開與否。根據(jù)這種思路,給出按鍵檢測(cè)和消抖流程圖,如圖2所示。
圖2 按鍵檢測(cè)和消抖流程圖
圖3所示為紅色颶風(fēng)E45開發(fā)板上按鍵的電路原理圖。從原理圖可以看出,按鍵按下時(shí)為低電平,按鍵斷開時(shí)為高電平。
圖3 E45中按鍵電路原理圖
圖4所示為本設(shè)計(jì)按鍵控制led的總體框架,由三個(gè)模塊組成,分別為子模塊KEY_Decounce、led_ctrl和頂層模塊key_ctrl_led。這里重點(diǎn)介紹按鍵檢測(cè)和消抖。圖5所示為KEY_Decounce模塊中所用到的按鍵檢測(cè)與消抖狀態(tài)機(jī)。狀態(tài)機(jī)中有四個(gè)狀態(tài),分別為IDLE、JITTER1、DEAL和JITTER2。在IDLE狀態(tài)中檢測(cè)按鍵是否按下,若按下即data!=1則跳轉(zhuǎn)到JITTER1狀態(tài)中延時(shí)10ms進(jìn)行消抖后再判斷按鍵是否真的按下了,若為真即data!=1則跳轉(zhuǎn)到DELA狀態(tài)中進(jìn)行按鍵按下處理,否則即data==1則返回IDLE狀態(tài)中繼續(xù)檢測(cè)按鍵是否按下,在DEAL狀態(tài)中除了按鍵按下處理外還要檢測(cè)按鍵是否松開,若檢測(cè)到按鍵松開即data==1則跳轉(zhuǎn)到JITTER2狀態(tài)中延時(shí)10ms進(jìn)行消抖后再判斷按鍵是否真的松開了,若為真即data==1則跳轉(zhuǎn)到IDLE狀態(tài)繼續(xù)檢測(cè)按鍵是否按下,否則返回DEAL狀態(tài)中繼續(xù)判斷按鍵是否松開。
圖4 按鍵控制led
圖5 按鍵檢測(cè)與消抖狀態(tài)機(jī)
三、設(shè)計(jì)實(shí)現(xiàn)
key_ctrl_led頂層模塊:
/**********************************************版權(quán)申明************************************************* ** 電子技術(shù)應(yīng)用網(wǎng)站, CrazyBird ** **--------------------------------------------文件信息-------------------------------------------------- ** 文件名: key_ctrl_led.v ** 創(chuàng)建者: CrazyBird ** 創(chuàng)建日期: 2015-7-12 ** 版本號(hào): v1.0 ** 功能描述: 頂層模塊將按鍵消抖模塊和led控制模塊連接起來,完成按鍵控制led的功能 ** ********************************************************************************************************/ // synopsys translate_off `timescale 1 ns / 1 ps // synopsys translate_on module key_ctrl_led( rst_n, clk, key_data, led_data ); //****************************************************************************** // 參數(shù)定義 //****************************************************************************** // 修改以下參數(shù)以滿足需求 parameter CLK_CYCLE = 20; // 時(shí)鐘周期,單位ns // 修改以上參數(shù)以滿足需求 //****************************************************************************** // 輸入/輸出端口定義 //****************************************************************************** input rst_n; // 全局復(fù)位信號(hào),低電平有效 input clk; // 全局時(shí)鐘信號(hào),50MHz input key_data; // 鍵值輸入 output led_data; // led狀態(tài) //****************************************************************************** // 變量定義 //****************************************************************************** wire key_flag; //****************************************************************************** // 模塊的連接 //****************************************************************************** // 例化KEY_Debounce模塊 KEY_Debounce #( .CLK_CYCLE(CLK_CYCLE) ) u_KEY_Debounce ( .rst_n ( rst_n ), .clk ( clk ), .key_data ( key_data ), .key_flag ( key_flag ) ); // 例化led_ctrl模塊 led_ctrl u_led_ctrl ( .rst_n ( rst_n ), .clk ( clk ), .led_en ( key_flag ), .led_data ( led_data ) ); //****************************************************************************** endmodule //*********************************************文件結(jié)束*****************************************************
KEY_Debounce模塊:
/**********************************************版權(quán)申明************************************************* ** 電子技術(shù)應(yīng)用網(wǎng)站, CrazyBird ** **--------------------------------------------文件信息-------------------------------------------------- ** 文件名: KEY_Debounce.v ** 創(chuàng)建者: CrazyBird ** 創(chuàng)建日期: 2015-7-12 ** 版本號(hào): v1.0 ** 功能描述: 該模塊主要負(fù)責(zé)完成按鍵的檢測(cè)和消抖 ** ********************************************************************************************************/ // synopsys translate_off `timescale 1 ns / 1 ps // synopsys translate_on module KEY_Debounce( rst_n, clk, key_data, key_flag ); //****************************************************************************** // 參數(shù)定義 //****************************************************************************** // 修改以下參數(shù)以滿足需求 parameter CLK_CYCLE = 20; // 時(shí)鐘周期,單位ns parameter T0 = 10_000_000; // 10ms,按鍵消抖時(shí)間 // parameter T0 = 1000; // 測(cè)試用 parameter DELAY = 19; // 10ms計(jì)數(shù)器位寬 // 修改以上參數(shù)以滿足需求 // 以下參數(shù)不要修改 parameter T0_VAL = (T0/CLK_CYCLE)-1; // 10ms,按鍵消抖時(shí)間 parameter IDLE = 2'b00, JITTER1= 2'b01, DEAL = 2'b10, JITTER2= 2'b11; // 以上參數(shù)不要修改 //****************************************************************************** // 輸入/輸出端口定義 //****************************************************************************** input rst_n; // 全局復(fù)位信號(hào),低電平有效 input clk; // 全局時(shí)鐘信號(hào),50MHz input key_data; // 鍵值輸入 output reg key_flag; // 按鍵按下標(biāo)志位 //****************************************************************************** // 變量定義 //****************************************************************************** wire delay_cnt_done; //****************************************************************************** // 實(shí)現(xiàn)按鍵檢測(cè)和消抖的狀態(tài)機(jī) //****************************************************************************** reg [1:0] state; reg delay_cnt_en; always @(posedge clk or negedge rst_n) begin if(rst_n==1'b0) begin state <= IDLE; delay_cnt_en <= 1'b0; key_flag <= 1'b0; end else begin case(state) IDLE : begin if(key_data!=1'b1) begin state <= JITTER1; delay_cnt_en <= 1'b1; end else state <= IDLE; end JITTER1 : begin if(delay_cnt_done==1'b1) begin delay_cnt_en <= 1'b0; if(key_data!=1'b1) begin state <= DEAL; key_flag <= 1'b1; end else state <= IDLE; end else state <= JITTER1; end DEAL : begin key_flag <= 1'b0; if(key_data==1'b1) begin state <= JITTER2; delay_cnt_en <= 1'b1; end else state <= DEAL; end JITTER2 : begin if(delay_cnt_done==1'b1) begin delay_cnt_en <= 1'b0; if(key_data==1'b1) state <= IDLE; else state <= DEAL; end else state <= JITTER2; end endcase end end //****************************************************************************** // 計(jì)數(shù)器的實(shí)現(xiàn) //****************************************************************************** reg [DELAY-1:0] delay_cnt; always @(posedge clk or negedge rst_n) begin if(rst_n==1'b0) delay_cnt <= {(DELAY){1'b0}}; else if(delay_cnt_en==1'b1) begin if(delay_cnt_done==1'b1) delay_cnt <= {(DELAY){1'b0}}; else delay_cnt <= delay_cnt + 1'b1; end else delay_cnt <= {(DELAY){1'b0}}; end assign delay_cnt_done = (delay_cnt==T0_VAL); //****************************************************************************** endmodule //*********************************************文件結(jié)束*****************************************************
led_ctrl模塊:
/**********************************************版權(quán)申明************************************************* ** **--------------------------------------------文件信息-------------------------------------------------- ** 文件名: led_ctrl.v ** 創(chuàng)建者: CrazyBird ** 創(chuàng)建日期: 2015-7-12 ** 版本號(hào): v1.0 ** 功能描述: 該模塊根據(jù)按鍵每次按下時(shí)將led的狀態(tài)取反 ** ********************************************************************************************************/ // synopsys translate_off `timescale 1 ns / 1 ps // synopsys translate_on module led_ctrl( rst_n, clk, led_en, led_data ); //****************************************************************************** // 輸入/輸出端口定義 //****************************************************************************** input rst_n; // 全局復(fù)位信號(hào),低電平有效 input clk; // 全局時(shí)鐘信號(hào),50MHz input led_en; // led狀態(tài)取反使能信號(hào) output reg led_data; // led狀態(tài) //****************************************************************************** // led狀態(tài)控制 //****************************************************************************** always @(posedge clk or negedge rst_n) begin if(rst_n==1'b0) led_data <= 1'b0; else if(led_en==1'b1) led_data <= ~led_data; else led_data <= led_data; end //****************************************************************************** endmodule //*********************************************文件結(jié)束*****************************************************
modelsim仿真結(jié)果:
從仿真結(jié)果看,本設(shè)計(jì)已實(shí)現(xiàn)了按鍵控制led的功能,同時(shí)也達(dá)到了按鍵消抖的效果。
最后對(duì)設(shè)計(jì)進(jìn)行綜合、布局布線、生成bit流文件、下載在紅色颶風(fēng)板子上,然后通過控制led燈的亮與滅。