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

数字IC设计学习笔记

按键消抖模块2

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

1. 原理图

在这里插入图片描述
实验现象:
每次按下按键0,4个led显示状态以二进制加法格式加1;每次按下按键1,4个led显示状态以二进制加法格式减1.

2 Verilog 代码

//----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

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

3. Modelsim仿真
在这里插入图片描述
按键模型
在这里插入图片描述

led的阳极端通过一个上拉电阻接到电源,若阴极端接低电平(LED[3:0]为低电平),led灯亮;若阴极端接高电平LED[3:0]为高电平),led灯灭;

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

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

猜你喜欢

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