0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

小编科普几种按键消抖电路的设计方案

Matin88 来源:人工智能科学与技术 2023-02-10 11:06 次阅读

数字电路中,开关用于用于产生高、低电平,按键用于产生单次脉冲。由于开关和按键为机械部件,每次按下或者释放时,由于簧片的弹性会产生短暂的抖动,然后才能稳定接通或者断开。

抖动现象会导致按键电路的输出产生毛刺,如图1所示,从而可能导致系统产生误动作。

开关和按键的抖动时间一般在20ms以内。为了防止因按键抖动引起的系统误动作,必须对按键电路进行消抖,只在按键闭合或者断开稳定后才允许输出。

940bd1ac-a8db-11ed-bfe3-dac502259ad0.png

图1按键抖动现象

按键消抖有软件消抖和硬件消抖两类方法。软件消抖是在嵌入式系统中,检测到按键按下时,应用软件延时20ms后再次检测按键的状态,如果两次状态相同,则确认按键已经按下。

这种处理方式虽然简单,但是会浪费CPU资源。

硬件消抖有多种方法。第一种方法是应用施密特电路的回差特性配合积分电路实现按键消抖,应用电路如图2所示。

9425e3e4-a8db-11ed-bfe3-dac502259ad0.png

图2应用积分电路实现按键消抖

第二种方法是应用锁存器的保持功能实现开关消抖,应用电路如图3所示。

94476258-a8db-11ed-bfe3-dac502259ad0.png

图3应用锁存器实现开关消抖

除了上述两种按键消抖方法外,在基于FPGA的数字系统设计中,也可以应用状态机设计按键消抖电路,在FPGA内部实现。

基于状态机设计按键消抖电路时,需要将按键的一次动作分解为:按下前、按下时、稳定期和释放时4个状态,如图1中所示,分别用KEY_IDLE、KEY_PRESSED、KEY_ACTIVE和KEY_RELEASE表示。

设按键输入用key_in表示,低电平有效,设计消抖时间为20ms,则按键消抖状态机的状态转换关系如图4所示。

9456a9ca-a8db-11ed-bfe3-dac502259ad0.png

图4按键消抖状态机

根据上述状态转换关系,描述按键消抖模块的Verilog HDL代码参考如下:

module KEY_debounce #(parameter DEBOUNCE_TIME = 1000_000 )( 
  // 50MHz时钟时,对应消抖时间为20ms
input clk_50,                         // 50MHz时钟,周期为20ns
      input rst_n,                          // 复位信号
      input key_in,                         // 按键输入
      output reg key_out  // 消抖后输出
      );
      // 内部状态定义,循环编码方式
      localparam KEY_IDLE    = 2'b00,     // 按下前
                   KEY_PRESSED = 2'b01,    // 按下时
                   KEY_ACTIVE  = 2'b11,    // 稳定期
                   KEY_RELEASE = 2'b10;    // 释放时
      // 内部变量定义          
      reg [19:0] debounce_cnt;                // 消抖计数变量
      reg [1:0]  current_state,next_state;  // 现态和次态
      reg [0:1]  keytmp;                        // 同步寄存器
      // 内部线网定义 
      wire cnt_en,cnt_end;                     // 计数允许和停止计数标志
      wire cnt_flag;                            // 消抖计数标志
      wire release_flag;                       // 按键释放标志
      // 允许消抖计数逻辑:按键按下时或者释放时,cnt_en有效。
assign cnt_en = current_state == KEY_PRESSED 
|| current_state == KEY_RELEASE;
      // 停止计数标志:cnt_en有效并且debounce_cnt达到最大值,则cnt_end有效。
       assign cnt_end = cnt_en && ( debounce_cnt == DEBOUNCE_TIME - 1 );
      // 正在计数标志:cnt_en有效并且debounce_cnt未达到最大值,则cnt_flag有效。
      assign cnt_flag = cnt_en && ( debounce_cnt < DEBOUNCE_TIME );
      // 按键已释放标志: cnt_end有效,并且keytmp[1]为高电平,则release_flag有效。
      assign release_flag = cnt_end && keytmp[1];
      // 按键输入两级同步寄存过程,以消除亚稳态。
      always @(posedge clk_50 or negedge rst_n)
         if ( !rst_n ) 
            keytmp <= 2'b00;                         // 清零
         else 
            keytmp[0:1] <= {key_in,keytmp[0]};   // 右移  
      // 时序逻辑过程,描述状态转换
      always @(posedge clk_50 or negedge rst_n) 
         if ( !rst_n )
             current_state <= KEY_IDLE;
         else 
             current_state <= next_state;
      // 组合逻辑过程,定义次态 
      always @(*)  begin
         case ( current_state )
             KEY_IDLE: if ( !keytmp[1] ) // 按键按下时,进入KEY_PRESSED
                            next_state = KEY_PRESSED;
                          else                // 否则,保持KEY_IDLE
                            next_state = current_state; 
             KEY_PRESSED: if ( cnt_end && !keytmp[1] ) 
// 消抖时间到且keytmp[1]为0,确认按下有效
                                 next_state = KEY_ACTIVE;
                             else if ( cnt_flag && keytmp[1] ) 
// 正在计数,但keytmp[1]为1,则为抖动
                                       next_state = KEY_IDLE;
else  // 否则状态保持
                                       next_state = current_state; 
             KEY_ACTIVE: if ( keytmp[1] ) // keytmp[1]跳变为1则进入释放状态
                               next_state = KEY_RELEASE;
                            else 
                               next_state = current_state; // 否则状态保持
             KEY_RELEASE: if ( release_flag ) // 按键已释放,返回
                                next_state = KEY_IDLE;  
                             else if ( cnt_flag && !keytmp[1] )
                                      // 正在计数,但keytmp[1]为0,则为抖动
                                      next_state = KEY_ACTIVE;  
                                   else  // 否则状态保持
                                      next_state = current_state;
                 default:  next_state = KEY_IDLE;
         endcase
      end
      // 时序逻辑过程,消抖计时
      always @( posedge clk_50 or negedge rst_n ) 
         if ( !rst_n )
             debounce_cnt <= 20'b0;
         else if ( cnt_en )       // 计数允许信号有效
                  if ( cnt_end )    // 消抖时间到
                     debounce_cnt <= 20'b0;
                  else             // 消抖时间未到
                     debounce_cnt <= debounce_cnt + 1'b1;
                else                // 计数允许信号无效
                   debounce_cnt <= 20'b0;
// 时序逻辑过程,按键消抖后输出
      always @( posedge clk_50 or negedge rst_n ) 
         if ( !rst_n )
             key_out <= 1'b1;   
         else 
             case ( current_state )
                KEY_IDLE   :     key_out <= 1'b1;
KEY_PRESSED:   key_out <= 1'b1;
KEY_ACTIVE :    key_out <= 1'b0; 
KEY_RELEASE:   key_out <= 1'b0;
default:  key_out <= 1'b1;
             endcase
endmodule

对上述代码进行仿真验证时,需要建立testbench文件,应用系统函数$random产生随机数,以模拟不规则的抖动脉冲间隔。

应用系统函数$random产生随机整数的语法格式为

num = $random%b
其中b为十进制整数,num为-(b-1) ~ (b-1)范围内的随机整数。 应用系统函数$random产生随机正整数的语法格式为
num ={$random}%b
其中b为十进制整数,num为0 ~ (b-1)范围内的随机整数。 测试按键消抖模块功能的testbench代码参考如下:
`timescale 1ns/1ps
module KEY_debounce_vlg_tst();
     reg  clk;
     reg  rst_n;
     reg  key_in;
     wire key_out;
     // 模块参数重定义,减少计数容量,以缩短仿真时间
     defparam KEY_debounce.DEBOUNCE_TIME = 50000;
// 内部变量定义
     reg [15:0] rand_num;
     // 仿真参数定义
     parameter RESET_TIME = 2, STEP = 5;
     // 按键消抖模块例化 
     KEY_debounce i1
        ( .clk      (clk),
          .rst_n    (rst_n),
          .key_in   (key_in),
          .key_out (key_out));
     // 设置复位信号波形 
   initial begin
        rst_n = 1;
        #1;
        rst_n = 0;
        #(STEP * RESET_TIME);
        rst_n = 1;
     end
     // 设置按键输入 
     initial begin
        #1; key_in = 1;                  //按下前
        #(STEP * 10); press_key;       // 第1次按键过程
        #10_000;       press_key;       // 第2次按键过程
     end
     // 设置时钟信号  
     initial clk_50 = 0;
     always  #(STEP/2) clk_50 = ~clk_50;
     // 监测任务
         initial                             
        $monitor($time,"clk_50=%b rst_n=%b key_in=%b key_out=%b",
clk_50,rst_n,key_in,key_out); 
     // 按键任务定义 
     task press_key;
        begin
          repeat (20) begin // 模拟前沿抖动过程
            rand_num = {$random}%5000;
            #rand_num key_in = ~key_in;
            end
          key_in = 0;
          #300_000;
          repeat (20) begin  // 模拟后沿抖动过程
            rand_num = {$random}%5000;
            #rand_num key_in = ~key_in;
            end
          key_in = 1;
          #300_000;
       end
     endtask
 endmodule

上述代码中使用了defparam语句用于对KEY_debounce模块中的DEBOUNCE_TIME参数进行重定义,在确保功能验证的前提下缩短消抖时间。启动modelsim进行仿真,结果如图5所示。

947c8636-a8db-11ed-bfe3-dac502259ad0.png

图5按键消抖模块仿真波形

从波形图中可以看出,消抖电路对按键按下和释放产生的4次抖动都能实现有效消抖,因此验证基于状态机设计的按键消抖模块功能正确。






审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FPGA
    +关注

    关注

    1628

    文章

    21722

    浏览量

    602879
  • 锁存器
    +关注

    关注

    8

    文章

    905

    浏览量

    41491
  • 数字电路
    +关注

    关注

    193

    文章

    1605

    浏览量

    80570
  • 状态机
    +关注

    关注

    2

    文章

    492

    浏览量

    27522
  • 按键消抖
    +关注

    关注

    2

    文章

    27

    浏览量

    10448

原文标题:按键消抖电路的几种设计方案

文章出处:【微信号:LowHuangMakerSpace,微信公众号:LowHuangMakerSpace】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    按键的硬件电路原理详解

    按键通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也
    的头像 发表于 02-02 09:42 9483次阅读
    <b class='flag-5'>按键</b>的硬件<b class='flag-5'>消</b><b class='flag-5'>抖</b><b class='flag-5'>电路</b>原理详解

    单片机的按键几种按键电路

    按键电路 一、 硬件按键电路控制
    的头像 发表于 12-17 07:45 10.6w次阅读
    单片机的<b class='flag-5'>按键</b><b class='flag-5'>消</b><b class='flag-5'>抖</b>与<b class='flag-5'>几种</b><b class='flag-5'>按键</b><b class='flag-5'>电路</b>

    按键电路的实现方式

    按键通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也
    的头像 发表于 08-29 11:25 4619次阅读

    按键

    请问大家的按键是用什么方法解决的,如普通的按键如何
    发表于 09-26 22:17

    技术分享:明德扬按键的原理和基于fpga的设计

    本帖最后由 明德扬吴老师 于 2017-8-2 11:45 编辑 按键1功能概述按键开关是各种电子设备不可或缺的人机接口,如电脑的键盘等。实际应用中,
    发表于 08-02 10:38

    请问怎样去设计一种按键电路

    按键电路结构与电路模型按键
    发表于 04-29 06:13

    按键代码方法有哪几种

    按键原理一、首先来回顾一下按键延时按键由于是
    发表于 07-14 06:21

    如何去消除K1-K3的按键问题?有哪几种方法?

    按键的实验原理是什么?如何去消除K1-K3的按键问题?有哪几种
    发表于 07-14 06:35

    MCU按键问题

    按键问题机械按键是必须的,1、延时
    发表于 11-04 06:37

    STM32单片机按键和FPGA按键的相关资料分享

    写在前面:STM32单片机按键和FPGA按键大全按键
    发表于 01-18 06:39

    基于FPGA的按键电路设计

    采用了VHDL语言编程的设计方法,通过FPGA来实现按键的硬件电路。论述了基于计数器、RS触发器和状态机3种方法来实现按键
    发表于 12-05 14:13 224次下载

    VHDL—按键

    按键检测需要,一般有硬件和软件两种方式。硬件就是加去抖动电路,这样从根本上解决按键抖动问题。除了用专用
    发表于 11-11 17:17 2次下载

    51单片机的独立按键按键及矩阵按键电路与程序免费下载

    本文档的主要内容详细介绍的是51单片机的独立按键按键及矩阵按键电路与程序免费下载。
    发表于 07-26 17:36 28次下载
    51单片机的独立<b class='flag-5'>按键</b>和<b class='flag-5'>按键</b><b class='flag-5'>消</b><b class='flag-5'>抖</b>及矩阵<b class='flag-5'>按键</b>的<b class='flag-5'>电路</b>与程序免费下载

    为什么要进行按键

    按键通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也
    的头像 发表于 04-19 14:55 1w次阅读

    按键的软件和硬件方法

    采用锅仔片式按键测量波形。按键按下与抬起的部分都出现抖动,大致时间10ms左右。为了防止按键误按或者重复识别,必须要按键
    的头像 发表于 03-01 10:53 1.4w次阅读
    <b class='flag-5'>按键</b><b class='flag-5'>消</b><b class='flag-5'>抖</b>的软件和硬件方法