Digital IC design study notes_button debounce module 2

Digital IC design study notes

Key debounce module 2

1 原理图
2 Verilog 代码
3 Modelsim仿真

1. Schematic

Insert picture description here
Experimental phenomenon:
Each time the button 0 is pressed, the display status of the 4 LEDs is increased by 1 in the binary addition format; each time the button 1 is pressed, the display status of the 4 LEDs is subtracted by 1 in the binary addition format.

2 Verilog code

//----top module---------------------------------
module fsm_key_filter_top(
	input clk,
	input rst_n,
	input key0,
	input key1,
	output [3:0] led
);
	wire key_flag0;
	wire key_flag1;
	wire key_state0;
	wire key_state1;
	
	led_ctrl uut_ctrl(
			.clk(clk),
			.rst_n(rst_n),
			.key_flag0(key_flag0),
			.key_state0(key_state0),
			.key_flag1(key_flag1),
			.key_state1(key_state1),
			
			.led(led)
	);
	
	fsm_key_filter uut_filter0(
			.clk(clk),
			.rst_n(rst_n),
			.key(key0),
			.key_state(key_state0),
			.key_flag(key_flag0)
);
	fsm_key_filter uut_filter1(
			.clk(clk),
			.rst_n(rst_n),
			.key(key1),
			.key_state(key_state1),
			.key_flag(key_flag1)
);

endmodule
//---------------------------------
//----抖动滤除模块------------------
module fsm_key_filter#(
	parameter IDLE = 4'b0001,
	parameter FILTER1 = 4'b0010,
	parameter DOWN = 4'b0100,
	parameter FILTER2 = 4'b1000
)
(
	input clk, //50MHz 20us
	input rst_n,
	input key,
	
	output  key_flag,
	output reg  key_state
);
	reg		cnt_en;
	reg		cnt_full;
	reg [19:0] cnt1;
	//reg [19:0] cnt2;
	reg [3:0] state;
	reg		key_syn1;
	reg		key_syn2;
	reg 		key_reg1;
	reg		key_reg2;
	wire 		pos_edge;
	wire 		neg_edge;
	
	always@(posedge clk or negedge rst_n)
		if(!rst_n)begin
			state <= IDLE;
			cnt_en <= 1'b0;
		end else 
		begin
			case(state)
				IDLE:
					begin
						if(neg_edge)begin
							state <= FILTER1;
							cnt_en <= 1'b1;
						end else
						begin
							state <=	IDLE;	
							cnt_en <= 1'b0;
						end
					end
					
				FILTER1:
					begin
							if(cnt_full)//20ms
							begin
								state <= DOWN;
								cnt_en <= 1'b0;
							end 
							else if(pos_edge)
							begin
								state <= IDLE;
								cnt_en <= 1'b0;
							end else
							begin
								state <= FILTER1;
								cnt_en <= cnt_en;
							end
					end
					
				DOWN:
					begin
						if(pos_edge)begin
							cnt_en <= 1'b1;
							state <= FILTER2;
						end else 
						begin
							cnt_en <= 1'b0;
							state <= DOWN;
						end
					end
					
				FILTER2:
					begin
							if(cnt_full)
								state <=	IDLE;	
							else if(neg_edge)begin
								cnt_en <= 1'b0;
								state <= DOWN;
							end 
							else
								state <= FILTER2;
					end
				default: begin
					state <= IDLE;
					cnt_en <= 1'b0;
				end
			endcase
		end
//----cnt--------------------------------------
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			cnt1 <= 20'd0;
		else if(cnt_en)
			cnt1 <= cnt1 + 20'd1;
			else 
			cnt1 <= 20'd0;
	end
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			cnt_full <= 1'b0;
		else if(cnt1 == 20'd999_999)
			cnt_full <= 1'b1;
			else 
			cnt_full <= 1'b0;
	end
//----异步信号key同步处理---------------------------------
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			key_syn1 <= 1'b0;
			key_syn2 <= 1'b0;
		end else
		begin
			key_syn1 <= key;
			key_syn2 <= key_syn1;
		end	
	end
//----key edge detect--------------------------------
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			key_reg1 <= 1'b0;
			key_reg2 <= 1'b0;
		end else
		begin
			key_reg1 <= key_syn2;
			key_reg2 <= key_reg1;
		end	
	end
	assign neg_edge = (!key_reg1) & key_reg2;
	assign pos_edge = key_reg1 & (!key_reg2);
	
//----key_flag---------------------------------------
	assign key_flag = (cnt1 == 20'd999_999)? 1'b1:1'b0;
//----key_state--------------------------------------
		always@(posedge clk or negedge rst_n)
			if(!rst_n)
				key_state <= 1;
			else if(cnt_full)
				key_state <= ~key_state;
			else
				key_state <= key_state;	
endmodule
//-------------------------------------------------
//----LED灯控制模块--------------------------------
`timescale 1ns/1ns
module fsm_filter_model(
	input		press,
	output reg key
);
	reg [15:0] myrand;
	
	initial begin
		key = 1;//before press
	end
	always@(posedge press)
		press_key;
		
task press_key;
	begin
		repeat(50)begin
		myrand = {
    
    $random}%65536;//{$random}%6553(0~65535);{random}%65536:(-65535~65535)
		#myrand; key = ~key;			
	   end
	   key = 0;
		#50000000;
		
		repeat(50)begin
		myrand = {
    
    $random}%65536;//0~65535;
		#myrand; key = ~key;			
	   end
	   key = 1;
		#25_000_000;
	   	
	end
	endtask
endmodule

//----------------------------------------------------
//----按键信号发生模型--------------------------------
`timescale 1ns/1ns
module fsm_filter_model(
	input		press,
	output reg key
);
	reg [15:0] myrand;
	
	initial begin
		key = 1;//before press
	end
	always@(posedge press)
		press_key;
		
task press_key;
	begin
		repeat(50)begin
		myrand = {
    
    $random}%65536;//{$random}%6553(0~65535);{random}%65536:(-65535~65535)
		#myrand; key = ~key;			
	   end
	   key = 0;
		#50000000;
		
		repeat(50)begin
		myrand = {
    
    $random}%65536;//0~65535;
		#myrand; key = ~key;			
	   end
	   key = 1;
		#25_000_000;
	   	
	end
	endtask
endmodule
//----testbench-------------------------------
`timescale 1ns/1ns
`define clock_period 20
module tb_fsm_key_filter_top;
	reg clk;
	reg rst_n;
	reg press0;
	reg press1;
	wire [3:0] led;
	
	wire key0;
	wire key1;
	
	
	fsm_filter_model uut_model0(
		.press(press0),
		.key(key0)
   );
	
	fsm_filter_model uut_model1(
		.press(press1),
		.key(key1)
   );
	
	fsm_key_filter_top uut_top(
		.clk(clk),
		.rst_n(rst_n),
		.key0(key0),
		.key1(key1),
		.led(led)
	);
	
	initial clk = 1;
	always #(`clock_period/2) clk = ~clk;
	
	initial begin
		rst_n = 0;
		press0 = 0;
		press1 = 0;
		#(`clock_period*10);
		rst_n = 1;
		#(`clock_period*10+1);
//----press0------------------------------
		#80_000_000;
		     press0 = 1;//press
		#(`clock_period*3);
		     press0 = 0;//release
		#80_000_000;
			  press0 = 1;//press
		#(`clock_period*3);
		     press0 = 0;//release
		#80_000_000;
		     press0 = 1;//press
		#(`clock_period*3);
		     press0 = 0;//release
		#80_000_000;
			  press0 = 1;//press
		#(`clock_period*3);
		     press0 = 0;//release
//----press1-------------------------------
		#120_000_000;	 
		     press1 = 1;//press
		#(`clock_period*3);
		     press1 = 0;//release
		#80_000_000;
			  press1 = 1;//press
		#(`clock_period*3);
		     press1 = 0; //release
		#80000100;
		$stop;
	end
	
endmodule

	
endmodule

How to load the simulation model to the testbench?
(Quartus) Since the internal logic statements of the simulation model cannot be synthesized, the simulation model needs to be added to the testbench before the simulation, and press the operation to execute:
Assignment–> setting–>simulation–>1–>2–>3–>4 ,
And then perform RTL simulation.
Insert picture description here

3. Modelsim simulation
Insert picture description here
button model
Insert picture description here

The anode end of the led is connected to the power supply through a pull-up resistor. If the cathode end is connected to a low level (LED[3:0] is a low level), the led light is on; if the cathode end is connected to a high level LED[3:0], it is High level), the led light is off;

The original content of learning comes from Xiaomei Ge FPGA self-study notes

[Note]: Personal study notes, if there are any mistakes, please feel free to enlighten me. This is polite~~~

Guess you like

Origin blog.csdn.net/weixin_50722839/article/details/109656032