不需要复位的verilog去抖

Verilog功能模块 —— 按键消抖_verilog按键消抖-CSDN博客

上面的博客提到了一种不需要复位按键的verilog去抖,这对于按键比较紧张的FPGA来说很有用,但是是用sv写的,下面给出v的版本:


/*
! 模块功能: 消除按键抖动, 得到正确的按键输入的电平
* 思路:
  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 reg key_down,          // 按键按下
  input   key_in,   // 按键输入
  input   clk
);


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


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


reg auto_detection_success;
// 50ms计数器
localparam CNT_50MS_MAX = CLKFREQ * 1000 * INTI_MS;
reg [$clog2(CNT_50MS_MAX+1)-1 : 0] cnt_50ms;
always @(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@(*) begin
  if (cnt_50ms == CNT_50MS_MAX) // 按键信号从复位开始50ms内输入未发生变化
    auto_detection_success = 1'b1;
  else
    auto_detection_success = 1'b0;
end


reg auto_detection_success_r1;
always @(posedge clk) begin
  auto_detection_success_r1 <= auto_detection_success;
end
wire auto_detection_success_pedge;
assign auto_detection_success_pedge = auto_detection_success && ~auto_detection_success_r1;


reg key_up_value; // 存储按键未按下时的引脚电平
always @(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;
reg [$clog2(CNT_40MS_MAX+1)-1 : 0] key_down_cnt_40ms;
always @(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, 则认为键正常松开
reg [$clog2(CNT_40MS_MAX+1)-1 : 0] key_up_cnt_40ms;
always @(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 @(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



//-- 按键消抖 ------------------------------------------------------------


endmodule

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值