Verilog功能模块 —— 按键消抖

一. 什么是按键消抖

按键消抖_百度百科 (baidu.com)

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

从按键对应的数字电平来看,按键的抖动过程如下图所示。在抖动期间,按键的输入电平是不稳定的,消抖的目的就是去除抖动的影响,得到能表征按键过程的稳定的按键输入电平。


二. 按键消抖的方案

2.1 硬件消抖

通常的做法是在按键两端并联一个贴片电容,利用电容两端电压不能突变的特性来消除抖动。

2.2 软件消抖

利用按键按下的特点来消抖:

1.按键按下和弹起都会抖动,抖动的持续时间和按键类型和质量有关,一般为5~10ms

2.按键按下后保持稳定电平的时间一般不小于120ms


三. Verilog实现按键消抖

3.1 模块框图

3.2 参数列表 与 接口列表

参数名说明
KEY_DOWN_OUTPUT_HIGH_LEVEL按键按下的输出电平, 默认高电平
CLKFREQ计时时钟频率, 注意修改
INTI_MS初始检测未按下电平, 需要持续多少MS才视为检测成功, 默认50ms, 通常无需修改
KEEP_MS检测到按键按下/松开需要持续多少MS才视为有效, 默认40ms, 通常无需修改
接口名说明
key_in按键输入
clk工作时钟
key_down消抖后的按键状态
key_down_one_time按键按下一次
key_up_one_time按键松开一次

3.3 模块IP框图 与 使用说明

使用说明请参照3.2 参数列表与接口列表 以及 3.4 模块源码。

3.4 模块源码

/*
 * @Author       : Xu Dakang
 * @Email        : xudaKang_up@qq.com
 * @Date         : 2021-12-20 15:13:10
 * @LastEditors  : Xu xiaokang
 * @LastEditTime : 2022-04-14 21:03:31
 * @Filename     :
 * @Description  :
*/

/*
! 模块功能: 消除按键抖动, 得到正确的按键输入的电平
* 思路:
  1.先检测按键未按下时的电平
    必须保证在复位完成后的50ms(可通过参数INTI_MS修改)内,按键一直处于未按下的状态,否则未按下电平的检测会出错
  2.当按键电平为按下电平时,开始一个40ms(可通过参数KEEP_MS修改)的计数器,计数到最大值则认为按键按下
  3.当按键电平为松开电平时,开始一个40ms(可通过参数KEEP_MS修改)的计数器,计数到最大值则认为按键松开
*/

module myKeyEliminateJitter
#(
  parameter KEY_DOWN_OUTPUT_HIGH_LEVEL = 1, // 按键按下输出的电平
  parameter CLKFREQ = 100, // 计时时钟频率, 注意修改
  parameter INTI_MS = 50,  // 初始检测未按下电平, 需要持续多少MS才视为检测成功, 默认50ms, 通常无需修改
  parameter KEEP_MS = 40   // 检测到按键按下/松开需要持续多少MS才视为有效, 默认40ms, 通常无需修改
)(
  output logic key_down,          // 按键按下
  output logic key_down_one_time, // 按键按下一次
  output logic key_up_one_time,   // 按键松开一次

  input  logic key_in,   // 按键输入

  input  logic clk
);


//++ 按键输入同步 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
logic key_in_r1;
logic key;
always_ff @(posedge clk) begin
  key_in_r1 <= key_in;
  key <= key_in_r1;
end
//-- 按键输入同步 ------------------------------------------------------------


//++ 按键未按下时的电平检测 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
logic key_r1;
always_ff @(posedge clk) begin
  key_r1 <= key;
end


logic auto_detection_success;
// 50ms计数器
localparam CNT_50MS_MAX = CLKFREQ * 1000 * INTI_MS;
logic [$clog2(CNT_50MS_MAX+1)-1 : 0] cnt_50ms;
always_ff @(posedge clk) begin
  // 按键信号一改变就重新计数, 初始情况下这不应该发生, 只是为了应对电磁干扰或机械振动等极端条件
  if (auto_detection_success)
    cnt_50ms <= cnt_50ms;
  else if (key_r1 != key)
    cnt_50ms <= '0;
  else if (cnt_50ms < CNT_50MS_MAX)
    cnt_50ms <= cnt_50ms + 1'b1;
  else
    cnt_50ms <= '0;
end


always_comb begin
  if (cnt_50ms == CNT_50MS_MAX) // 按键信号从复位开始50ms内输入未发生变化
    auto_detection_success = 1'b1;
  else
    auto_detection_success = 1'b0;
end


logic auto_detection_success_r1;
always_ff @(posedge clk) begin
  auto_detection_success_r1 <= auto_detection_success;
end

assign auto_detection_success_pedge = auto_detection_success && ~auto_detection_success_r1;


logic key_up_value; // 存储按键未按下时的引脚电平
always_ff @(posedge clk) begin
  if (auto_detection_success_pedge)
    key_up_value <= key;
  else
    key_up_value <= key_up_value;
end
//-- 按键未按下时的电平检测 ------------------------------------------------------------


//++ 按键消抖 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// 检测按下电平, 如果按下保持40ms, 则认为键正常按下
localparam CNT_40MS_MAX = CLKFREQ * 1000 * KEEP_MS;
logic [$clog2(CNT_40MS_MAX+1)-1 : 0] key_down_cnt_40ms;
always_ff @(posedge clk) begin
  if (auto_detection_success_r1 && key == ~key_up_value) // 按键按下了
    if (key_down_cnt_40ms < CNT_40MS_MAX)
      key_down_cnt_40ms <= key_down_cnt_40ms + 1'b1;
    else
      key_down_cnt_40ms <= key_down_cnt_40ms;
  else
    key_down_cnt_40ms <= '0;
end


// 检测按键松开, 如果松开保持40ms, 则认为键正常松开
logic [$clog2(CNT_40MS_MAX+1)-1 : 0] key_up_cnt_40ms;
always_ff @(posedge clk) begin
  if (auto_detection_success_r1 && key == key_up_value) // 按键松开了
    if (key_up_cnt_40ms < CNT_40MS_MAX)
      key_up_cnt_40ms <= key_up_cnt_40ms + 1'b1;
    else
      key_up_cnt_40ms <= key_up_cnt_40ms;
  else
    key_up_cnt_40ms <= '0;
end


always_ff @(posedge clk) begin
  if (key_down_cnt_40ms == CNT_40MS_MAX) // 按下计数值保持最大值不变说明键处于按下的状态
    key_down <= KEY_DOWN_OUTPUT_HIGH_LEVEL;
  else if (key_up_cnt_40ms == CNT_40MS_MAX) // 松开计数值保持最大值不变说明键处于松开的状态
    key_down <= ~KEY_DOWN_OUTPUT_HIGH_LEVEL;
  else
    key_down <= key_down;
end


logic key_down_r1;
always_ff @(posedge clk) begin
  key_down_r1 <= key_down;
end

assign key_down_pedge = key_down && ~key_down_r1;
assign key_down_nedge = ~key_down && key_down_r1;

assign key_down_one_time = key_down_pedge;
assign key_up_one_time = key_down_nedge;
//-- 按键消抖 ------------------------------------------------------------


endmodule

3.5 工程分享

Verilog功能模块 —— 按键消抖 Vivado 2021.2工程 基于正点原子ZYNQ领航者V1-20220414。

欢迎大家关注我的公众号:徐晓康的博客,回复以下代码获取。

2352

建议复制过去不会码错字!


徐晓康的博客持续分享高质量硬件、FPGA与嵌入式知识,软件,工具等内容,欢迎大家关注。
  • 11
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Verilog按键消抖模块是一种用于消除按键抖动的电路模块。在Verilog代码中,通常会使用状态机来实现按键消抖功能。引用\[1\]中的代码展示了一个名为key_filter_top的模块,该模块包含一个时钟信号Clk、一个复位信号Rst_n和一个按键输入信号press。该模块还输出了一个按键标志信号key_flag和一个按键状态信号key_state。在该模块中,使用了名为key_filter的子模块和名为key_model的子模块。其中,key_filter模块用于实现按键消抖功能,key_model模块用于模拟按键输入。引用\[2\]中的代码展示了一个名为key_filter_top_tb的测试模块,该模块用于对key_filter_top模块进行仿真测试。在该测试模块中,使用了一个时钟信号Clk、一个复位信号Rst_n和一个按键输入信号press。通过对时钟信号进行周期性翻转,模拟了时钟信号的工作。引用\[3\]中的代码展示了一个名为key_filter_tb2的仿真模块,该模块用于模拟按键的抖动现象。在该仿真模块中,使用了一个时钟信号Clk、一个复位信号Reset_n和一个按键输入信号Key。通过使用随机函数模拟按键的抖动现象,模拟了按键的按下和释放过程。整体来说,Verilog按键消抖模块通过消除按键抖动现象,确保按键信号的稳定性和可靠性。 #### 引用[.reference_title] - *1* *2* [verilog常用模块1——按键消抖模块详解](https://blog.csdn.net/m0_37921318/article/details/105890194)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [verilog功能模块——按键消抖](https://blog.csdn.net/m0_70935984/article/details/130803240)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值