首页 > 资讯

FPGA按键消抖

来源:博客园 2023-07-29 11:31:06
简介按键

按键是输入设备,一般来说,按键在没有按下的时候是高电平;当按键按下的时候,为低电平。

DE2-70 User Manual


(资料图片)

Each switch provides a high logic level (3.3 volts) when it is not pressed, and provides a low logic level (0 volts) when depressed. Since the pushbutton switches are debounced, they are appropriate for use as clock or reset inputs in a circuit.

这里介绍到了按键抖动(Button Bouncing)和按键消抖(Button Debouncing)。

按键消抖

按键消抖通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动,为了不产生这种现象而作的措施就是按键消抖。

上图描述的是硬件的按键消抖。可见,消抖后,一次按键,只产生了一次电平变化。

这对我们接下来利用按键意义重大。

物理消抖

简单介绍下实现上图的消抖。

电容滤波

将电容并联在按键的两端,利用电容的放电的延时特性。将产生抖动的电平通过电容吸收掉。从而达到消抖的作用。

RS触发器

利用RS触发器来吸收按键的抖动。一旦有键按下,触发器立即翻转,触电的抖动便不会再对输出产生影响。

程序消抖

按键在FPGA中必不可少,我们需要利用按键对一些变量进行累加或累减。比如频率、分数等。

未消抖

在一开始的学习中,我们可能只用到了开关(switch),编写开关控制的程序类似于将开关当作一个布尔(Boolean)变量。

但是按键与开关不同,以下面这段代码为例,期望作用是 按键按下后,LED灯状态改变

module Test(    input       sys_clk,    input       rst_n,    input       key,    output  reg led);    always@(posedge sys_clk or negedge rst_n)    begin        if(rst_n == 1"b0)             led <= 1"b0;        else if(key == 1"b0)            led <= ~led;        else            led <= led;    endendmodule

然而,上板测试发现,LED状态灯一直处于不亮的状态。

假设,我们的时钟频率是50MHz,那么它的周期就是20ns

那么,在你按按钮的全过程中,按下的状态持续了多长时间呢?

显然,远大于20ns,所以LED会多次取反。所以这种简单粗暴的方法是不适合按键的。

消抖

我们刚刚的问题是,短时间内重复检测,从而多次执行了按键后的行为。

可以想到,给这个按键定个时:当有按键按下,计数器不断自增,若因为抖动,则计数器会清空,重新计数,当不抖动的时候,就会计满,此时才会判定为按键按下。

代码

// 定时器消除抖动module key_filter(    inputwire            sys_clk,          // 50M时钟    input   wire         sys_rst_n,        // 复位信号,低电平有效    input   wire      key,              // 按键输入    output reg       key_flag,         // 按键信号有效信号output reg       key_value         // 消抖后的按键信号     );     reg [31:0] delay_cnt;// 32位定时器reg        key_reg; 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   endalways @(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   // 按键稳定状态维持了20ms            key_flag  <= 1"b1;         // 此时消抖过程结束,信号有效            key_value <= key;          // 保存此时按键信号        end           else begin            key_flag  <= 1"b0;            key_value <= key_value;         end      end   end    endmodule 

如此,我们再重新写下刚刚的未消抖程序。

module Test(      input       sys_clk,     // 系统时钟      input       rst_n,       // 复位信号,低电平有效      input           key,     // 按键信号         output    reg     led // LED灯  );  wire key_value;wire key_flag;// 例化key_filterkey_filter_inst(    .sys_clk(sys_clk),     // 50M时钟    .sys_rst_n(sys_rst_n),   // 复位信号,低电平有效    .key            (key),         // 按键输入)    .key_flag(key_flag),    // 按键信号有效信号    .key_value      (key_value)    // 按键消抖后的数据  );always @ (posedge sys_clk or negedge sys_rst_n) begin    if(!sys_rst_n)beginled <= 1"b0;end    else if(key_flag && (~key_value))  // 按键是否有效按下begin led  <= ~led;end    else    begin        led <= led;    endendendmodule 

成功,按键可以控制LED灯亮与熄灭。仿真略。

这是简单的计时消抖,读者有兴趣可阅读学习状态机的方法。

参考文献

[1] 按键的硬件消抖电路原理详解

[2] FPGA要按键实现四个数码管加减计数怎么搞?

[3] FPGA学习—按键控制

[4] DE2-70 User Manual

上一篇

BHG北京华联关闭全国首家仓储会员店

下一篇

最后一页

为你推荐

最新热文