FPGA开发——边缘检测与按键消抖

一、边缘检测

1.说明

检测信号的跳变,即上升沿(0→1)或下降沿(1→0)。常用于检测1bit信号的电平跳变,例如光耦、按键、微动开关等器件在正常工作时会产生由0到1或者由1到0的跳变,检测到边沿的跳变后就能知道这些器件在什么时候被触发。

2.verilog代码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date:    20:33:46 05/10/2024 
// Design Name: 
// Module Name:    edge_check 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 这里写了一个D触发器,我们观测他的上升沿和下降沿的变化情况。
//
// Dependencies: 
//
// Revision: OA
// Revision 0.01 - File Created
// Additional Comments: 
//
//
module edge_check(

	input	wire	rst_n,
	input	wire	clk  ,
	input   wire	D    ,
	
	output	wire	pos_edge,
	output	wire	neg_edge
 );
	reg	temp0,  temp1;
	
	always @(posedge clk, negedge rst_n)
	begin
		if(rst_n == 1'b0)begin
			temp0 <= 1'b0;
			temp1 <= 1'b0;
		end
		else begin                //这里敲两拍!!!!做寄存!!!
			temp0 <= D;
			temp1 <= temp0;
		end
	end
	
	assign pos_edge = temp0 & (~temp1);
	assign neg_edge = (~temp0) & temp1;
			

endmodule

temp0是当前值,temp1是之前值!!!

3.测试代码

`timescale 1ns / 1ps


// Company: 
// Engineer:
//
// Create Date:   20:43:20 05/10/2024
// Design Name:   edge_check
// Module Name:   D:/202405/20220213/prj/adge_check/adge_check_tb.v
// Project Name:  adge_check
// Target Device:  
// Tool versions:  
// Description: 
//
// Verilog Test Fixture created by ISE for module: edge_check
//
// Dependencies:
// 
// Revision:OA
// Revision 0.01 - File Created
// Additional Comments:
// 


module adge_check_tb;

	// Inputs
	reg rst_n;
	reg clk;
	reg D;

	// Outputs
	wire pos_edge;
	wire neg_edge;

	// Instantiate the Unit Under Test (UUT)
	edge_check uut (
		.rst_n(rst_n), 
		.clk(clk), 
		.D(D), 
		.pos_edge(pos_edge), 
		.neg_edge(neg_edge)
	);

	initial begin
		// Initialize Inputs
		rst_n = 0;
		clk = 0;
		D = 0;

		// Wait 100 ns for global reset to finish
		#100;
		rst_n = 1;
		
		#1000;
		D=1;
		#5005;
		D=0;
		#200;
		$stop;
        
		// Add stimulus here

	end
      
	always #10 clk = ~clk;
endmodule

4.ISE仿真图

上升沿检测

下降沿检测

二、按键消抖

1.说明

按键消抖是为了防止按键信号由于机械接触不良而产生的快速开闭抖动导致的错误电信号读取,确保每次按压动作只被识别一次。通常有两种实现方式:硬件消抖和软件消抖。具体如下:

  1. 硬件消抖

    • 通过在按键电路中加入RC(电阻-电容)延时电路或RS触发器等硬件元件来实现。
    • 硬件消抖的优点是反应速度快,因为它是在信号进入系统之前就已经完成了消抖处理。
    • 缺点是需要额外的硬件支持,增加了成本和设计的复杂度。
  2. 软件消抖

    • 在代码中通过设置一定的延时来忽略连续的信号变化,或者使用定时器中断来过滤掉短时间内的信号抖动。
    • 软件消抖的优点是不增加硬件成本,灵活性高,可以通过调整延时时间或定时器设置来适应不同的应用场景。
    • 缺点是对处理器资源的占用,可能会影响其他任务的执行效率。

这里主要介绍通过延时,来进行抖动消除。

(图片搬运自ww丶121

抖动是在按键按下与抬起时发生的,这段时间非常段,我们可以通过计数器计时20MS左右的时间之后,把稳定的信号通过flag标志,判断是否按下。

2.verilog代码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date:    15:33:46 05/12/2024 
// Design Name: 
// Module Name:    jitter 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 按键消抖
//
// Dependencies: 
//
// Revision: OA
// Revision 0.01 - File Created
// Additional Comments: 
//
//
module jitter(
	input	wire		clk	,
	input	wire		rst_n	,
	input	wire		key	,    //初始为1,没按下
	
	output	reg	        flag	//flag:1,没按下   0:按下
    );
	
    parameter	t = 500_000;  //计时器,t*20ns,大约10ms
	reg	[18:0]	cnt;
	
	reg	temp0,  temp1;
	wire	pos_edge, neg_edge;
	reg	[1:0]	state;
	
	always @(posedge clk, negedge rst_n)
	begin
		if(rst_n == 1'b0)begin
			temp0 <= 1'b0; //初值和寄存器的输入(key)要保持一致,0的话有问题,有个毛刺,见图
			temp1 <= 1'b0;
		end
		else begin
			temp0 <= key;
			temp1 <= temp0;
		end
	end
	
	assign pos_edge = temp0 & (~temp1);
	assign neg_edge = (~temp0) & temp1;
	
	
	//计数器在下降沿的时候开始计数。
	always@ (posedge clk, negedge rst_n)
	begin
		if(rst_n == 1'b0)
			begin
			flag <= 1'b1;  //flag是等效替代按键的,低电平有效。
			state <= 2'b00;
			cnt <= 19'd0;
			end
		else
			case(state)
				2'd0 : begin
							if(neg_edge)	//	
								state <= 2'd1;
							else
								state <= 2'd0;
						 end
				2'd1	: begin
							if(key == 0)
								begin
									if(cnt == t-1)
									 begin
										cnt <= 19'd0;
										state <= 2'd2;
										flag <= 1'b0;
									 end
									else
										begin
											cnt <= cnt +1'b1;
											state <= 2'd1;
											flag <= 1'b1;
										end
								end
							else
								begin
									cnt <= 19'd0;
									state <= 2'd1;
									flag <= 1'b1;
								end
							end
				2'd2	: begin		
							if(pos_edge)
								state <= 2'd3;
							else
								state <= 2'd2;
						  end
				2'd3	: begin
							if(key == 1)
								begin
									if(cnt == t-1)
									 begin
										cnt <= 19'd0;
										state <= 2'd0;
										flag <= 1'b1;
									 end
									else
										begin
											cnt <= cnt +1'b1;
											state <= 2'd3;
											flag <= 1'b0;
										end
								end
							 else
								begin
									cnt <= 19'd0;
									state <= 2'd3;
									flag <= 1'b0;
								end
						  end
				default: ;
			endcase
	
		 end

endmodule

再解释一下代码,代码也就是说,通过状态机来实现,如果按下(key==0)时间超过10ms,那么判断为按下,flag拉低。以此类推。

3.测试代码

`timescale 1ns / 1ps


// Company: 
// Engineer:
//
// Create Date:   17:36:25 05/12/2024
// Design Name:   jitter
// Module Name:   D:/202405/20220213/prj/jitter/jitter_tb.v
// Project Name:  jitter
// Target Device:  
// Tool versions:  
// Description: 
//
// Verilog Test Fixture created by ISE for module: jitter
//
// Dependencies:
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 


module jitter_tb;

	// Inputs
	reg clk;
	reg rst_n;
	reg key;

	// Outputs
	wire flag;
	
	defparam jitter_inst.t = 20;  //这里时间改了一下,方便测试~~~

	// Instantiate the Unit Under Test (UUT)
	jitter jitter_inst (
		.clk(clk), 
		.rst_n(rst_n), 
		.key(key), 
		.flag(flag)
	);

	initial begin
		// Initialize Inputs
		clk = 0;
		rst_n = 0;
		key = 1;

		// Wait 100 ns for global reset to finish
		#100;
		rst_n = 1;
		#1000;
		
		key = 0;    //这里模拟抖动
		#50;
		key = 1;
		#20;
		key = 0;
		#20;
		key = 1;
		#40;
		key = 0;
		
		#2000;
		key = 1;    //这里模拟抖动
		#20;
		key = 0;
		#30;
		key = 1;
		#40;
		key = 0;
		#50;
		key = 1;
		
		#1000;
		$stop;
		
		
        
		// Add stimulus here

	end
	
	always #10 clk = ~clk;
      
endmodule

4.ISE仿真图

rst_n==1时,有一个毛刺,是因为初始值temp0 <= 1'b0; temp1 <= 1'b0;应该和key=1一样就没有了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值