FPGA中的按键消抖

按键的抖动

按键在按下过程中,触点接触和断开瞬间都会产生机械抖动,如果不进行处理,每一次按键就会产生若干次的响应。在单片机中一般使用delay函数来去除抖动,那么硬件去抖动该如何实现呢?

按键去抖动电路

在这里插入图片描述

原理

该按键消抖电路主要由四个移位寄存器构成,在按键按下时,每个时钟上升沿都会对key_in进行检测,只有当连续四个时钟上升沿都检测到键值为1时,key

Verilog 结构描述

源代码
module xiaodou_structure(key_in,clk,key_out);

input key_in,clk;
output key_out;
reg q0,q1,q2,q3;

always @(posedge clk)
begin 
 q3 <= q2;
 q2 <= q1;
 q1 <= q0;
 q0 <= key_in;
end

assign key_out=q0&q1&q2&q3;

endmodule

我一直对阻塞赋值和非阻塞赋值有疑惑,如果不能确定这样写是否会综合为移位寄存器,我们也可以这样写:

module xiaodou_structure2(key_in,clk,key_out);

input key_in,clk;
output key_out;
reg [3:0] q;

always @(posedge clk)
begin 
 q={q[2:0],key_in};
end

assign key_out=(q===4'b1111)?1:0;
endmodule

检查一下,综合器综合后生成的网表,确实是一个4位的移位寄存器。

Technology Map Viewer

在这里插入图片描述
再看看仿真的结果,也确实达到了消抖的效果

仿真波形

在这里插入图片描述

Verilog 行为描述

源代码
module xiaodou_action(key_in,clk,key_out);

input key_in,clk;
output reg key_out;
reg [1:0] state;

parameter S0='d0,S1='d1,S2='d2,S3='d3;

always @(posedge clk)
begin
 case(state)
  S0: begin 
    if(key_in) begin key_out<=0; state<=S1; end
    else begin key_out<=0; state<=S0; end
    end 
  S1: begin 
    if(key_in) begin key_out<=0; state<=S2; end
    else begin key_out<=0; state<=S0; end
    end 
  S2: begin 
    if(key_in) begin key_out<=0; state<=S3; end
    else begin key_out<=0; state<=S0; end
    end 
  S3: begin 
    if(key_in) begin key_out<=1; state<=S0; end  //S3改为S0
    else begin key_out<=0; state<=S0; end
    end 
  default state<=S0;
 endcase
end

endmodule

这段代码其实就是用状态机设计的1111序列检测器,这里我做了微微的改动,在日常经验中我们知道,如果长按某个按键,按键按下且稳定时,每隔一段时间,就会有一个按键有效脉冲,这样就可以实现对某个参数的连续调整。所以这里我将S3下一个状态设定为S0,而不是保持S3,这样在按键长按的情况下,每4个时钟就会有一个按键有效脉冲输出。

RTL

在这里插入图片描述

仿真结果

在这里插入图片描述
从图中可以看到,在第二次按键按下时,一共输出了3个按键有效脉冲。

Testbench

以上仿真所使用的testbench主要代码均相同,具体如下:

initial                                                
begin                                                  
clk=0;
key_in=0;
//按下
#20 key_in=1;
#3 key_in=0;
#2 key_in=1;
#1 key_in=0;
#1 key_in=1;
#3 key_in=0;
#2 key_in=1;
#3 key_in=0;
#2 key_in=1;
//稳定
#90 key_in=0;
//松手
#2 key_in=1;
#1 key_in=0;
#1 key_in=1;
#3 key_in=0;
#2 key_in=1;
#3 key_in=0;

//按下
#150 key_in=1;
#3 key_in=0;
#2 key_in=1;
#1 key_in=0;
#1 key_in=1;
#3 key_in=0;
#2 key_in=1;
#3 key_in=0;
#2 key_in=1;
//稳定
#280 key_in=0;
//松手
#2 key_in=1;
#1 key_in=0;
#1 key_in=1;
#3 key_in=0;
#2 key_in=1;
#3 key_in=0;

#100 $stop;                      
$display("Running testbench");                       
end 

always                                                               
begin                                                  
#10 clk=~clk;                                
end                                                    
endmodule
注意

最后需要注意的是时钟clk的选取,不能过大,一般取100Hz以下,但如果clk过小,也有可能得不到按键有效脉冲。

若文档有任何错误或不足,欢迎在博客下方留言指正;

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值