1、旋转编码器
旋转编码器是一种输入设备,通常用于测量和控制旋转运动。它由一个旋转轴和一系列编码器组成。旋转编码器可以根据旋转轴的位置和方向来测量旋转角度,并将其转化为电子信号输出。
旋转编码器通常分为两种类型:绝对值编码器和增量值编码器。
绝对值编码器可以直接输出旋转轴的绝对位置,无需进行位置复位。它通常使用一组二进制编码来表示不同的位置。绝对值编码器具有高精度和高分辨率,适用于需要准确度较高的应用。
增量值编码器则根据旋转轴的运动方向和速度来输出增量值。它通常包含两个输出信号,一个输出脉冲信号用于计数旋转轴的步数,另一个输出方向信号用于指示旋转方向。增量值编码器相对较简单,成本较低,适用于一般的旋转控制应用。
旋转编码器广泛应用于各种领域,如机械加工、机器人控制、汽车导航等。它可以实现精确的角度测量和控制,提高系统的精度和稳定性。
2、EnCode11
EC11旋转编码器广泛用于车载DVD,车载导航,汽车影音上常被人称为车载编码器。编码器主要用于频率调节,高度调节温度调节及音量调节的参数控制。
EC11旋转编码器通常具有两个正交的输出信号(A相和B相),通过检测这两个信号的变化来确定旋转的方向和步长。它还可能具有一个开关信号输出,用于表示按压旋钮的操作。
EC11旋转编码器的工作原理是通过编码盘上的凹槽和接触触点的接触来感知旋转运动。当旋转编码器旋转时,凹槽和接触触点之间的接触状态会不断变化,从而产生相应的输出信号。
总而言之,EC11旋转编码器是一种常见的用于测量和控制旋转运动的输入设备,具有防尘、防水和耐用的设计,适用于各种工业和消费电子应用。
上面2种旋转编码器实际上是一种,就是引脚编号不同,具体对应关系如下。
GND:接地连接。
VCC(+):正电源电压,额定电压5伏。
SW:按钮开关的输出(低电平有效)。当按下旋钮时,电压变低。
DT(输出 B):与CLK输出类似,但滞后于CLK 90°相移。该输出用于确定旋转方向。
CLK(输出A):用于确定旋转量的主要输出脉冲。每次仅通过一个制动装置(咔嗒声)向任一方向转动旋钮时,“CLK”输出就会经历一个先高后低的周期。
3、EC11工作原理
丝印上显示“CLK”、“DT”、“SW”、“+”、“GND”这类是Arduino的编码器,我多说一段话,做个笔记,就是介绍下Arduino,Arduino是一个开源电子平台,它起源于意大利,主要用于简化原型设计和物联网(IoT)项目的创建。Arduino板通常包括微控制器、输入/输出端口以及用于连接各种传感器和设备的插槽。用户可以通过编写简单的基于文本的程序,也就是称为“sketches”的,利用 Ardunio IDE(集成开发环境)来控制硬件。
Arduino的魅力在于其易学性,即使是缺乏专业电路知识的人也能快速上手。它广泛应用于教育、艺术、自动化、家居自动化等领域,支持各种扩展模块,如WiFi、蓝牙等,使得项目具备无线通信功能。通过Arduino,人们可以轻松地将物理世界与数字世界连接起来。
实际上我们树莓派+Python也可以,能比Arduino难不倒哪去,有机会我们也玩玩Arduino的ESP32。言归正传,“CLK”、“DT”:在该模块上显示的丝印名称为这两个,不明白为什么是这个丝印,应该实际对应于编码器常用的“A”、“B”信号吧,这两个信号的发生方式如下:
正旋:如上图当旋钮开始正向旋转时,“A”从低电平变为高电平,“B”保持不变;当旋钮旋转到预定位置时,“A”维持为高电平,“B”然后跟着从低电平跳变到高电平。也就是说,正旋时,“A”总是先与“B”开始电平变化。
反旋:与正旋相反,“B”总是先与“A”开始电平变化。
4、EC11与树莓派连接
VCC:5V
GND:GND
A:GPIO19(BOARD35)
B:GPIO26(BOARD37)
C:GPIO21(BOARD40)
旋转编码器有2个动作,一个是旋转,包括顺时针旋转和逆时针旋转。另一个是按下,车载收音机旋钮也有这个按下的动作,有的是作为退出键,这个按下的输入检测到低电平,可自行定义功能。
但是我这款EC11ABC的C引脚,用万用表测试按下无法产生低电平,令大家失望了,看来这个C引脚硬件内部没有实现按下接地的逻辑,我们用一个按键来模拟即可。
5、实验代码与现象
顺时针旋转编码器,计数值增加,OLED屏上面显示该数值。逆时针旋转编码器,计数值减少。
同时可根据这个计数值改变LED灯的亮暗,注意占空比的范围是(0-100),而编码器的值是(-无穷至+无穷),同学们可以思考下,如何做一个数学函数,将其映射过去。代码有点BUG,我就不改了。
import RPi.GPIO as GPIO
import time
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
import RPi.GPIO as GPIO
import luma.oled as oled
from luma.core.interface.serial import i2c
from luma.oled.device import ssd1306
from luma.core.render import canvasWIDTH=128
HEIGHT=64 PWM_LED = 11
RoAPin = 35 # 旋转编码器CLK管脚
RoBPin = 37 # 旋转编码器DT管脚
BtnPin = 13 # 旋转编码器SW管脚
#global globalCounter
globalCounter = 0 # 计数器值flag = 0 # 是否发生旋转标志位
Last_RoB_Status = 0 # DT 状态
Current_RoB_Status = 0 # CLK 状态# 初始化工作
def setup():GPIO.setmode(GPIO.BOARD) # 采用实际的物理管脚给GPIO口GPIO.setwarnings(False) # 忽略GPIO操作注意警告GPIO.setup(PWM_LED, GPIO.OUT)GPIO.setup(RoAPin, GPIO.IN) # 旋转编码器CLK管脚,设置为输入模式GPIO.setup(RoBPin, GPIO.IN) # 旋转编码器DT管脚,设置为输入模式GPIO.setup(BtnPin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # 设置BtnPin管脚为输入模式,上拉至高电平(3.3V)def load_device():# 创建I2C接口对象 serial = i2c(port=1, address=0x3C) # 地址可能因显示屏型号而异,由命令行“sudo i2cdetect -y 1”得到# 创建OLED设备对象 device = ssd1306(serial, WIDTH, HEIGHT) return device# 旋转编码方向位判断函数
def rotaryDeal():global flag # 是否发生旋转标志位global Last_RoB_Statusglobal Current_RoB_Statusglobal globalCounter # 计数器值pwm = GPIO.PWM(PWM_LED, 80)pwm.start(0)if GPIO.input(BtnPin)==GPIO.HIGH:Last_RoB_Status = GPIO.input(RoBPin)while(not GPIO.input(RoAPin)): # 判断CLK管脚的电平变化来区分方向Current_RoB_Status = GPIO.input(RoBPin)flag = 1 # 发生旋转标记if flag == 1: # 标记位为1 发生了旋转flag = 0 # 复位标记位if (Last_RoB_Status == 0) and (Current_RoB_Status == 1):globalCounter = globalCounter - 1 # 逆时针方向,负if (Last_RoB_Status == 1) and (Current_RoB_Status == 0):globalCounter = globalCounter + 1 # 顺时针方向,正print(globalCounter)with canvas(device) as draw:draw.rectangle(device.bounding_box, outline=0, fill=0)draw.text((0,0), "当前计数值为:",font=font, fill='white')draw.text((20,20), str(globalCounter), font=font, fill="white")PwmCounter=int(abs(globalCounter)/255*100)for i in range(0, PwmCounter, 1):# 更改占空比,pwm.ChangeDutyCycle(i)time.sleep(0.02) else:globalCounter = 0with canvas(device) as draw:draw.rectangle(device.bounding_box, outline=0, fill=0)draw.text((0,0), "当前计数值为:",font=font, fill='white')draw.text((20,20), str(globalCounter), font=font, fill="white")print('计数值已经回零!')# 中断函数,当SW管脚为0,使能中断
def btnISR():global globalCounterwhile True:if GPIO.input(BtnPin)==GPIO.LOW:time.sleep(0.2)if GPIO.input(BtnPin)==GPIO.LOW:print('Button pressed.')globalCounter = 0 # 给计数器赋print(globalCounter)break# 循环函数
def loop():global globalCounter tmp = 0 # 当前状态判断while True:rotaryDeal() # 旋转编码方向位判断函数if tmp != globalCounter: # 判断状态值发生改变print ('globalCounter = %d' % globalCounter) # 打印出状态信息tmp = globalCounter # 把当前状态赋值到下一个状态,避免重复打印# 释放资源
def destroy():GPIO.cleanup() # 释放资源# 程序入口
if __name__ == '__main__': global devicedevice = load_device() font = ImageFont.truetype('STKAITI.TTF',17)setup() # 调用初始化工作try:loop() # 调用循环函数except KeyboardInterrupt: # 当按下Ctrl+C时,将执行destroy()子程序。destroy()
这个代码有点长,后面再介绍传感器的综合实验还是减少点内容,不然代码过于冗长。一般做嵌入式开发,按键LED显示屏这三个是必备的输入输出设备。
旋转编码器