我正在构建一个键盘,一些固件在用 C 语言编程的无线模块上运行。我正在尝试推出自己的去抖动算法,并且需要一些帮助。本质上,代码的布局如下:
#define DEBOUNCE 5
- 这个值可以是从 1(不建议,不是真正的反跳)到无穷大(同样不建议,原因显而易见)之间的任何值。我用它来消除 32 个按钮的抖动,因此接下来我使用以下方法创建一个 32 位整数数组:
static uint32_t key_integration[DEBOUNCE];
在每次扫描输入(1KHz 轮询率)时,我将数组的倒数第二个项目移至最后一个,将倒数第三个移至倒数第二个,依此类推,直到我最终将按键的原始扫描输入到第 0 个数组项中。 (附带问题:比仅仅从 0 迭代到 DEBOUNCE-2 的循环更简单的方法?如果我有一个 (32*DEBOUNCE) 位整数,我只会使用按位移位,但是......无论如何。)
现在是我遇到困难的棘手部分:将数组结果与当前(去抖)键状态进行比较。本质上,如果 key_integration int 的位 X 为 1 是所有数组,我想将其与当前(去抖)键状态进行异或以查看它是否已更改。如果 key_integration int 的每一位 X 在所有数组中都是 0,我想做同样的事情。如果位 X 在数组中分散为 1 和 0,则它仍然是去抖的,不需要进行比较。
我目前对如何将 key_integration 数组与去抖键状态 int 进行比较感到困惑。我真的很感激关于如何 A)比较它们,或 B)重构代码以更简单的方式实现相同结果的建议。我绝对无法相信我所想到的是最好的方法。
最佳答案
您可以相当轻松地计算其键始终为零或始终为一的掩码(伪代码)
alwaysZ = -1
alwaysO = -1
for (int i = 0; i < DEBOUNCE; i++)
alwaysZ &= ~keys[i]
alwaysO &= keys[i]
这样就可以非常简单地确定哪些键保持不变(但处于任一极性):stable = alwaysZ |总是O
尽管这需要在每个轮询时刻重新计算,但这是可以避免的。显然,当且仅当设置第 i 位的次数为 0 或 DEBOUNCE
(可能 DEBOUNCE - 1
,取决于您定义该常量的含义,但重点是它将是 0 或“所有内容”)。因此,这里有一个替代方案:保留一个计数数组,用于计算每个按钮在整个防抖窗口中处于按下状态的次数。为每个当前按下的按钮加一,为每个按下的按钮减一 DEBOUNCE
步入过去。
通过计数数组,您可以判断每个按钮在恒定时间内是否稳定,而与去抖量无关。缺点是,您必须明确检查每个计数,而使用位掩码您可以立即确定任何按钮是否稳定,然后提前退出。
对于附带问题,可以使用标准circular buffer避免移动数据本身的技术,只是通过调整索引来虚拟地移动数据。但这也不是免费的,对于 DEBOUNCE=5 我不会这样做。由于开销是恒定的,因此它可以很好地扩展到巨大的去抖值。您通常可以避免进行实际的模运算,因为您只是递增索引(因此,如果到达末尾,您可以递增并返回到 0),而不是随机索引到缓冲区的中间。
关于c - 按位积分去抖动运算符混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45383814/