背景
在我们所使用的电子设备中,信号输入输出设备尤其多,除了机械按键,触摸按键外,旋钮的使用尤其多,这也就需要我们学习和了解旋钮工作的基本原理。
旋钮基本波形
下图是旋钮的基本波形。
通过观察波形,我们会发现,其实使用软件判断旋钮状态,可以使用非常简单的实现方式,即使用一个脚的边沿触发,在触发时判断两个管脚之间的电平关系,即可判断出旋钮的选装方向。
而在实际设计中,存在以下这几种情况:
部分旋钮使用全波逻辑,即每次旋钮旋转一格,示波器抓取的波形会出现一个完整的波形(两个管脚分别出现一次下降后上升的波形)
部分旋钮使用半波逻辑,即每次旋钮旋转一格,示波器抓取的波形会出现半个完整的波形(即若当前两个管脚电平都为低电平,则转动一格时两个脚都先后从低电平转向高电平;若当前两个管脚电平都为高电平,则转动一格时,两个脚的电平都先后从高电平转向低电平)
部分旋钮存在以下问题,旋转时某一相会出现波形丢失的情况(即转动一格时,某个脚的电平不会跟随变化)
设计代码时,需要根据旋钮的具体情况设计合适的实现代码。
旋钮实现代码
根据以上知识,出于旋钮逻辑实现理解的必要,以c类情况为例,设计如下代码:
#define ENCODE_PORT GPIO2
#define ENCODE_A_PIN 7U
#define ENCODE_B_PIN 9U
// 其中,lwrb_write为向应用发送旋钮旋转事件的入口
void GPIO2_GPIO_COMB_0_15_IRQHANDLER(void) {
BaseType_t pxHigherPriorityTaskWoken = pdFALSE;
msg_buffer send_data;
static uint8_t firstKeyDetect;
if (GPIO_GetPinsInterruptFlags(ENCODE_PORT) & (1U << ENCODE_A_PIN)) {
/* clear the interrupt status */
GPIO_PortClearInterruptFlags(ENCODE_PORT, 1U << ENCODE_A_PIN);
/* Change state of switch. */
if (GPIO_PinRead(ENCODE_PORT, ENCODE_A_PIN)) { // Rising edge
if (GPIO_PinRead(ENCODE_PORT, ENCODE_B_PIN) && (firstKeyDetect == ROTARY_LEFT)) {
send_data.type = ROTARY_LEFT;
lwrb_write(&msg, &send_data, sizeof(msg_buffer));
} else if (!GPIO_PinRead(ENCODE_PORT, ENCODE_B_PIN) && (firstKeyDetect == ROTARY_RIGHT)) {
send_data.type = ROTARY_RIGHT;
lwrb_write(&msg, &send_data, sizeof(msg_buffer));
}
} else { // Falling edge
if (GPIO_PinRead(ENCODE_PORT, ENCODE_B_PIN)) {
firstKeyDetect = ROTARY_RIGHT;
} else {
firstKeyDetect = ROTARY_LEFT;
}
}
}
SDK_ISR_EXIT_BARRIER;
}代码设计思路:由于所使用的旋钮B相概率性的丢失波形,由于该波形为无效波形,且丢失波形无规律,无法在丢失波形的情况下仍然向应用上报正确的旋转方向,因此代码层面仅能实现屏蔽该种波形的逻辑。由于该旋钮为全波旋钮,因此我在不丢波形的A相上注册GPIO边沿触发中断,在该脚下降沿中断时读取B相电平,此时记录估计的正反旋标记,之后在该脚上升沿中断时检测B相波形,同时检验是否丢失波形,若未丢失,则上报旋装状态消息。
验证效果
最终的验证效果与预期一致,丢失波形时仅影响丢失波形那格信号(这一次消息不上报应用),其他时候波形与预期一致。
总结
实际设计中,部分芯片硬件支持旋钮检测功能,但万变不离其踪,基本原理还是一样的,唯一的区别为中断消息少了一部分,对软件正常运行打断相对较少罢了。掌握了旋钮的基本原理,可以灵活选用不同的实现方式,在低消耗的情况下快速实现设计目标。
我要赚赏金
