Verilog——FPGA按键去抖操作
目标
- Verilog编程语言,实现按键去抖。
- 模块:key_delay,模块可以输入按键去抖延迟时间参数。
- 输入:时钟、复位、按键信号 key_in
- 输出:去抖后的按键信号 key_out
代码
- 实现代码
module key_delay #( parameter FREQ = 200 ,//MHz, 晶振频率 parameter DLY_TIME = 20_000 //us, 按键延迟时间 ) ( input sys_clk_p , input sys_clk_n , input rst_n , input key_in , output reg key_out ); localparam MAX_TIME = FREQ * DLY_TIME;//延时时间对应计数值 wire clk200M ; reg [31:0] cnt ; wire max_flag ;//计数器达到最大值 reg key_in_r1 ;//按键key_in节拍 reg key_in_r2 ; wire key_act ;//按键动作标志 IBUFDS #( .DIFF_TERM ("FALSE" ),// Differential Termination .IBUF_LOW_PWR ("TRUE" ),// Low power="TRUE", Highest performance="FALSE" .IOSTANDARD ("DEFAULT" ) // Specify the input I/O standard ) IBUFDS_inst ( .O (clk200M ),// Buffer output .I (sys_clk_p ),// Diff_p buffer input (connect directly to top-level port) .IB (sys_clk_n ) // Diff_n buffer input (connect directly to top-level port) ); //key_in_r1, key_in_r1 always @(posedge clk200M) begin key_in_r1 <= key_in; key_in_r2 <= key_in_r1; end //key_act, 按键有动作 assign key_act = key_in_r1 ^ key_in_r2; //max_flag, 计数达到最大值 assign max_flag = (cnt == MAX_TIME) ? 1'b1 : 1'b0; //cnt always @(posedge clk200M) begin case({key_act, max_flag}) 2'b00://按键无动作, 且计数未达到最大值 cnt <= cnt + 'd1; 2'b01://按键无动作, 且计数达到最大值 cnt <= cnt; default://按键有动作 cnt <= 'd0; endcase end //key_out always @(posedge clk200M or negedge rst_n) begin if(~rst_n) key_out <= key_in_r2; else if(cnt == MAX_TIME) key_out <= key_in_r2; else key_out <= key_out; end endmodule
- 仿真代码
`timescale 1ns / 1ps module tb_key_delay; reg sys_clk_p; wire sys_clk_n; reg rst_n; reg key_in; wire key_out; //----------------------------------------------- integer i; key_delay #( .FREQ (200 ),//MHz, 晶振频率 .DLY_TIME (1 ) //us, 按键延迟时间 ) inst_key_delay ( .sys_clk_p (sys_clk_p ), .sys_clk_n (sys_clk_n ), .rst_n (rst_n ), .key_in (key_in ), .key_out (key_out ) ); initial begin sys_clk_p = 0; rst_n = 0; key_in = 0; #100; rst_n = 1; #100; for(i = 0; i <= 10; i = i + 1) begin key_in = ~key_in; #30; end #1500; for(i = 0; i <= 10; i = i + 1) begin key_in = ~key_in; #30; end #1500; for(i = 0; i <= 10; i = i + 1) begin key_in = ~key_in; #30; end end //时钟 always #2.5 sys_clk_p = ~sys_clk_p; assign sys_clk_n = ~sys_clk_p; endmodule
- 仿真结果
- VIVADO下的XDC文件代码
#LOCATION set_property PACKAGE_PIN C8 [get_ports sys_clk_p] set_property PACKAGE_PIN AF15 [get_ports rst_n] set_property PACKAGE_PIN AF14 [get_ports key_in] set_property PACKAGE_PIN AB15 [get_ports key_out] #IOSTANDARD set_property IOSTANDARD LVCMOS33 [get_ports key_in] set_property IOSTANDARD LVCMOS33 [get_ports key_out] set_property IOSTANDARD LVCMOS33 [get_ports rst_n] set_property IOSTANDARD DIFF_SSTL15 [get_ports sys_clk_p] #TIME CONSTRAINT create_clock -period 5.000 -waveform {0.000 2.500} [get_ports sys_clk_p] #IOB