FPGA_消抖(光耦等开关的抖动)

一、按键消抖

按键消抖只是针对机械弹性开关按键,打开闭合时由于机械触点的弹性作用,一个按键在闭合后不会马上达到稳定状态,因此在闭合瞬间伴随一连串的抖动。必须对这部分抖动进行消抖处理。

按键消抖可以分为硬件消抖和软件消抖。

硬件消抖:主要用RS触发器和电容等方法消抖。(硬件消抖比较受限)

软件消抖:对按键信号延时5ms-20ms采样,也可以检测到按键稳定状态后采样。如图

 1、1

       软件消抖:这里按键稳定时间为20ms,系统晶振为50MHz,周期20ns,20ms/20ns=1000000,所以计数器最大值为999999。当检测到按键为低电平时计数器开始计数,计数到最大值时此时按键状态稳定,当系统检测到高电平时,对计数器清零,当计数器到最大值时,让计数器保持值不变,在定义一个标志信号对按键消抖的稳定状态进行采集,当计数器计数到最大值时,说明按键处于稳定状态。

在这里插入图片描述

 

module	key_shake
#(
	parameter		CNT_MAX = 20'd999_999//计数最大值,20ms
)
(
		input	wire			sys_clk		,
		input	wire			sys_rst_n	,
		input	wire			key_in		,
		
		output	reg				key_flag
);



reg	[19:0]		cnt;

always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		cnt <= 20'd0;
	else	if(key_in == 1'b1)
		cnt <= 20'd0;
	else	if(cnt == CNT_MAX)
		cnt <= CNT_MAX;
	else
		cnt <= cnt + 1'b1;
		
always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		key_flag <= 1'b0;
	else	if(cnt == CNT_MAX)
		key_flag <= 1'b1;
	else
		key_flag <= 1'b0;


endmodule

testbench

`timescale	1ns/1ns 
module	tb_key_shake();

reg			sys_clk;
reg			sys_rst_n;
reg			key_in;
reg	[7:0]	tb_cnt; 
wire		key_flag;

initial	
	begin
		sys_clk = 1'b0;
		sys_rst_n <= 1'b0;
		key_in	<= 1'b1;
		#20
		sys_rst_n <= 1'b1;
	end
	
always	#10 sys_clk = ~sys_clk;

//把按键消抖过程压缩至250个系统周期
always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		tb_cnt <= 8'd0;
	else	if(tb_cnt == 8'd249)
		tb_cnt <= 8'd0;
	else
		tb_cnt <= tb_cnt + 1'b1;

//模拟按键抖动
always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		tb_cnt <= 8'd0;
	else	if(tb_cnt <= 8'd24 || tb_cnt >= 8'd224)
		key_in <= 1'b1;
	else	if((tb_cnt <= 8'd74 && tb_cnt > 8'd24)||(tb_cnt <= 8'd224 && tb_cnt >= 8'd174))
		key_in <= {$random}%2;
	else
		key_in <= 1'b0;
		
key_shake
#(
	.CNT_MAX(70)
)
key_shake_inst
(
		.sys_clk		(sys_clk),
		.sys_rst_n		(sys_rst_n),
		.key_in			(key_in),

		.key_flag       (key_flag)
);

endmodule


仿真结果把按键按下时长缩短到250个系统时钟周期。定义一个计数器tb_cnt,计数最大值为249,然后模拟按键被按下的过程。过程如下图所示。

仿真结果

在这里插入图片描述

 由仿真结果得,每一次模拟按键的稳定状态都被标志信号key_flag采集到。

1、2

还有一种软件消抖写法,同样计数时间为20ms,对按键保存当前的值进寄存器,判断下一个周期的值是否不等于上一个周期,如果不等于,对计数器赋值,下一个周期如果相等计数器递减,如果一直相等,计数器一直递减到1,输出按键有效标志位。

module key_debounce(
 input sys_clk, //外部 50M 时钟
 input sys_rst_n, //外部复位信号,低有效
  input key, //外部按键输入
 output reg key_flag, //按键数据有效信号
 output reg key_value //按键消抖后的数据 
 );
 
 //reg define 
 reg [31:0] delay_cnt;
 reg key_reg;
 
 //*****************************************************
 //** main code
 //*****************************************************
 always @(posedge sys_clk or negedge sys_rst_n) begin
 if (!sys_rst_n) begin
 key_reg <= 1'b1;
 delay_cnt <= 32'd0;
 end
 else begin
 key_reg <= key;
 if(key_reg != key) //一旦检测到按键状态发生变化(有按键被按下或释放)
 delay_cnt <= 32'd1000000; //给延时计数器重新装载初始值(计数时间为 20ms)
 else if(key_reg == key) begin //在按键状态稳定时,计数器递减,开始 20ms 倒计时
 if(delay_cnt > 32'd0)
 delay_cnt <= delay_cnt - 1'b1;
 else
 delay_cnt <= delay_cnt;
 end 
 end 
 end
 
 always @(posedge sys_clk or negedge sys_rst_n) begin
 if (!sys_rst_n) begin
 key_flag <= 1'b0;
 key_value <= 1'b1; 
 end
 else begin
 if(delay_cnt == 32'd1) begin //当计数器递减到 1 时,说明按键稳定状态维持了 20ms
 key_flag <= 1'b1; //此时消抖过程结束,给出一个时钟周期的标志信号
 key_value <= key; //并寄存此时按键的值
 end
 else begin
 key_flag <= 1'b0;
 key_value <= key_value;
 end 
 end 
 end
 
 endmodule

第一种软件消抖要比第二种软件消抖简单高效,用按键输入电平值作为判断。

1、3

光耦问题:

 实际使用PS2801-4光耦,作为开关管起到隔离作用,输出端集电极接入到FPGA中,但是开关管有5us的开关稳定时间,光耦之前一直用作PWM输出,没有单独采集过信号。所以光耦是电流驱动型里面同样也有开关抖动时间的说法。

 1、4

三极管是否有抖动:

1、5

MOSS管是否有抖动:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值