战术消抖:)--(又名按键消抖~)

消抖缘由:

       为什么需要按键消抖呢,???

原因在于按键按下时,实际的按键信号并不像人们以为的那样直接按下就发生转变且稳定输出,实际上由于物理构造等原因,期间会经过多次快速的电平抖动,最终达到稳定,弹起时:the same! 这对于一些敏感的元器件或者特殊的场合(哈哈我也不知道实际是哪些场合~)肯定是不适合的.(上图?)

这里我们就需要用到战术消抖!

消抖步骤:

         这里我们可以假设若输出信号稳定的时间达到某一时间段(如本例中我们认为达到20ms)即为稳定输出.有了这个前提我们只需忽略电平沿持续时间达不到20ms的电平变化即可! (是不是很简单 

代码如下: (有很详细的注释哦,仔细看都能看懂.这里我们就已经达到了战术消抖的目的了!)

module keyIn_filter(
							Clk, 			//系统时钟,频率为50M
							Rst_n, 		//复位信号低电平有效
							key_in, 		//低电平有效
							key_flag,	//记录完成一次变化(消抖完成)的信号
							key_state	//实际所需的稳定(消抖后)输出
							);
input Clk;
input Rst_n;
input key_in;

output reg key_flag;
output reg key_state;

reg[3:0] state;	//用来保存状态机的几种状态
localparam			//状态名分别为无动作、滤波器0、低电平、滤波器1
	IDEL = 4'b0001,
	FILTER0 = 4'b0010,
	DOWN = 4'b0100,
	FILTER1 = 4'b1000;

reg[19:0]cnt;	//计数器寄存器(20位)
reg en_cnt;		//计数器使能信号
reg cnt_full;	//计数满信号
	
reg key_reg0, key_reg1;
wire pog, neg;

always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
	key_reg0 <= 1'b0;
	key_reg1 <= 1'b0;
end
else begin 
	key_reg0 <= key_in;
	key_reg1 <= key_reg0;
end

//高低电平沿的定义

assign pog = !key_reg0 & key_reg1;
assign neg = key_reg0 & (!key_reg1);

always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
	state <= IDEL;
	en_cnt <= 1'b0;
	key_flag <= 1'b0;
	key_state <= 1'b1;
end
else begin 
	case(state)
		IDEL:
			begin 
				key_flag <= 1'b0;
				if(neg)begin 
					state <= FILTER0;
					en_cnt <= 1'b1;
				end
				else 
					state <= IDEL;
			end
			
		FILTER0:
			if(cnt_full)begin
				state <= DOWN;
				en_cnt <= 1'b0;
				key_flag <= 1'b1;
				key_state <= 1'b0;
			end
			else if(pog)begin
				state <= IDEL;
				en_cnt <= 1'b0;
			end
			else 
				state <= FILTER0;
				
		DOWN:
			begin
				key_flag <= 1'b0;
				if(pog)begin
					state <= FILTER1;
					en_cnt <= 1'b1;
				end
				else 
					state <= DOWN;				
			end	
				
		FILTER1:
			if(cnt_full)begin
				state <= IDEL;
				key_flag <= 1'b1;
				key_state <= 1'b1;
			end
			else if(neg)begin
				en_cnt <= 1'b0;
				state <= DOWN;
			end
			else 	
				state <= FILTER1;
				
		default:
			begin
				state <= IDEL;
				en_cnt <= 1'b0;
				key_flag <= 1'b0;
				key_state <= 1'b1;
			end
	endcase		

end

//计数器为一个时钟周期(20ns)计数一次

always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
	cnt <= 20'd0;
else if(en_cnt)
	cnt <= cnt + 1'b1;
else 
	cnt <= 20'd0;

//则计数满一次为20ms(预设保持20ms以上的时长为有效)需
//20ms = 20_000_000ns  /20ns = 1000_000次
//也是由此得出计数器寄存器cnt的位数为20位(二进制)
	
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)	
	cnt_full <= 1'b0;
else if(cnt == 999_999)
	cnt_full <= 1'b1;
else 
	cnt_full <= 1'b0;

endmodule	

这里检查代码状态部分是否正确可以看一下State Machine Viewer:

Testbench (这里引出了task用法和($random)的一个用法)

`timescale 1ns/1ns	//testbench精度

`define clock_period 20	//时钟周期为20ns

module keyIn_filter_tb();
	reg Clk;
	reg Rst_n;
	reg key_in;
	
	wire key_flag;
	wire key_state;
	keyIn_filter keyIn_filter0(
									.Clk(Clk), 
									.Rst_n(Rst_n), 
									.key_in(key_in), 
									.key_flag(key_flag), 
									.key_state(key_state)
							);

//系统时钟产生
							
	initial Clk = 1;
	always #(`clock_period/2) Clk = ~Clk;

//方法1.每行手写产生输出信号	

//	initial begin
//		Rst_n = 0;
//		key_in = 1;
//		#(`clock_period*50) Rst_n = 1;
//		#(`clock_period*50 + 1);	//老技巧,+1使波形便于观察
//		
//		//进入滤波0状态消抖
//		#10000 key_in = 0;
//		#2000 key_in = 1;
//		#3000 key_in = 0;
//		#4000_0000;	//状态转换为DOWN
//		//进入滤波1状态消抖
//		#1000 key_in = 1;
//		#2000 key_in = 0;
//		#3400 key_in = 1;
//		#3424 key_in = 0;
//		#45345 key_in = 1;
//		#4500_0000;	//状态转为常态..
//		
//		//复制粘贴
//		
//		//进入滤波0状态消抖
//		#10000 key_in = 0;
//		#2000 key_in = 1;
//		#3000 key_in = 0;
//		#4000_0000;	//状态转换为DOWN
//		//进入滤波1状态消抖
//		#1000 key_in = 1;
//		#2000 key_in = 0;
//		#3400 key_in = 1;
//		#3424 key_in = 0;
//		#45345 key_in = 1;
//		#4500_0000;	//状态转为常态..
//		
//		//进入滤波0状态消抖
//		#10000 key_in = 0;
//		#2000 key_in = 1;
//		#3000 key_in = 0;
//		#4000_0000;	//状态转换为DOWN
//		//进入滤波1状态消抖
//		#1000 key_in = 1;
//		#2000 key_in = 0;
//		#3400 key_in = 1;
//		#3424 key_in = 0;
//		#45345 key_in = 1;
//		#4500_0000;	//状态转为常态..
//	
//		//进入滤波0状态消抖
//		#10000 key_in = 0;
//		#2000 key_in = 1;
//		#3000 key_in = 0;
//		#4000_0000;	//状态转换为DOWN
//		//进入滤波1状态消抖
//		#1000 key_in = 1;
//		#2000 key_in = 0;
//		#3400 key_in = 1;
//		#3424 key_in = 0;
//		#45345 key_in = 1;
//		#4500_0000;	//状态转为常态..
//	
//		$stop;	//不要忘了暂停!
//	end
	
//方法2:使用task功能创建一次的输入信号,之后反复调用
	
	reg [15:0]myrand;
	
	task press_key;
		begin
			repeat(50)begin
				myrand = ($random)%458433;
				#myrand key_in = ~key_in;
			end
			key_in = 0;
			#4500_0000;
			
			repeat(50)begin
				myrand = ($random)%458433;
				#myrand key_in = ~key_in;
			end
			key_in = 1;
			#4500_0000;
		end
	endtask
	
	initial begin
		Rst_n = 0;
		key_in = 1;
		#(`clock_period*50) Rst_n = 1;
		#(`clock_period*50 + 1); 	//老技巧,+1使波形便于观察
		press_key;
		#1000;
		press_key;
		#1000;
		press_key;
		#1000;
		press_key;
		#1000;	
		$stop;
	end
	
endmodule

WAVE:  (好像时间设置的不太好啊~

 

 没关系,放大(50倍~)看:

 成功达到战术消抖!

今日份达成~加油!

and another one is : test_model (like this picture)

蓝色箭头为激励和输出.

New code (1.test_model 2.testbench)

1.
`timescale 1ns/1ns	//testbench精度

module key_model(key);	//测试模块中不用关心时间只关心激励,增加了灵活性!
	output reg key;	//???
	
	reg [15:0]myrand;
	
	task press_key;
		begin
			repeat(50)begin
				myrand = ($random)%458433;
				#myrand key = ~key;
			end
			key = 0;
			#4500_0000;
			
			repeat(50)begin
				myrand = ($random)%458433;
				#myrand key = ~key;
			end
			key = 1;
			#4500_0000;
		end
	endtask

//只用产生激励信号	
	initial begin
		key = 1'b1;
		press_key;
		#1000;
		press_key;
		#1000;
		press_key;
		#1000;
		press_key;
		#1000;	
		$stop;
	end


endmodule
		
2.
`timescale 1ns/1ns	//testbench精度

`define clock_period 20	//时钟周期为20ns

module keyIn_filter_tb();
	reg Clk;
	reg Rst_n;
	//reg key_in;
	wire key_in;
	
	wire key_flag;
	wire key_state;
	keyIn_filter keyIn_filter0(
									.Clk(Clk), 
									.Rst_n(Rst_n), 
									.key_in(key_in), 
									.key_flag(key_flag), 
									.key_state(key_state)
							);

//引入测试模块进行灵活测试

 key_model key_model(
							.key(key_in)
							);							
					
//系统时钟产生
							
	initial Clk = 1;
	always #(`clock_period/2) Clk = ~Clk;

//产生复位信号
	
	initial begin
		Rst_n = 0;
		#(`clock_period*50) Rst_n = 1;
		#(`clock_period*50 + 1); 	//老技巧,+1使波形便于观察
	end
	
endmodule

this new one do make testbench more flexible !

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值