【FPGA】【verilog】【基础模块】按键消抖

方案1[参考自小梅的《FPGA自学笔记》]:

module key_filter(clk,rst_n,key_in,key_flag,key_state);
	input clk;
	input rst_n;
	input key_in;
	output reg key_flag;
	output reg key_state;
	
	//----synchronize the key signal 
	reg key_in_a,key_in_b;
	always @(posedge clk or negedge rst_n)	begin 
		if (!rst_n) begin
			key_in_a <= 1'b0;
			key_in_b <= 1'b0;
		end 
		else begin 
			key_in_a <= key_in;
			key_in_b <= key_in_a;
		end 
	end 
	//------------------------------------
	
	//-------posedge detection && negedge detection-----------
	reg key_tempa,key_tempb;
	wire key_posedge,key_negedge;
	always@(posedge clk or negedge rst_n) begin 
		if (!rst_n)	begin 
			key_tempa <= 0;
			key_tempb <= 0;
		end 
		else begin 
			key_tempa <= key_in_a;
			key_tempb <= key_in_b;
		end 
	end 
	
	assign key_posedge = key_tempa		& (!key_tempb);
	assign key_negedge = (!key_tempa)	&	key_tempb;
		

	
	//-----------------counter-----------------------------
	reg [19:0] cnt;
	reg en_cnt;
	reg cnt_full;
	//------counter_enable-------
	always @(posedge clk or negedge rst_n) begin
		if(!rst_n)
			cnt <= 20'b0;
		else if (en_cnt)
			cnt <= cnt + 1'b1;
		else if (cnt_full == 1'b1)
			cnt <= 20'b0;
		else 
			cnt <= 20'b0;
	end 
	
	//------counter_upperlimit
	always @(posedge clk or negedge rst_n) begin 
		if (!rst_n)
			cnt_full <= 1'b0;
		else if (cnt == 20'd999_999)
			cnt_full <= 1'b1;
		else 
			cnt_full <= 1'b0;
	end 
	
	
	//----------------------------------------------------
	
	
	//------------state machine for key debounce
	localparam
		IDLE		=	4'b0001,
		FILTER1	=	4'b0010,
		DOWN		=	4'b0100,
		FILTER2	=	4'b1000;
		
	reg [3:0] state;
	always@(posedge clk or negedge rst_n)
	if(!rst_n) begin 
		en_cnt	<=	1'b0;
		state		<=	IDLE;
		key_flag	<= 1'b0;
		key_state<=	1'b1;
	end 
	else begin 
		case(state)
			IDLE:	begin
						key_flag	<= 1'b0;
						if(key_negedge) begin 
							state 	<= FILTER1;
							en_cnt	<= 1'b1;
						end
						else 
							state		<= IDLE;
					end
			
			FILTER1:	begin 
							if(cnt_full) begin
								key_flag		<=	1'b1;
								key_state	<=	1'b0;
								en_cnt		<= 1'b0;
								state			<= DOWN;
							end
							else if(key_posedge)	begin
								state		<=	IDLE;
								en_cnt	<=	1'b0;
							end
							else 
								state		<=	FILTER1;
						end 
			
			DOWN:		begin
							key_flag		<=	1'b0;
							if(key_posedge)	begin
								state		<=	FILTER2;
								en_cnt	<=	1'b1;
							end 
							else 
								state		<= DOWN;
						end
						
			FILTER2:	begin
							if(cnt_full)	begin
								key_flag	<=	1'b1;
								key_state<=	1'b1;
								state		<=	IDLE;
								en_cnt	<=	1'b0;
							end 
							else if(key_negedge)	begin
								en_cnt	<=	1'b0;
								state		<=	DOWN;
							end 
							else 
								state		<=	FILTER2;
						end 
						
			default:	begin
							state		<=	IDLE;
							en_cnt	<=	1'b0;
							key_flag	<=	1'b0;
							key_state<=	1'b1;
						
						end 
		endcase 
	end 
	
	//-------------------------------------------
	
endmodule 

    testbench:    

key_filter_tb.v

`timescale 1 ns /1 ns
`define clk_period 20

module key_filter_tb;
	reg clk;
	reg rst_n;
	wire key_in;
	wire key_flag;
	wire key_state;
	//-----------------------
	key_filter 	u2(clk,rst_n,key_in,key_flag,key_state);
	
	key_model 	u3(.key_in(key_in));
	//----------------------
	
	
	initial clk = 1'b1;
	initial #(`clk_period *5) rst_n = 1'b0;
	initial #(`clk_period *5) rst_n = 1'b1;
	
	always #(`clk_period/2) clk = ~clk;
	

endmodule 
key_model.v

    

`timescale 1 ns /1 ns 
`define clk_period 20
module key_model(key_in);
	output reg key_in;
	reg [15:0]	myrandom;

	initial #(`clk_period *5) key_in = 1'b1;
	
	task press_key;
		begin
			repeat(50) begin 
			myrandom = {$random}%65535;
			#myrandom key_in = ~key_in;
			end
			
			key_in = 1'b0;
			#(2*20'd999_999*`clk_period);
		
			repeat(50) begin 
			myrandom = {$random}%65535;
			#myrandom key_in = ~key_in;
			end
			
			key_in = 1'b1;
			#(2*20'd999_999*`clk_period);
		end 
	endtask
	//----------------------------
		
	initial begin 
		
		repeat(1) begin 
		press_key;
		end
		
		#(`clk_period*100);
		$stop;
	end 
	
	//----------------------

endmodule


波形:

【FPGA】【verilog】【基础模块】按键消抖_第1张图片

你可能感兴趣的:(FPGA学习,基础模块)