> 技术文档 > FPGA功能模块---按键消抖key bounce eliminate

FPGA功能模块---按键消抖key bounce eliminate


FPGA功能模块---按键消抖key bounce eliminate

    • 1、按键抖动Key Bounce
    • 1.1 定义
    • 1.2 形成原因
    • 1.3 影响后果
    • 2、 按键消抖Key Bounce Eliminate
    • 2.1 目的
    • 2.2 实现方式
    • 3、Verilog代码
    • 3.1 功能描述
    • 3.2 状态机
    • 3.3 源代码及TestBench仿真文件
    • 3.4 仿真结果

1、按键抖动Key Bounce

1.1 定义

“按键抖动”一般指的是按键在按下或释放时,电信号出现快速的开闭抖动,导致多个不稳定的触发信号出现。这个现象在机械按键、电路按钮等硬件输入设备中很常见,通常被称为“按键抖动”或“按键抖动效应”(Key Bounce)。如下图所示。
在这里插入图片描述

1.2 形成原因

(1)机械原因:按键内部的弹簧或触点在按下时不会立刻稳定,会发生物理抖动,使电路连接一断一连多次。
(2)电气原因:按键触点接触不良或电路噪声也会导致信号抖动。

1.3 影响后果

(1)造成多个信号触发,导致多次响应,比如一次点击被处理成多次点击。
(2)影响程序对按键事件的识别,造成误操作。

2、 按键消抖Key Bounce Eliminate

2.1 目的

按键消抖的目的是消除按键在按下或释放时电信号快速开闭的抖动状态,确保按键信号稳定可靠。

2.2 实现方式

(1)默认按键信号的电平:按键稳定按下后为低电平👇L,按键稳定弹起后为高电平👆H。
(2)当按键按下时,检测到按键信号的下降沿之后开始计时10ms,如果10ms内没有再次检测到下降沿,则认为按键被按下,否则重新计时,直至10ms内按键信号不再出现下降沿。
(3)当按键弹起时,检测到按键信号的上升沿之后开始计时10ms,如果10ms内没有再次检测到上升沿,则认为按键被弹起,否则重新计时,直至10ms内按键信号不再出现上升沿。
(4)按键消抖示意图如下图所示。
在这里插入图片描述

3、Verilog代码

3.1 功能描述

(1)用于消除按键抖动的模块
(2)按键输入信号的要求:按下时低电平
(3)可以输出完整的按键信号、上升沿、下降沿和双边沿
(4)按键判断条件
①按下:检测到按键信号的下降沿之后,BOUNCE_TIME内无下降沿出现
②弹起:检测到按键信号的上升沿之后,BOUNCE_TIME内无上升沿出现

3.2 状态机

根据按键操作过程可以分为以下4种状态,状态转换关系如下图所示

localparamOFF= 4\'b0001;//按键弹起状态localparamOFF2ON= 4\'b0010;//按键按下抖动状态localparamON= 4\'b0100;//按键按下状态localparamON2OFF= 4\'b1000;//按键弹起抖动状态reg [ 3:0]cur_state;//现态reg [ 3:0]next_state;//次态reg[19:0]cnt_bounce_time;//抖动时间计数器wire key_posedge;//按键input信号的上升沿wire key_negedge;//按键input信号的下降沿

在这里插入图片描述

3.3 源代码及TestBench仿真文件

源代码:

//==========================================================================//作者:DingXY的硬件笔记本//邮箱:1324830818@qq.com//版本:V1.0//日期:2025/07/29//功能描述//1.用于消除按键抖动的模块//2.按键输入信号的要求:按下时低电平//3.可以输出完整的按键信号、上升沿、下降沿和双边沿//4.按键判断条件//按下:检测到按键信号的下降沿之后,BOUNCE_TIME内无下降沿出现//弹起:检测到按键信号的上升沿之后,BOUNCE_TIME内无上升沿出现//==========================================================================module key_bounce_eliminate(inputclk,//系统时钟inputrst_n,//系统复位信号(低电平有效)inputkey,//按键input信号(按下时低电平)output regkey_n,//按键output信号(按下时低电平)output regkey_up,//按键弹起标志output regkey_down //按键按下标志);//--------------------------------------------------------------------------//信号定义//--------------------------------------------------------------------------//localparamCNT_BOUNCE_TIME = 20\'d20 ;//仿真:抖动时间400ns/20nslocalparamCNT_BOUNCE_TIME = 20\'d500_000 ;//抖动时间10ms/20nslocalparamOFF= 4\'b0001;//按键弹起状态localparamOFF2ON= 4\'b0010;//按键按下抖动状态localparamON= 4\'b0100;//按键按下状态localparamON2OFF= 4\'b1000;//按键弹起抖动状态reg [ 3:0]cur_state;//现态reg [ 3:0]next_state;//次态reg[19:0]cnt_bounce_time;//抖动时间计数器wire key_posedge;//按键input信号的上升沿wire key_negedge;//按键input信号的下降沿//--------------------------------------------------------------------------//例化edge_detector模块//按键input信号的上升沿key_posedge//按键input信号的下降沿key_negedge//--------------------------------------------------------------------------edge_detectoredge_detector_inst0(.clk (clk),//系统时钟.rst_n (rst_n),//复位信号(低电平有效).signal (key),//待检测信号.sig_sync (),//时钟同步后的检测信号.sig_posedge (key_posedge),//sig_sync信号的上升沿标志.sig_negedge (key_negedge),//sig_sync信号的下降沿标志.sig_bothedge() //sig_sync信号的上升沿和下降沿标志);//--------------------------------------------------------------------------//抖动时间计数器cnt_bounce_time//--------------------------------------------------------------------------always @(posedge clk or negedge rst_n) beginif(rst_n == 1\'b0)cnt_bounce_time <= 20\'d0 ;else begincase(cur_state)OFF2ON:beginif(cnt_bounce_time < CNT_BOUNCE_TIME - 1\'b1)//按键抖动过程中if(key_negedge == 1\'b1)//有抖动cnt_bounce_time <= 20\'d0 ;else//无抖动cnt_bounce_time <= cnt_bounce_time + 1\'b1 ;else//按键抖动结束cnt_bounce_time <= 20\'d0 ;//计数器清零endON2OFF:beginif(cnt_bounce_time < CNT_BOUNCE_TIME - 1\'b1)//按键抖动过程中if(key_posedge == 1\'b1)//有抖动cnt_bounce_time <= 20\'d0 ;else//无抖动cnt_bounce_time <= cnt_bounce_time + 1\'b1 ;else//按键抖动结束cnt_bounce_time <= 20\'d0 ;//计数器清零enddefault:cnt_bounce_time <= 20\'d0 ;endcaseendend//--------------------------------------------------------------------------//三段式状态机//--------------------------------------------------------------------------// 第一段:同步时序描述状态转移always @(posedge clk or negedge rst_n) beginif(rst_n == 1\'b0)cur_state <= OFF ;elsecur_state <= next_state ;end// 第二段:组合逻辑判断状态转移条件,描述状态转移规律always @(*) beginnext_state <= OFF ;case(cur_state)OFF:beginif(key_negedge == 1\'b1)//OFF状态下,检测到按键输入信号的下降沿next_state <= OFF2ON ;elsenext_state <= OFF ;endOFF2ON:beginif(cnt_bounce_time == CNT_BOUNCE_TIME - 1\'b1)//按键按下的抖动过程结束next_state <= ON ;elsenext_state <= OFF2ON ;endON:beginif(key_posedge == 1\'b1)//ON状态下,检测到按键输入信号的上升沿next_state <= ON2OFF ;elsenext_state <= ON ;endON2OFF:beginif(cnt_bounce_time == CNT_BOUNCE_TIME - 1\'b1)//按键弹起的抖动过程结束next_state <= OFF ;elsenext_state <= ON2OFF ;enddefault:next_state <= OFF ;endcaseend// 第三段:时序逻辑描述输出always @(posedge clk or negedge rst_n) beginif(rst_n == 1\'b0) beginkey_n<= 1\'b1 ;key_up<= 1\'b0 ;key_down<= 1\'b0 ;endelse begincase(cur_state)OFF:beginkey_n<= 1\'b1 ;key_up<= 1\'b0 ;key_down<= 1\'b0 ;endOFF2ON:beginif(cnt_bounce_time == CNT_BOUNCE_TIME - 1\'b1) begin//按键按下的抖动过程结束key_n<= 1\'b0 ;key_up<= 1\'b0 ;key_down<= 1\'b1 ;endelse beginkey_n<= 1\'b1 ;key_up<= 1\'b0 ;key_down<= 1\'b0 ;endendON:beginkey_n<= 1\'b0 ;key_up<= 1\'b0 ;key_down<= 1\'b0 ;endON2OFF:beginif(cnt_bounce_time == CNT_BOUNCE_TIME - 1\'b1) begin//按键按下的抖动过程结束key_n<= 1\'b1 ;key_up<= 1\'b1 ;key_down<= 1\'b0 ;endelse beginkey_n<= 1\'b0 ;key_up<= 1\'b0 ;key_down<= 1\'b0 ;endenddefault:beginkey_n<= 1\'b1 ;key_up<= 1\'b0 ;key_down<= 1\'b0 ;endendcaseendendendmodule

TestBench仿真文件:

//定义时间刻度`timescale 1ns/1nsmodule key_bounce_eliminate_tb();reg clk;//系统时钟reg rst_n;//系统复位信号(低电平有效)//--------------------------------------------------------//信号定义//--------------------------------------------------------reg key;//按键input信号(按下时低电平)wirekey_n;//按键output信号(按下时低电平)wirekey_up;//按键弹起标志wirekey_down;//按键按下标志//--------------------------------------------------------//定义主时钟,周期20ns,频率50MHz//--------------------------------------------------------always #10 clk = ~ clk ;//50MHz时钟//--------------------------------------------------------//设计仿真时序//--------------------------------------------------------initial beginclk <= 1\'b0 ;rst_n <= 1\'b0 ;key <= 1\'b1 ;//系统开始工作#20rst_n <= 1\'b1 ;//按下抖动#10key <= 1\'b0 ;#30key <= 1\'b1 ;#20key <= 1\'b0 ;#10key <= 1\'b1 ;#40key <= 1\'b0 ;#20key <= 1\'b1 ;#20key <= 1\'b0 ;#400key <= 1\'b0 ;//按下稳定状态#200key <= 1\'b0 ;//弹起抖动#10key <= 1\'b1 ;#20key <= 1\'b0 ;#30key <= 1\'b1 ;#20key <= 1\'b0 ;#40key <= 1\'b1 ;#10key <= 1\'b0 ;#20key <= 1\'b1 ;#400key <= 1\'b1 ;//弹起稳定状态#200key <= 1\'b1 ;//结束仿真#20$finish ;end//--------------------------------------------------------//例化key_bounce_eliminate模块//--------------------------------------------------------key_bounce_eliminatekey_bounce_eliminate_inst0(.clk(clk),//系统时钟.rst_n(rst_n),//系统复位信号(低电平有效).key(key),//按键input信号(按下时低电平).key_n(key_n),//按键output信号(按下时低电平).key_up(key_up),//按键弹起标志.key_down(key_down) //按键按下标志);endmodule

3.4 仿真结果

注意:key信号经过edge_detector之后会有2个时钟周期的延时
FPGA功能模块---按键消抖key bounce eliminate

更多内容请关注微信公众号:
在这里插入图片描述