关于消抖电路的再认知(消抖电路的简洁写法)

文章目录

    • 1. 引言
    • 2. 简洁的方法,令人愉悦的代码
      • 2.1 module
      • 2.2 tb

1. 引言

2019年11月,学习了梅雪松的消抖电路,但始终觉得他用状态机来判断抖动并消除抖动会增加很多功耗,毕竟一个按键的每次抖动都要用状态机来判断,增加了电路电平某段时间的翻转率,觉得不妥。

随后便学习了特权同学的视频,有了关于特权同学第9课——消抖电路rtl的分析这一文章。

可是本人始终觉得两人的写法都有些欠缺。

恰巧入职未满一周,有幸接触到了公司合作方所给的FPGA代码,其中简洁的消抖电路令我拍案惊奇——这才是它应该有的样子!

2. 简洁的方法,令人愉悦的代码

2.1 module

细细一看,发现这段代码可能是德州仪器所写的,毕竟题头已经标注了“TI”两字。

贴出来供大家参考。

module debouncer (
	clk,  
	rstn, 
	din,  
	dout   
);

input	 clk;
input	 rstn;
input	 din;

output 	dout;
reg		dout;

reg		[15:0]	clk_c;  //counter for clock divider

reg		debounce_clk;
reg		signal_sample_1, signal_sample_2, signal_sample_3, signal_sample_4;

always@(posedge clk or negedge rstn)	begin
	if (~rstn) begin 
		clk_c 		 <= 16'h0;
		debounce_clk <= 1'b0;
	end	
	else if (clk_c == 3) begin  //28'h16590
	    clk_c 			<= 16'h0;
		 debounce_clk 	<= ~debounce_clk;
	end	
	else begin 
	    clk_c 			<= clk_c + 1'b1;
		 debounce_clk 	<= debounce_clk;
	end
end

always@(posedge debounce_clk or negedge rstn)begin
	if (~rstn) begin 
		signal_sample_1 <= 1'b1;
		signal_sample_2 <= 1'b1;
		signal_sample_3 <= 1'b1;
		signal_sample_4 <= 1'b1;
	end	
	else begin 
		signal_sample_1 <= signal_i;
		signal_sample_2 <= signal_sample_1;
		signal_sample_3 <= signal_sample_2;
		signal_sample_4 <= signal_sample_3;
	end   
end

always@(posedge clk or negedge reset_z)		
begin
	if (~rstn)  
		signal_o <= 1'b1;
	else if (signal_o == 1'b1 && 
			 signal_sample_1 == 1'b0 && 
			 signal_sample_2 == 1'b0 &&
			 signal_sample_3 == 1'b0 &&
			 signal_sample_4 == 1'b0)
		signal_o <= 1'b0;
	else if (signal_o == 1'b0 && 
			 signal_sample_1 == 1'b1 && 
			 signal_sample_2 == 1'b1 &&
			 signal_sample_3 == 1'b1 &&
			 signal_sample_4 == 1'b1)
		signal_o <= 1'b1;	
	else
		signal_o <= signal_o;
end

endmodule

//此debouncer电路,最终的输出signal_o相对于signal_i的延迟为
// 3*debounce_clk_period + clk_perild

2.2 tb

测试文件很简单,希望各位看官自己动手,如果偷懒的话,我写的给大家做个参考。

`timescale 1ns/1ns
`define p 20

module debouncer_tb;

reg clk		;
reg rstn		;
reg signal_i;

wire signal_o;

debouncer test(
	.clk		(clk	),
	.reset_z	(rstn	),
	
	.signal_i	(signal_i),
	.signal_o	(signal_o)
);

initial 	   clk = 1'b0;
always #(`p/2) clk = ~clk; //clk 频率50MHz

initial begin 
	rstn 		= 1'b0; 
	signal_i	= 1'b0;
	
	#(`p*10 + 3);
	rstn = 1'b1;
	
	repeat (5) begin
		#(`p*200);
		signal_i = ~signal_i;
	end
	
	#(`p*10);
	$stop;
end
endmodule

这才是消抖电路该有的逻辑,该有的样子。

最后关于输入到输出的时间计算,假设debounce_clk的周期为Pd,而clk的周期为P,则

别看了用了四个寄存器(分别是signal_sample_1, signal_sample_2, signal_sample_3, signal_sample_4),实际上dout距离din的时间差为:

t = 3 ∗ P d + P t = 3*P_d + P t=3Pd+P

以上。

你可能感兴趣的:(FPGA,fpga,verilog,编程语言)