数字IC设计学习笔记_按键消抖模块1

数字IC设计学习笔记

按键消抖模块1

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

1. 原理图

在这里插入图片描述
(1). key波形图
在这里插入图片描述
理想的按键key信号在0,1转换之间,可以瞬时间完成;实际在按键时,会产生一定时间范围的抖动信号,这里抖动信号的持续时间定为20ms。
(2). key_flag, key_state 波形图
在这里插入图片描述
第一条波形为按键信号key;
第二条波形为key_flag信号,当滤除抖动波形完成后,产生单周期高脉冲;
第三条波形为key_state信号,当滤除抖动波形后,转变为与key信号一致的波形;
(3). 状态转移图
在这里插入图片描述

2 Verilog 代码

//----top module---------------------------------
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
//----asyn_key-->syn---------------------------------
	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---------------------------------------
//		always@(posedge clk or negedge rst_n)
//			if(!rst_n)
//				key_flag <= 0;
//			else if(cnt_full)
//				key_flag <= 1;
//			else
//				key_flag <= 0;
	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
//----------------------------------------------------
//----testbench--------------------------------------
`timescale 1ns/1ns
`define clock_period 20
module tb_fsm_key_filter;
	reg clk;
	reg rst_n;
	reg key;
	wire key_flag;
	wire key_state;
	
	fsm_key_filter uut(
		.clk(clk),
		.rst_n(rst_n),
		.key(key),
		.key_flag(key_flag),
		.key_state(key_state)
	);
	initial clk = 1;
	always #(`clock_period/2) clk = ~clk;
	
	initial begin
		rst_n = 0;
		key = 1;//before press
		#(`clock_period*10);
		rst_n = 1;
		#(`clock_period*1000000+1);
//-----------第一种testbench------------------
//-------------------------------------
//----first time-----------------------	
//----press--------------------
//  //---jitter------------
//		key = 0;
//		#1000;key = 1;
//		#2000;key = 0;
//		#1400;key = 1;
//		#2600;key = 0;
//		#1300;key = 1;
//		#20;  key = 0;
//  //---non jitter--------
//		#20000100;
//		#50000100;
-----------------------------
//
----release------------------
//  //---jitter------------
//		#1000;key = 1;
//		#2000;key = 0;
//		#1400;key = 1;
//		#2600;key = 0;
//		#1300;key = 1;
//	//---non jitter-------------
//		#20000100;
-------------------------------------
----second time----------------------	
----press--------------------
//  //---jitter------------
//		key = 0;
//		#1000;key = 1;
//		#2000;key = 0;
//		#1400;key = 1;
//		#2600;key = 0;
//		#1300;key = 1;
//		#20;  key = 0;
//  //---non jitter--------
//		#20000100;
//		#50000100;
-----------------------------
//
----release------------------
//  //---jitter------------
//		#1000;key = 1;
//		#2000;key = 0;
//		#1400;key = 1;
//		#2600;key = 0;
//		#1300;key = 1;
//	//---non jitter-------------
//		#20000100;		
//		
//-----------第二种testbench------------------
      press_key;
		#10000;
      press_key;
		#10000;
      press_key;
		#10000;		
		//#50000100;
		$stop;
	end
	reg [15:0] myrand;
	
	task press_key;
	begin
		repeat(50)begin
		myrand = {
    
    $random}%65536;//0~65535;
		#myrand; key = ~key;			
	   end
	   key = 0;
		#50000000;
		
		repeat(50)begin
		myrand = {
    
    $random}%65536;//0~65535;
		#myrand; key = ~key;			
	   end
	   key = 1;
		#50000000;
	   	
	end
	endtask
	
endmodule

Testbench:
第一种详细列出激励信号,简单但代码冗长;
第二种采用task,随机发生函数$random,代码简单;
第三种采用仿真模型,单独一个module产生激励信号,多用于方真存储器模型等;(仿真模型一般由官方提供)

在这里插入图片描述

//----------------------------------------------------
//----第三种test bench--------------------------------------
`timescale 1ns/1ns
`define clock_period 20
module tb2_fsm_key_filter;
	reg clk;
	reg rst_n;
	wire key;
	wire key_flag;
	wire key_state;
	
	fsm_key_filter uut1(
		.clk(clk),
		.rst_n(rst_n),
		.key(key),
		.key_flag(key_flag),
		.key_state(key_state)
	);
	
	fsm_filter_model uut2(
		.key(key)
);
	
	initial clk = 1;
	always #(`clock_period/2) clk = ~clk;
	
	initial begin
		rst_n = 0;
		#(`clock_period*10);
		rst_n = 1;
		#(`clock_period*1000000+1);	
//		#50000100;
//		$stop;
	end
//----仿真模型-------------------------------
`timescale 1ns/1ns
module fsm_filter_model(
	output reg key
);
	reg [15:0] myrand;
	
	initial begin
		key = 1;//before press

      press_key;
		#10000;
      press_key;
		#10000;
      press_key;
		#10000;		
		//#50000100;
		$stop;
	end
		
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;
		#50000000;
	   	
	end
	endtask
endmodule

	
endmodule

如何将仿真模型加载到testbench?
(Quartus)由于仿真模型内部是不可综合逻辑语句,所以在仿真前,需要将仿真模型加到testbench,按一下操作执行:
Assignment–> setting–>simulation–>1–>2–>3–>4,
再进行RTL simulation.
在这里插入图片描述

3 Modelsim仿真
在这里插入图片描述

学习原内容来自小梅哥FPGA自学笔记

【注】:个人学习笔记,如有错误,望不吝赐教,这厢有礼了~~~

猜你喜欢

转载自blog.csdn.net/weixin_50722839/article/details/109626087