按键消抖通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开
     消抖是为了避免在按键按下或是抬起时电平剧烈抖动带来的影响
结合上节笔记的边沿检测,我们看一下按键消抖例程
代码:
moduleKey_filter(
						clk,
						rst_n,
						key_in,
						key_flag,
						key_state
						);
						
	inputclk,rst_n;
	inputkey_in;
	
	outputregkey_state;//按键状态
	outputregkey_flag;//按键标志输出
		
//	localparam
//			idel=4'b0001,//空闲态
//			filter0=4'b0010,//抖动滤波
//			down=4'b0100,//按下稳定态
//			filter1=4'b1000;
			
////////////////处理外部输入信号////////////////////////	
	regkey_in1,key_in2;//
	//外部输入的异步信号同步化消除亚稳态
	always@(posedgeclkornegedgerst_n)
	if(!rst_n)begin
		key_in1<=1'b0;
		key_in2<=1'b0;
	end
	elsebegin
		key_in1<=key_in;
		key_in2<=key_in1;
	end
	
	regkey_tmp1,key_tmp2;
	//使用两级寄存器,边沿检测
	always@(posedgeclkornegedgerst_n)
	if(!rst_n)begin
		key_tmp1<=1'b0;
		key_tmp2<=1'b0;
	end
	elsebegin
		key_tmp1<=key_in2;
		key_tmp2<=key_tmp1;
	end
	
	wirep_edge,n_edge;
	//产生跳变沿信号
	assignn_edge=!key_tmp1&key_tmp2;
	assignp_edge=key_tmp1&(!key_tmp2);
	
/////////////////计数信号输出//////////////////////	
	reg[3:0]cnt;
	regen_cnt;//使能计数
	always@(posedgeclkornegedgerst_n)
	if(!rst_n)
		cnt<=4'd0;
	elseif(en_cnt)
		cnt<=cnt+1'b1;
	elseif(!en_cnt)
		cnt<=4'd0;
	//计数满标志
	always@(posedgeclkornegedgerst_n)
	if(!rst_n)
		key_flag<=1'd0;
	elseif(cnt==4'd9)
		key_flag<=1'b1;
	else
		key_flag<=1'd0;
////////////////状态机模块///////////////////////	
	reg[3:0]state,NS;//两段式状态机
	always@(posedgeclkornegedgerst_n)
	if(!rst_n)begin
		state<=4'b1;
	end
	elsebegin
		state<=NS;
	end
	
	always@(stateorn_edgeorp_edgeorkey_flag)
	begin
		//en_cnt<=1'b0;
		key_state<=1'b1;
		case(state)
				4'd1	:	begin
									if(n_edge)begin
										en_cnt<=1'b1;
										NS<=4'd2;
									end
									else
										NS<=4'd1;
								end
						
				4'd2	:	begin
								if(key_flag)begin
									NS<=4'd3;
									en_cnt<=1'b0;
								end
								else
									NS<=4'd2;
							end
							
				4'd3	:	begin
									key_state<=1'b0;
									if(p_edge)begin
										en_cnt<=1'b1;
										NS<=4'd4;
									end
									else
										NS<=4'd3;
								end
							
				4'd4	:	begin
									if(key_flag)begin
										en_cnt<=1'b0;
										key_state<=1'b1;
										NS<=4'd1;
									end
									else
										NS<=4'd4;
								end
			default	:	begin
								NS<=4'd1;
								en_cnt<=1'b0;
								key_state<=1'b1;
							end
		endcase
			
	end
endmodule
`timescale1ns/1ns
`defineclk_period20
moduleKey_tb;
	regclk;
	regrst_n;
	regkey_in;
	wirekey_flag;
	wirekey_state;
	
	Key_filterkey_filter0(
		.clk(clk),
		.rst_n(rst_n),
		.key_in(key_in),
		.key_flag(key_flag),
		.key_state(key_state)
	);
	initialclk=1;
	always#(`clk_period/2)clk=~clk;
	
//	always@(posedgeclk)//随机函数使用
//	begin
//		#(`clk_period*100);
//		key_in={$random}%2;
//	end
	initialbegin
		rst_n=0;
		key_in=1;
		#(`clk_period*5);
		rst_n=1;
		#(`clk_period+1);
		press_key;
		#(`clk_period*200);
		press_key;
		#(`clk_period*200);
		press_key;
		#(`clk_period*500);
		$stop;
	end
	
	taskpress_key;//任务函数的使用
		begin
			#500key_in=0;
			#500key_in=1;
			#500key_in=0;
			#500key_in=1;
			#500key_in=0;
			#500key_in=1;
			#500key_in=0;
			#500key_in=1;
			#500key_in=0;
			#500key_in=1;
			#500key_in=0;
			#500key_in=1;	
		end
	endtask
endmodule
仿真波形:
