打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
【RISC-V MCU应用开发】详解EC11编码器高效驱动方法
userphoto

2023.09.27 河南

关注
旋转编码器是一种常用的旋转调整参数的元件,例如鼠标滚轮就是用的旋转编码器,今天给大家介绍一种旋转编码器——EC11

该元件外观与电位器很像,具备5个功能引脚,两个是开关,用于按键开关使用,另外三条引脚是用于旋转编码。

外观如下图所示:


引脚关系示意图如下:


在应用中,我们将D和E作为一个按键开关(非自锁)使用(想必这个大家都会,这里就不多说了)。

而作为编码器引脚的ACB三个引脚,中间的引脚通常接地,这样如果A和B通过上拉电阻拉高后,旋转旋钮,这个时候A和B会以相位差90°的方式交替且有重叠的去接触C。这个电路如下图所示,为了提高抗干扰能力,可以在A和B引脚分别使用一个0.1uF电容接地。


而A和B上的信号在时间刻度上如下图所示:


关键点:

当向着箭头方向旋转的时候我们发现:A在下降沿的时刻B是高电平,A在上升沿的时刻B是低电平,这可以表述为(A下B1,A上B0),记作表述1;

当方向取图中反向的时候,可以看出当A在下降沿的时刻B是低电平,A在上升沿的时刻B是高电平,这可以表述为(A下B0,A上B1),记作表述2。

因此,我们可以锁定A作为跳变沿检测中断引脚,在中断中记录下同一方向两个不同组合的状态,当完成一个完整的表述后我们就改变一次用于确定最终是否旋转的全局变量。

例如,我们定义一个全局变量flag用于告诉主函数是否发生了旋钮旋转;定义一个全局变量val,当正向旋转编码器发生一次咔哒声后,我们将val++;当反向旋转编码器发生一次咔哒声后,我们将val--操作一次。

这样为了记录下完整的表述1和表述2,我们定义两个全局变量flag1和flag2,当没有进入中断的时候,默认我们将其初始化为0,当发生了属性为“下1”的中断后,我们将flag1=1;当发生了属性为“下0”的操作后我们记录flag2=1;这样下次再次进入中断后那结果只能是对应的“上0”或“上1”,这个时候我们将对val进行操作,同时将flag1和flag2清零,并标记flag为1,这样我们可以在主函数识别出刚才发生了旋转操作,并在主函数中对其清零。

好了,思路有了,上程序的环节到了(此处代码,请点击文末“阅读原文”查看)

在写该程序之前,我阅读了网上大量的EC11的贴文和例子,并对部分进行了测试,有不少的代码无法准确识别出每一次旋动操作,或一次旋转导致了多次结果。另外一部分就是代码写的冗长复杂,因此,我在认真观察了手册的时序图后,决定重写这个代码,并分享出来。

实际测试电路如下:


串口打印内容如下:

  • 右旋


  • 左旋


该代码无需使用所谓的软件消抖操作,易于理解,移植方便,支持IO边沿跳变中断的单片机都可以使用。

以上简单的示例是为了讲明白旋转编码器在旋转过程中发生了什么,根据发生的具体物理事件中的某个完整周期事件实现旋转检测。在实际的应用中,我们可以将其作为一个头文件使用,并优化相关的变量名称,增加代码的可读性。

以下代码是我在ESP32上通过Arduino编写的相关代码,可供参靠,同时增加了旋转编码器上按键的示例,包含单击、长按,经过实际操作,发现编码器的按钮不适合双击和三连击。如果需要,可自行参靠长按的检测实现双击检测。


  • 头文件名称:EC11.h
#define EC11_A_PIN 0#define EC11_B_PIN 1#define BUTTON_PIN 2
bool R_Encoder_Left_Flag =false ; //定义用于旋转编码器的左旋标志变量bool R_Encoder_Right_Flag =false ; //定义用于旋转编码器的右旋标志变量#define EC11_LEFT_ACTIVE (-1) //定义变量R_Encoder_Active的向左旋转取值#define EC11_RIGHT_ACTIVE (1) //定义变量R_Encoder_Active的向右旋转取值int R_Encoder_Active =0 ; //定义用于旋转编码器的激活状态,如果为真认为发生了有效旋转,如果为-1则左旋,如果为1则右旋 <-----
bool Button_Flag =false ; //定义用于按键的标志变量bool Button_Active =false ; //定义用于按键的激活状态,如果为真(1)则认为发生了有效按键事件 <-----
bool Button_Falling_Flag =false; //标记按键被按下
unsigned long buttonPressStartTime =0; //用于记录按键被按下的时间点,在主函数中如果被按下还没抬起,可以读取当时的时间减去该标记时间,即可知道是否发生了长按事件 <-------
void ButtonHandleInterrupt(void){ if( digitalRead(BUTTON_PIN) == LOW ) //如果是下降沿,即为按键被按下 { Button_Flag = true;
buttonPressStartTime = millis(); Button_Falling_Flag = true; } else if( (digitalRead(BUTTON_PIN) == HIGH) && (Button_Flag == true) ) //如果是上升沿,按键被抬起 { if(millis()-buttonPressStartTime<1000)
Button_Active = true; Button_Flag = false; }}
/*在A:B上每次旋转发生了两组不同的电平跳变组合(L1->H0)、(L0->H1),其中L表示A的下降沿,H表示A的上升沿,1表示此刻B为高电平,0表示此刻B为低电平*/void EC11HandleInterrupt(void){ if ( digitalRead(EC11_A_PIN) == LOW ) { if( digitalRead(EC11_B_PIN) == HIGH ) { R_Encoder_Left_Flag =true; } else { R_Encoder_Right_Flag =true; } } else { if( (digitalRead(EC11_B_PIN) == LOW) && (R_Encoder_Left_Flag ==1) ) { R_Encoder_Left_Flag = false; R_Encoder_Active =EC11_LEFT_ACTIVE; } else if( (digitalRead(EC11_B_PIN) == HIGH) && (R_Encoder_Right_Flag ==1) ) { R_Encoder_Right_Flag = false; R_Encoder_Active =EC11_RIGHT_ACTIVE; } }}

void EC11_Init(void){ pinMode(EC11_A_PIN , INPUT_PULLUP); pinMode(EC11_B_PIN , INPUT_PULLUP); pinMode(BUTTON_PIN , INPUT_PULLUP); attachInterrupt(BUTTON_PIN,ButtonHandleInterrupt,CHANGE); attachInterrupt(EC11_A_PIN, EC11HandleInterrupt, CHANGE);}

  • 文件EC11_V3.ino


#include 'EC11.h'
//定义开发板载LED#define LED4 12#define LED5 13
int Mode = 0 ; //定义模式变量,用于标识出不同的模式int val =0; //测试打印用变量
void setup() { Serial.begin(115200); Serial1.begin(115200); Serial1.println('SERIAL-l'); pinMode(LED4 , OUTPUT); pinMode(LED5 , OUTPUT); EC11_Init(); Serial.println('--------------');}
void loop() {//检测是否发生了单击按键事件,即按下又松开 if(Button_Active == true) { Button_Active = false; Mode++; if(Mode > 3) Mode = 0; Serial.print('MODE:');Serial.println(Mode); digitalWrite(LED4,!digitalRead(LED4)); }
if(R_Encoder_Active !=0) { val=val+R_Encoder_Active; R_Encoder_Active =0; digitalWrite(LED5,!digitalRead(LED5)); Serial.print('Val= ');Serial.println(val); }//检测是否发生了长按事件 if(Button_Falling_Flag == true) { if(millis()-buttonPressStartTime>1000) { while( digitalRead(BUTTON_PIN) == LOW ) { val++;Serial.print('Val= ');Serial.println(val); delay(100); } Button_Falling_Flag = false; } }}
实际电路可以这样处理,预留抗干扰小电容焊盘,不一定使用。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
旋转编码器Arduino教程
Arduino关于旋转编码器程序的介绍
小车测速码盘读数请教(主要是想让小车走直线)?
旋转编码器EC11_支持长按、短按、双击、顺时针逆时针
STM32CubeMX EC11旋转编码器普通IO口外部中断+定时器实现
S7-1200 1500 指令说明DQ4_CAM 输出参数
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服