电子产业一站式赋能平台

PCB联盟网

搜索
查看: 186|回复: 0
收起左侧

如何在单片机中消除按键抖动?

[复制链接]

1001

主题

1001

帖子

8805

积分

高级会员

Rank: 5Rank: 5

积分
8805
发表于 2024-11-1 08:01:00 | 显示全部楼层 |阅读模式

ricwnywzpoc64078634314.gif

ricwnywzpoc64078634314.gif

6 S' p/ p6 r4 j. m4 @: d点击上方蓝色字体,关注我们
! y0 l4 h, E+ y( E4 B9 ?, |# y' A在单片机(如STM32、AVR、PIC等)上处理按键输入时,按键抖动是常见的问题。
8 e0 M. N2 \/ c1 p' J4 l& W% {; O# T* |2 E! D/ @
按键抖动是指机械按键在按下或释放时,由于物理弹性会出现反复开闭,产生“抖动”,导致单片机在一个短时间内检测到多次按键变化,影响输入的可靠性。
8 K" L7 L$ Z4 d  n% Q, i
2 x' K( C$ G5 h# j9 V( C/ t+ ~

ibbup2uvscc64078634415.png

ibbup2uvscc64078634415.png

$ X0 q, `# ?/ j9 K8 ?% C/ [% J! j: P% ]( K! S" @7 }; Z0 e- U0 `
1
  _+ M  l: [/ Q1 w& Y为什么按键抖动会造成问题?
; [% _# s3 G. h( K按键抖动通常持续几毫秒(约5-20毫秒),在此期间按键的状态会在“高”与“低”电平之间多次跳变。如果不进行消抖处理,单片机在检测到按键被按下的瞬间可能会认为按键被多次按下,导致错误触发。
' Q. H2 D2 |+ }0 u9 Q5 F- `3 S& r/ ]! @, h( a7 g( j
例如:用户只按下一次按键,但由于抖动未被处理,可能会多次触发事件,尤其是在较高采样频率的系统中。# v! B: m+ r  }
26 w+ V1 G3 d$ {1 @  x
消除按键抖动的常见方法
) O. U9 K8 |4 r+ l8 H% h可以通过硬件或软件手段消除按键抖动。通常情况下,软件消抖更为灵活,硬件和软件消抖可以组合使用以提高可靠性。/ c2 p# u; ~/ w4 y

) X$ t4 _/ m& @  m3 c4 V' I硬件消抖
" Q3 l  G% @! q" g, t& U+ V' C7 ^硬件消抖通常通过加入电容和电阻组成RC滤波电路。RC电路的阻容时间常数可以缓解电平的快速跳变,使得按键在电平转变过程中更为平滑,减少抖动。+ Z% [' Z' u0 S( p# ^5 z
7 o: G% {7 F9 L* f

dgfqf5llsrm64078634515.jpg

dgfqf5llsrm64078634515.jpg
0 j" h1 a! E7 n
2 w& t8 W! t6 f! {# c  D
典型的电容值是0.1μF,电阻在10kΩ左右。这种方法在不增加处理器负担的情况下能够有效减少抖动,但增加了硬件成本。# P4 w' t3 D- ^) @  p$ T8 n8 n

) E  S4 d6 V- B' R; Q0 W. A软件消抖- ^3 q/ U9 {7 @. L
软件消抖通常有以下几种方法。( c' E4 c( p: M; ^$ _" S
1 S& d' E3 N) _1 ]7 G# c6 ~
延时法:在按键检测到一次变化后,直接延时一段时间(如20毫秒)再读取按键状态。这种方法简单,但会引入固定延迟,对实时性要求较高的系统可能会影响响应速度。" `( b  N; K& w* [4 `3 Z( a

& e' P. z& G# c2 B& s  v
  • int read_key_state() {    if (key_is_pressed()) {   // 检测到按键按下        delay_ms(20);         // 延时消抖        if (key_is_pressed()) // 再次确认按键状态            return 1;    }    return 0;}* {0 o. r1 k. l7 a, \6 j: y. A
    计数法:设定一个计数器并每次检测按键状态。当检测到按键状态持续相同多次(如连续检测到10次为按下),则确认按键按下并消除抖动。这种方法更适合于定时器中断方式。8 w! p& O( v% x- `8 ?+ {: W

    & N( p7 j, C3 G" ]2 c6 D8 u
  • int debounce_key() {    static int count = 0;    static int last_state = 0;    int current_state = key_is_pressed();& {& H' A7 z5 `4 H
        if (current_state == last_state) {        count++;        if (count >= 10) {  // 假设10次表示稳定状态            count = 0;            return current_state;        }    } else {        count = 0;    }    last_state = current_state;    return -1; // 表示不稳定,无法确认}
    % a( n4 X6 _4 D& o( j, Y0 X% k状态机法:使用状态机进行消抖,设置“未按下”、“按下确认”、“按下稳定”、“释放确认”等状态,并在每个状态下加入延时或计数逻辑。这种方法对复杂的按键输入情况非常有效,如长按、短按、连按等操作模式。
    + R, R# \" J+ _8 ?  `' G5 X
    + h3 i( [* L. f( ?/ f2 c5 h
  • typedef enum {    KEY_IDLE,    KEY_PRESS_DETECTED,    KEY_PRESSED_STABLE,    KEY_RELEASE_DETECTED} KeyState;% ?0 x# a8 W- x7 D/ E
    KeyState key_state = KEY_IDLE;int debounce_key_state() {    switch (key_state) {        case KEY_IDLE:            if (key_is_pressed()) {                key_state = KEY_PRESS_DETECTED;                delay_ms(5);            }            break;        case KEY_PRESS_DETECTED:            if (key_is_pressed()) {                key_state = KEY_PRESSED_STABLE;                return 1; // 确认按下            } else {                key_state = KEY_IDLE;            }            break;        case KEY_PRESSED_STABLE:            if (!key_is_pressed()) {                key_state = KEY_RELEASE_DETECTED;                delay_ms(5);            }            break;        case KEY_RELEASE_DETECTED:            if (!key_is_pressed()) {                key_state = KEY_IDLE;                return 0; // 确认释放            } else {                key_state = KEY_PRESSED_STABLE;            }            break;    }    return -1; // 状态不变}
    " f) s& \7 l! d3 M6 f( a, [定时器中断法:定时器中断法结合了硬件定时器和软件消抖的优点,通过定时器周期性地采样按键状态,并记录多个采样点的按键电平。如果某段时间内按键状态一致,则判断按键有效。这种方法不引入阻塞等待,对实时性要求较高的系统很合适。
    ! L- _9 Q2 Y9 s) w
    * X! V5 v6 t7 }% q- b% v( j
  • volatile int stable_key_state = -1;8 }8 s' a/ Z; u+ {4 Z% d
    void TIM_IRQHandler(void) {    static int last_state = 0;    static int debounce_count = 0;
    9 A' n. [6 x5 B( I/ L    int current_state = key_is_pressed();    if (current_state == last_state) {        debounce_count++;        if (debounce_count >= 10) {  // 假设10次为消抖稳定            stable_key_state = current_state;        }    } else {        debounce_count = 0;    }    last_state = current_state;}5 X. q1 s& J% K% L; P. Q5 s
    30 N) i7 `5 x4 y0 V
    综合消抖方案
    - f4 S5 I' H. `  H+ p在实际设计中,选择消抖方法时需要平衡实时性和稳定性,尤其是多按键或长按短按的情况下。组合硬件消抖和软件消抖可以提高按键的响应速度和可靠性。# p3 y9 y3 e2 A* t# _) V
    ( l3 g2 j6 @% n3 ]- B
    例如,可以通过硬件RC滤波先过滤大部分抖动,然后结合软件计数器或状态机法确认按键是否按下。
    ) J: ^) e- Z' z4 |! l4
    4 K9 H- I1 n- v. z9 M% F+ n按键消抖的应用场景
    0 j/ y% ]' e" a消抖在用户界面开发、工业控制、智能家居等按键较多的应用中非常关键。在带有多个按键或需要检测长按、连按等复杂输入的应用中,状态机或定时器法最适合。2 {* ~; l4 f7 K  F7 w3 P7 t

    8 k: l1 N5 n8 R1 \- y而在系统资源有限或要求简单按键检测的场景中,可以优先选择计数法或延时法。
    3 G0 [2 T# B# D* B  f5
    $ B9 V1 c9 D8 E7 r如何调试按键消抖?8 t, W$ z& K: _* H* P) g
    调试消抖算法可以通过以下方式:5 x. v" s! ^: C# ]5 W
  • 使用逻辑分析仪观察按键按下和释放时的电平变化,验证抖动消除效果。
  • 将每次按键检测到的状态变化通过串口或LED指示输出,便于观察实际检测效果。
  • 使用定时器记录按键状态变化时间,优化消抖算法的计时和延迟参数。
  • 通过适合的消抖方法,可以显著提高系统对按键输入的响应质量,减少误触发,提高用户体验。0 W3 \# ~& _  s+ e
    , H1 ]6 Z& L. s5 a4 z+ K
    8 a" y8 j3 x2 H& ~2 X+ `7 J& E

    edu5rwgoeas64078634615.jpg

    edu5rwgoeas64078634615.jpg
    & f3 o" f! {9 J

    vcqwrbcytwg64078634715.gif

    vcqwrbcytwg64078634715.gif

    4 E* U) U- c# k; ^6 [0 _点击阅读原文,更精彩~
  • 回复

    使用道具 举报

    发表回复

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则


    联系客服 关注微信 下载APP 返回顶部 返回列表