硬件按钮的中断和采样之间的区别?


8

我有一个连接到中断的硬件按钮,但是我的问题是它会弹起一点,使按钮按下不可靠。我认为可以通过在主循环中进行采样来解决很多这些问题,但这在技术上感觉是错误的。

中断是否更适合于电路内通信,或者中断也适合于硬件开关?如果可以,我可以使用哪些去抖动技术?

我尝试过保留计时器变量,并根据当前时间,延迟和其他技术对其进行检查。看来跳动是如此之快,没关系。



如果您在主循环中做出反应,则在主循环中采样没有任何问题。如果要异步响应,则中断更合适。有时候你会做,有时候你不会。
Eugene Ryabtsev

消除抖动的最佳方法是使用简单的低通滤波器。
lucas92

Answers:


8

防弹跳是一个常见问题。您应该能够找到...关于该主题的网页数量几乎不受限制。Smith也评论了Jack Ganssle在该主题上广泛阅读的PDF。通过所有这些答案,您可以获得硬件和软件方法。

我将主要通过谈论尚未很好涵盖的想法来补充这一“文学”。但在我这样做之前,有两点:

  1. 在模拟硬件中进行反跳可以实现您无法通过轮询或什至通过硬件引脚更改事件仅以数字方式“定期”观察到的开关所无法实现的结果。但是您可以以数字方式针对所有意图和目的“足够好”。如今,几乎没有人使用外部模拟去抖动解决方案。但是我使用了从单次脉冲拉伸(74121)到Jack Ganssle 此处提到的技术的所有方法。
  2. 对于那些只进行嵌入式编程而对学习电子产品完全不感兴趣的人来说,去抖动开关可能是所需的两个基本技能之一。运行LED可能是另一个。因此,我并不是说只有一种技能。我的意思是能够以多种方式做到这一点。所以,你真的需要全面缉拿什么杰克Ganssle写的,并且依然较多,对于开关。

由于我已经提到过使用74121进行脉冲拉伸并且杰克·甘斯尔(Jack Ganssle)尚未提及,这里也没有人提及,因此,我也可以提供此附加链接,作为使用74121或555作为单次拍摄的其他建议读物。跳动开关的计时器。


现在,通过使用微控制器观察来完成此操作。

我通常使用状态机来处理反跳。这几乎总是由我设置为大约的常规“心跳”计时器驱动的8多发性硬化症, 在可能的情况。(出于多种原因,我通常不使用边沿触发的中断事件。)

状态机如下所示:

原理图

模拟此电路 –使用CircuitLab创建的原理图

开关的DEBOUNCED值可以采用“无效”,“有效”和“未知”值。这样,您可以确保软件在初始化后一直等到开关值稳定下来。但是通常,我不会为此而烦恼。我将“未知”值替换为一些默认值,而只是使用二进制值系统。

通过首先将去抖动的值设置为其默认值,然后进入状态机的“ CHANGING”状态来进入状态机。在每个时间间隔(通常8多发性硬化症(如果可以解决),我将读取当前的开关值并执行当前状态的更新,并可能执行去抖动的值。然后我退出。然后,高级代码仅访问去抖动状态。

如果对我来说很重要,我可能还会保留先前的反跳状态。在这些情况下,当更新去抖动状态本身时,我将首先将该状态复制到“先前的去抖动状态”。然后,我可以使用一对值来确定是否存在去抖动的过渡。有时候,我不在乎过渡。有时候,我愿意。因此,这取决于。但是在所有情况下,我只想知道已消除抖动的过渡。我从不关心欠缺过渡。因此,高级代码绝不会使用状态机用于其自身工作的任何内部状态。

这种方法的优点之一是,我可以立即对整个交换机端口进行防抖动处理。而且我也可以在中断代码中没有任何分支的情况下进行操作。这意味着可以在微控制器的端口宽度(通常为8位宽)内进行非常短的快速反跳代码。AtmelAT90的示例显示了如何使用Timer0中断事件来实现:

.equ    SWPORTPINS  =   PINB
.def    SwRawCurr   =   r4
.def    SwRawPrev   =   r5
.def    SwState     =   r6
.def    SwDebCurr   =   r7
.def    SwDebPrev   =   r8

            ; Debounce the input switches.

                mov     SwRawPrev, SwRawCurr
                in      SwRawCurr, SWPORTPINS
                mov     Timer0Tmp1, SwRawCurr
                eor     Timer0Tmp1, SwRawPrev
                mov     Timer0Tmp0, Timer0Tmp1
                or      Timer0Tmp1, SwState
                mov     SwState, Timer0Tmp0
                mov     Timer0Tmp0, Timer0Tmp1
                com     Timer0Tmp0
                and     Timer0Tmp1, SwDebCurr
                and     Timer0Tmp0, SwRawCurr
                or      Timer0Tmp1, Timer0Tmp0
                mov     SwDebPrev, SwDebCurr
                mov     SwDebCurr, Timer0Tmp1

现在,此示例显示了全部交易,包括先前和当前去抖动的开关值。并且它还执行所有必要的状态转换。我没有显示此代码的初始化。但是,以上内容说明了状态机的操作有多容易,以及执行此操作所需的代码很少。它非常快速,简单,并且不需要分支(有时会涉及额外的循环以及额外的代码空间。)


我更喜欢使用 8多发性硬化症时机之久,是因为使用我过去使用过的设备与各种不同的人进行了长时间的测试,这使我进入了这一领域。我尝试了更长的时间,当我这样做时,我开始让人们告诉我,“响应能力”还不够“敏捷”。(近来,随着孩子们长大后从事实时的“射击游戏”游戏,我什至可能会进一步缩短游戏时间。他们会为现代数字电视在设置和显示框架时甚至略有延迟而苦苦抱怨。)

有些人会对系统应该有多清脆和反应灵敏。酥脆且反应迅速的采样方式更多而不是更少。但是我个人发现20多发性硬化症观察期可以接受。(我不是即使我找到更长的时间足够好,虽然)。

请注意,我提到的状态机必须先进入SETTLED状态,然后再停留一个采样时间,然后更新DEBOUNCED的值。因此,即使在最好的情况下,按下并按住按钮也将需要以下方向:

  1. 从已设置更改为更改
  2. 从CHANGING更改为SETTLED
  3. 待定,更新已取消

因此,一个新的去抖动状态至少需要3个采样时间周期才能实现。

一个按钮将需要至少6个采样时间才能从非活动状态变为活动状态,然后再回到活动状态。


我提到了上面的细节,因此绝对清楚 8多发性硬化症 表示它介于 16多发性硬化症<Ť24多发性硬化症从非活动状态变为公认的活动去抖动结果。这将需要另一个24多发性硬化症状态可以恢复为非活动状态。至少是40多发性硬化症<Ť48多发性硬化症 经历整个按钮循环。

使用更长的采样时间将相应地具有更长的时间。使用20多发性硬化症 我已经对我提到“可以接受”,那么就意味着 100多发性硬化症<Ť120多发性硬化症整个按钮周期。这正逐渐进入人们确实注意到的区域。我当然不喜欢这种“感觉”,甚至比它更长的时间。

如果您走这条路线,请不要因为使用更长的采样时间而变得更加谨慎。如果必须,那么我认为您还必须对用户/消费者进行大量测试。

而且,如果您正在开发用于打字键盘的代码,请使用更短的时间。打字员的记录是几十年前以217 wpm创下的。这导致大约每个键45多发性硬化症。像这样的打字员正在以受控的顺序敲击多个键。为了使使用汞润湿的簧片继电器开关系统的快速打字员获得良好的性能,我发现2多发性硬化症 运作良好。


弹跳时间从汞开关的0到微型触觉开关的“很少” ms典型值到笨拙的拨动开关的30ms不等,因此考虑到弹跳时间随老化而增加,8ms是一个很好的数字。
托尼·斯图尔特Sunnyskyguy EE75,2016年

@ TonyStewart.EEsince'75我选择使用带各种不同开关的设备与用户进行广泛的测试,而8 ms的数字来自所有工作的提炼。(由于构建和制造交换机的实践以及它们的种类繁多,使得对这些数据的收集和分析似乎令人生畏,因此我并不担心“理论”。)在可能的情况下,我总是使用8毫秒,因为看起来要甜蜜点给出的长期经验的写作软件,只是作品并在售后投诉到一个确切的零(在这一点上,反正。)
jonk

@ TonyStewart.EEsince'75顺便说一句,此测试包括使用汞润湿的簧片继电器作为键盘中使用的按键开关的一部分(我想似乎不再制造了。)在这些情况下,我要进行1-2毫秒的采样(具体取决于单位)
。–琼克

我之前提到的那种激光花园灯..具有触发时间短的触觉薄膜遥控器开关,但程序员使它们以10Hz的频率切换,因此必须在<100ms内释放它们,否则电源会开关。另请注意。Yamaha钢琴键盘非常快,支持10键翻转,而只有原始的IBM PC键盘才支持真正的前沿翻转。从那时起,所有键盘的第一个击键都是
先行先击

@ TonyStewart.EEsince'75此区域的开关采样是一个痛处。廉价的Micros的出现,带有零外部去抖动和应用了谁知道什么开关,加之于嵌入式程序员的无知,这意味着我实际上发现几乎所有带有键盘或按钮的单一嵌入式仪器都存在问题。在我的选择下,它们都非常糟糕。我认为这主要是因为程序员几乎没有经验,或者只是“谷歌搜索并应用它”而没有思考。有时,甚至用随机的轮询点加盐。是垃圾 镦。容易正确。
2016年

5

可以在软件中通过屏蔽IRQ来实现抖动时间,也可以在硬件中通过添加一个保持电容来实现抖动,其中RC = T>抖动时间在1到15ms之间,具体取决于开关的大小。

  • 例如,开关两端的100k上拉电阻和0.1μF= 50%Vdd时为10ms @ 63%或〜8ms,或者如果使用施密特触发器门@ 1.33V = Vil from 5V或〜73%V +〜12ms

4

要使SW反跳,请记录当前事件的时间戳并检查自上一个有效事件起的延迟:

#define DELAY_DEBOUNCE       150

uint32_t    __ts_lastpress = 0;

ISR(some_vector)
{
    uint32_t    now = millis(); // some timer tick counter

    if ( now - __ts_lastpress < DELAY_DEBOUNCE )
        return; // ignore it

    __ts_lastpress = now;
    // do the job here
}

UPD:只需进行少量修改即可注册双击:

#define DELAY_DEBOUNCE       150
#define DELAY_DOUBLE_CLICK   600

uint32_t    __ts_lastpress = 0;

ISR(some_vector)
{
    uint32_t    now = millis(); // some timer tick counter

    if ( now - __ts_lastpress < DELAY_DEBOUNCE )
        return; // ignore it

    // do the job here
    if ( now - __ts_lastpress < DELAY_DOUBLE_CLICK )
    {
        // it is double click
    }
    else
    {
        // it is single click
    }

    __ts_lastpress = now;
}

2

中断对于硬件开关也同样非常有用。通过使用中断,可以避免资源和能源的大量浪费,尤其是在处理电池供电的设备时。

另外,随着代码的变得越来越大,您会发现实现按钮的中断比在主循环中轮询按钮更容易。

至于防抖,可能是编码问题。我通常使用〜10ms计时器进行反跳,同时检查按钮的释放情况。确保在消除抖动时也暂时禁用按钮中断,以使中断例程不会执行多次。

如果仍有问题,请在此处发布代码,以便我们提供帮助。


1

这与Tony Stewart的《答案》非常相似,但我认为可以对其进行扩展。

最上面的原理图是针对低沿或下降沿的中断。底部的原理图用于高沿或上升沿的中断。

原理图

模拟此电路 –使用CircuitLab创建的原理图

就个人而言,考虑到电容器的成本,对我来说,简单地使用它是值得的,而不用担心我的软件防抖是否有问题。

请注意,正如托尼·斯图尔特(Tony Stewart)所说,此电路中的时间常数为10ms [RC 要么 10ķΩ1个μF。这将需要三到五个时间常数(具体取决于微控制器对按钮进行自我复位的敏感度,因此,如果微控制器在重复中断功能方面遇到问题,则可能是原因,因此您可能需要调整电容/电阻以使中断不会多次发生(也就是说,仅当您的中断被设置为在高或低信号上起作用,而不是在上升沿或下降沿起作用时)。

关于硬件反跳


1
两种版本均适用于+ ve或-ve沿,尤其是在中断引脚具有施密特风格的输入特性的情况下(很多这样做)。关闭时,SW1和SW2都会经历电流浪涌。某些碳素按钮可能会产生与金属弹片按钮不同的结果。
glen_geek

1

人类很慢,我们不需要立即注意微秒级范围内的微秒。

当然,这不是始终执行此操作的唯一方法,也不是正确的方法,但是我发现通常更明智的方法是设置一个计时器(许多微控制器具有sys ticks)以固定的间隔触发中断并将引脚的状态转换为a变量供以后检查代码。您最终会在弹跳时得到一个充满灰分的var

10010110灰

但在某些时间点上,您将获得以下4个值:
01111111上升沿仅
在稳定状态下反跳11111111按钮处于上升状态
10000000下降沿仅
在稳定状态下反弹了000000000按钮下降

不过,在大多数情况下,我只是使用一个在弹跳过程中重置的计数器。它快速,经过测试且易于执行。
如果失败,那么我尝试其他人建议的Ganssle文档中更明智的方法!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.