赞
踩
一、按键消抖
按键消抖只是针对机械弹性开关按键,打开闭合时由于机械触点的弹性作用,一个按键在闭合后不会马上达到稳定状态,因此在闭合瞬间伴随一连串的抖动。必须对这部分抖动进行消抖处理。
按键消抖可以分为硬件消抖和软件消抖。
硬件消抖:主要用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管是否有抖动:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。