由于最近论坛课程安排时间比较久,就去看了一些FPGA大神们的文章,最近看了一位大神的关于按键消抖的文章,很受益,就自己写了个工程来加深对按键消抖的理解,由于代码比较简单就没有写testbench,如有谬误,恭请指正。
`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: Charles Wang // // Create Date: 10/27/2014 // Design Name: keyinput // Module Name: keyinput // Project Name: keyinput // Target Devices: EP4CE6E22C8 // Tool versions: Quartus II 12.0 // Description: 根据按键的单击与长击,分别点亮一个Led // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// module keyinput(key,sys_clk,sys_rst_n,led); input key;//按键输入 input sys_clk;// input sys_rst_n;//异步复位,低电平有效 output [1:0]led;//LED 输出驱动 reg [27:0]cnt; reg rst_n_r1; reg rst_n_r2; reg P1,P2; wire isH2L; wire isL2H; parameter T50MS= 28'd2_500_000, T5S = 28'd250_000_000; ////////////////////////////////////////////////////////////////////////////////// //将sys_rst_n 同步化 always@(posedge sys_clk) begin {rst_n_r2,rst_n_r1} <= {rst_n_r1,sys_rst_n}; end ////////////////////////////////////////////////////////////////////////////////// //用P2,P1分别保存第一和第二个时钟的按键值 always@(posedge sys_clk or negedge rst_n_r2) begin if(!rst_n_r2) begin {P2,P1} <= 2'b11; end else begin {P2,P1} <= {P1,key}; end end assign isH2L = (P2 == 1'b1) && (P1 == 1'b0); assign isL2H = (P2 == 1'b0) && (P1 == 1'b1); reg [3:0]i; reg isLClick;//用isLClick 作为长按标志,isSClick 作为单击 reg isSClick; reg [1:0]flag; ////////////////////////////////////////////////////////////////////////////////// always@(posedge sys_clk or negedge rst_n_r2) begin if(!rst_n_r2) begin i <= 4'd0; isLClick <= 1'b0; isSClick <= 1'b0; flag <= 2'd0; cnt <= 28'd0; end else case(i) 4'd0: //等待按键按下 if(isH2L) begin i <= i + 1'b1; end 4'd1://按下后消抖 if(cnt == T50MS - 1'b1) begin cnt <= 28'd0; i <= i + 1'b1; end else cnt <= cnt + 1'b1; 4'd2://判断是否是长按 if({P2,P1} == 2'b00 && cnt >= T5S - 1'b1) begin cnt <= 28'd0; i <= i + 1'b1; flag <= 2'd1; end else if(isL2H) begin cnt <= 28'd0; i <= i + 1'b1; flag <= 2'd2; end else cnt <= cnt + 1'b1; 4'd3://步骤3和4是为了产生一组高脉冲isLClick,isSClick if(flag == 2'd1) begin isLClick <= 1'b1; i <= i + 1'b1; end else if(flag == 2'd2) begin isSClick <= 1'b1; i <= i + 1'b1; end 4'd4: begin isLClick <= 1'b0; isSClick <= 1'b0; i <= i + 1'b1; end 4'd5://等待按键释放 if(isL2H) begin i <= i + 'b1; end 4'd6://释放后消抖 if(cnt == T50MS - 1'b1) begin cnt <= 28'd0; i <= 4'd0; flag<= 2'd0; end else cnt <= cnt + 1'b1; default: i <= 4'd0; endcase end ////////////////////////////////////////////////////////////////////////////////// //让led2,led1 根据isLClick,isSClick高脉冲不停的反转 reg led1,led2; always@(posedge sys_clk or negedge rst_n_r2) begin if(!rst_n_r2) begin {led2,led1} <= 2'b11; end else if(isSClick) begin led1 <= ~led1; end else if(isLClick) begin led2 <= ~led2; end end assign led = {led2,led1};//使用led1,led2驱动led endmodule
现象如下链接:
http://v.youku.com/v_show/id_XODEyODcxOTEy.html