背景
在我们所使用的电子设备中,信号输入输出设备尤其多,除了机械按键,触摸按键外,旋钮的使用尤其多,这也就需要我们学习和了解旋钮工作的基本原理。
旋钮基本波形
下图是旋钮的基本波形。
通过观察波形,我们会发现,其实使用软件判断旋钮状态,可以使用非常简单的实现方式,即使用一个脚的边沿触发,在触发时判断两个管脚之间的电平关系,即可判断出旋钮的选装方向。
而在实际设计中,存在以下这几种情况:
部分旋钮使用全波逻辑,即每次旋钮旋转一格,示波器抓取的波形会出现一个完整的波形(两个管脚分别出现一次下降后上升的波形)
部分旋钮使用半波逻辑,即每次旋钮旋转一格,示波器抓取的波形会出现半个完整的波形(即若当前两个管脚电平都为低电平,则转动一格时两个脚都先后从低电平转向高电平;若当前两个管脚电平都为高电平,则转动一格时,两个脚的电平都先后从高电平转向低电平)
部分旋钮存在以下问题,旋转时某一相会出现波形丢失的情况(即转动一格时,某个脚的电平不会跟随变化)
设计代码时,需要根据旋钮的具体情况设计合适的实现代码。
旋钮实现代码
根据以上知识,出于旋钮逻辑实现理解的必要,以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相波形,同时检验是否丢失波形,若未丢失,则上报旋装状态消息。
验证效果
最终的验证效果与预期一致,丢失波形时仅影响丢失波形那格信号(这一次消息不上报应用),其他时候波形与预期一致。
总结
实际设计中,部分芯片硬件支持旋钮检测功能,但万变不离其踪,基本原理还是一样的,唯一的区别为中断消息少了一部分,对软件正常运行打断相对较少罢了。掌握了旋钮的基本原理,可以灵活选用不同的实现方式,在低消耗的情况下快速实现设计目标。