0.前言
EC11是一种常用的旋转编码器,在小型设备中用的很多。
网上有很多该旋转编码器的micropython版本驱动,但大多采用中断方式。在程序比较小时,中断方式还是可用的,但是如果程序逻辑比较复杂,采用中断方式就会带来程序时序逻辑控制困难等问题。
本文提供了一种采用周期扫描,而不是中断的驱动方式。
1.编码器简单介绍
![](https://img-blog.csdnimg.cn/img_convert/084123feb761fccb29b6ea59968edd0c.webp?x-oss-process=image/format,png)
![](https://img-blog.csdnimg.cn/img_convert/11d3b725978f9a5012fe09fb5eb64468.jpeg)
EC11的样子如图,共有5个脚,一侧3脚,一侧2脚。 2脚的一侧是可以按下的按钮,3脚的一侧是旋转编码脚。
使用时,把3脚侧的中间脚接地,两个边上的引脚一个取名为CLK,另一个取名为DATA,均用10k电阻上拉,并且并联一个104的电容对地消抖。2脚侧的其中1个脚接地,另一个取名叫KEY,同样加上拉和电容。电路如下:
![](https://img-blog.csdnimg.cn/img_convert/b337456817f5e5fd67f2c0c5e2ca8a37.png)
旋转时,其CLK和DAT脚输出时序如下:
![](https://img-blog.csdnimg.cn/img_convert/d6e2ba32de1fc7cfc98086be86bdd8fa.png)
2.驱动程序
驱动程序封装为一个单独文件,定义2个类:EC11Var和EC11Process。
EC11Var用于子线程与主程序间传递键值信息,EC11Process是扫描程序。
'''
EC11旋转编码器处理程序
By:fat0x 2023/3/17
旋转读取原理:
不断扫描CLK引脚状态,在CLK引脚下降沿读取DATA状态,从而判断旋转。
CLK和DATA并不严格区分,如果发现左右转反了,把线换一下或者调换本程序中EC11Value返回的2和3的位置即可
本程序采用扫描的方式来读取EC11的动作,并没有采取中断方式。原因是读取EC11的动作时耗时比较长(因为要做按键消抖)
几十毫秒的中断处理时间极有可能导致CPU因为WDT超时重启。
如果采取只在中断处理函数中置中断标志位,动作判断交给主程序的话,也会导致主程序运行不流畅,用户图形界面卡顿问题。
因此,本程序采用了多线程的方式,单独启动一个EC11动作扫描的进程,独立于主程序运行,并向主程序传递动作信息EC11Var.EC11Value。
主程序中不断判断EC11Var.EC11Value的值,并采取相应动作即可。
使用本类时注意:
1.要先定义一个EC11Var类实例,在定义EC11Process实例时
将其传递给EC11Process实例,用于EC11Process里向主程序传递按键和旋转信息;
2.按键定义:EC11Var.EC11Value=0时无动作,=1为按钮按下,=2为右旋转,=3为左旋转。
主程序处理按键的事务后,要将EC11Var.EC11Value重新赋值为0,否则将会重复进入按键处理。
见最后示例程序。
'''
from machine import Pin
import time,machine
import _thread
class EC11Var:
def __init__(self):
self.EC11Value=0x00
class EC11Process:
def __init__(self,pinNumClk,pinNumData,pinNumKey,insEC11Var):
self.ECPin_Clk = Pin(pinNumClk,Pin.IN,Pin.PULL_UP)
self.ECPin_Data = Pin(pinNumData, Pin.IN, Pin.PULL_UP)
self.ECPin_Key = Pin(pinNumKey, Pin.IN, Pin.PULL_UP)
self.insEC11Var=insEC11Var
def EC_ReadValue(self):
while True:
if self.ECPin_Key.value() == 0x00:
#先判断是否是按钮按下。如果是按下状态并有旋转动作,则只会处理按下动作,不会处理旋转动作
#一般人也不会采取这种非常规的动作....
#print("key pressed!")
time.sleep_ms(50)#延时消抖
if self.ECPin_Key.value() != 0x00:
print("EC11按键-抖动")
return
i=1000000
while(self.ECPin_Key.value()==0 and i>0):
#等待引脚返回高电平(按钮释放)
#同时防止旋转按钮卡住或不到位导致程序卡死
i-=1
if i==0:
print("EC11按键-卡涩超时")
self.insEC11Var.EC11Value=0x00
self.insEC11Var.EC11Value=0x01
#print(self.clsEC11Value.EC11Value)
return
elif self.ECPin_Clk.value() == 0x00:
if self.ECPin_Clk.value() != 0x00:#重复检测一次防抖
print("EC11旋转-抖动")
return
if self.ECPin_Data.value()==0:
#print("EC11右转!")
self.insEC11Var.EC11Value=0x03
elif self.ECPin_Data.value()==1:
#print("EC11左转")
self.insEC11Var.EC11Value=0x02
else:
print("EC11旋转-检测错误!")
i=1000000
while((self.ECPin_Data.value()==0 and i>0) or (self.ECPin_Clk.value()==0 and i>0)):
#等待CLK和DATA引脚都返回高电平,才是旋转一格结束
#同时防止旋转按钮卡住或不到位导致程序卡死
i-=1
if i==0:
print("EC11旋转-卡涩超时")
self.insEC11Var.EC11Value=0x00
'''
以下是示例程序
'''
#示例程序先在主程序前定义EC11扫描的线程程序
def thread_EC_ReadValue(insEC11Process):
while True:
insEC11Process.EC_ReadValue()
if __name__ == "__main__":
insEC11Var =EC11Var()
insEC11Process =EC11Process(18,19,23,insEC11Var)#Pin18=clk,19=data,23=key
print("EC11示例程序启动...")
PerPwrPin=Pin(25,Pin.OUT)#开启EC11电源,你的板子如果没有电源控制,删掉即可
PerPwrPin(1)
_thread.start_new_thread(thread_EC_ReadValue,(insEC11Process,))#启动EC11扫描程序
while True:
if insEC11Var.EC11Value!=0x00:
print("insEC11Var.EC11Value=",insEC11Var.EC11Value)
insEC11Var.EC11Value=0