c - 按位积分去抖动运算符混淆

标签 c arrays embedded bit-manipulation debouncing

我正在构建一个键盘,一些固件在用 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/

相关文章:

javascript - 运行前判断数据是否是新的(比较数组和JSON)

c++数组赋值多个值

c - 如何使用RL_ARM lib来设计TCP项目

programming-languages - F35 Lightning II飞机使用的主要编程语言是什么?

c - 为什么我的 C 程序在这里打印 0.000000?

c - kernel.h中min宏中 "(void) (&_min1 == &_min2)"的作用是什么?

c - Netfilter 内核模块拦截数据包并记录它们

c - 结构体和字符串

java - 在java中每行10个整数之后开始新行的更有效方法是什么?

embedded - 有人在嵌入式项目中使用 Scheme/LISP 吗?