从“光耦”到“编码器”:用几块钱的槽型模块给Arduino Uno做个低成本旋转编码器
用槽型光耦打造低成本旋转编码器:Arduino Uno的创意实践
在创客和电子爱好者的世界里,成本往往是一个无法回避的现实问题。当我们需要为Arduino项目添加旋转编码器功能时,商业编码器的价格可能让预算有限的爱好者望而却步。但你知道吗?只需几块钱的槽型光耦模块,加上一些巧妙的硬件布局和软件逻辑,就能实现旋转方向检测、角度测量等基本编码器功能。
1. 槽型光耦模块的工作原理与选择
槽型光耦(Slot-Type Photo Interrupter)是一种常见的光电传感器,由红外发光二极管和光电晶体管组成,中间有一个物理槽口。当槽口被物体遮挡时,光电晶体管接收不到红外光,输出状态发生变化;当槽口畅通时,红外光能够到达接收端,输出另一种状态。
常见槽型光耦模块特性对比:
| 型号 | 槽宽 | 工作电压 | 输出类型 | 响应时间 | 典型应用 |
|---|---|---|---|---|---|
| FTR9606 | 5mm | 3.3-5V | 数字开关量 | 3μs | 转速检测、位置限位 |
| ITR9608 | 8mm | 3-5V | 数字开关量 | 4μs | 物体检测、计数器 |
| GP1A57HR | 3mm | 4.5-16V | 集电极开路 | 5μs | 打印机、复印机 |
提示:选择槽型光耦时,槽宽应与你的码盘厚度匹配,太窄可能导致安装困难,太宽可能影响检测精度。
这些模块通常具有以下特点:
- 采用LM393等比较器芯片,输出干净的数字信号
- 带有状态指示灯,直观显示检测状态
- 工作电压兼容3.3V和5V系统
- 提供M3安装孔,便于固定
2. 从单光耦到旋转编码器的设计思路
商业旋转编码器通常采用两个光电传感器以一定角度排列,通过检测两个信号相位差来判断旋转方向。我们可以用两个槽型光耦模块模拟这种结构。
实现方案对比:
-
双模块方案:
- 使用两个独立的槽型光耦模块
- 物理排列成90度相位差
- 需要精确的机械安装
-
单模块+特殊码盘方案:
- 使用一个槽型光耦模块
- 设计特殊开槽的码盘(如不等距开槽)
- 通过检测脉冲间隔判断方向
双模块安装要点:
- 两个模块间隔1/4码盘周期
- 确保码盘与模块间距离适当(通常1-3mm)
- 使用支架固定,避免振动影响
// 双模块引脚定义
#define ENCODER_A 2 // 连接到第一个光耦模块
#define ENCODER_B 3 // 连接到第二个光耦模块
volatile int encoderPos = 0;
int lastEncoded = 0;
void setup() {
pinMode(ENCODER_A, INPUT_PULLUP);
pinMode(ENCODER_B, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(ENCODER_A), updateEncoder, CHANGE);
attachInterrupt(digitalPinToInterrupt(ENCODER_B), updateEncoder, CHANGE);
}
void updateEncoder() {
int MSB = digitalRead(ENCODER_A);
int LSB = digitalRead(ENCODER_B);
int encoded = (MSB << 1) | LSB;
int sum = (lastEncoded << 2) | encoded;
if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderPos++;
if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderPos--;
lastEncoded = encoded;
}
3. 码盘设计与制作技巧
码盘是旋转编码器的核心部件,其设计直接影响检测精度和可靠性。对于DIY项目,我们可以用多种材料制作码盘。
常见码盘材料对比:
| 材料 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| PCB | 精度高、耐用 | 需要专业制板 | 长期使用项目 |
| 亚克力 | 易加工、美观 | 易刮花 | 展示项目 |
| 卡纸 | 成本低、易制作 | 不耐用 | 原型验证 |
码盘设计参数:
- 开槽数量:通常20-60个,越多分辨率越高
- 开槽宽度:与光耦槽宽匹配,通常1-3mm
- 开槽间距:与开槽宽度相同或略大
- 直径:根据应用需求,通常30-100mm
注意:码盘开槽应均匀分布,边缘清晰,避免毛刺影响检测。可以使用激光切割或3D打印获得更高精度。
制作步骤:
- 使用CAD软件设计码盘图案
- 选择合适的材料
- 使用激光切割机或手工切割
- 测试码盘与光耦的配合效果
- 调整开槽参数优化性能
4. 信号处理与抗干扰设计
槽型光耦输出的信号可能包含抖动和噪声,需要进行适当的处理才能获得稳定的旋转检测。
常见问题及解决方案:
-
信号抖动:
- 硬件:增加RC滤波电路(如10kΩ电阻+0.1μF电容)
- 软件:实现消抖算法(如延时检测)
-
误触发:
- 调整光耦与码盘的距离
- 优化码盘开槽设计
- 增加环境光屏蔽
-
方向误判:
- 检查两个光耦的安装位置
- 验证相位差是否为90度
- 调整软件判断逻辑
// 带消抖的编码器读取代码
#define DEBOUNCE_TIME 5 // 消抖时间(ms)
unsigned long lastA = 0;
unsigned long lastB = 0;
void updateEncoder() {
unsigned long now = millis();
int A = digitalRead(ENCODER_A);
int B = digitalRead(ENCODER_B);
// A通道消抖
if(A != lastAState) {
lastA = now;
}
if((now - lastA) > DEBOUNCE_TIME) {
if(A != lastAState) {
lastAState = A;
// 处理A通道变化
}
}
// B通道消抖同理
// ...
}
5. 应用实例:自制音量控制旋钮
将DIY旋转编码器应用于实际项目,我们可以创建一个低成本但功能完善的音量控制旋钮。
所需材料:
- Arduino Uno开发板
- 两个槽型光耦模块(如FTR9606)
- 自制码盘(直径50mm,20开槽)
- 旋钮帽
- 3D打印或激光切割的支架
实现步骤:
- 组装编码器部件,确保码盘能顺畅旋转
- 连接光耦模块到Arduino(A通道到D2,B通道到D3)
- 上传编码器检测程序
- 添加音量控制功能代码
- 通过USB或蓝牙连接电脑/手机
#include <Keyboard.h> // 用于模拟键盘音量控制
void setup() {
Keyboard.begin();
// 编码器初始化代码...
}
void loop() {
static int lastPos = 0;
if(encoderPos != lastPos) {
int delta = encoderPos - lastPos;
if(delta > 0) {
Keyboard.write(KEY_MEDIA_VOLUME_UP);
} else {
Keyboard.write(KEY_MEDIA_VOLUME_DOWN);
}
lastPos = encoderPos;
}
}
性能优化技巧:
- 使用中断而非轮询检测信号变化
- 优化码盘开槽数量与系统响应速度的平衡
- 考虑使用硬件计数器(如Arduino的PCINT)提高性能
- 添加加速度检测,实现快速旋转时音量变化加速
6. 进阶应用与扩展思路
掌握了基本原理后,这种低成本编码器方案可以扩展到更多创意应用中。
扩展应用场景:
- 电机控制系统:检测电机转速和方向
- DIY MIDI控制器:音乐制作设备的参数调节
- 菜单导航界面:旋转选择+按下确认的操作方式
- 机器人关节反馈:监测关节旋转位置
性能提升方向:
-
分辨率提升:
- 增加码盘开槽数量
- 使用更高精度的光耦
- 采用四倍频计数技术
-
可靠性改进:
- 添加冗余检测通道
- 实现自动校准功能
- 增加温度补偿
-
多功能集成:
- 结合按键功能(按下旋钮)
- 添加RGB指示灯反馈
- 集成无线传输模块
// 四倍频计数实现(提高分辨率)
void updateEncoder() {
int A = digitalRead(ENCODER_A);
int B = digitalRead(ENCODER_B);
int currentState = (A << 1) | B;
int prevState = lastEncoded & 0b11;
if(currentState != prevState) {
int change = (prevState << 2) | currentState;
if(change == 0b0001 || change == 0b0111 || change == 0b1110 || change == 0b1000) {
encoderPos++;
} else if(change == 0b0010 || change == 0b1011 || change == 0b1101 || change == 0b0100) {
encoderPos--;
}
lastEncoded = (lastEncoded << 2) | currentState;
}
}
在实际项目中,我发现机械安装的精度对系统性能影响很大。使用3D打印的支架固定光耦模块,比手工用热熔胶固定能获得更稳定的检测结果。另外,码盘材料的透光性也需要考虑——完全不透明的材料比半透明材料能提供更清晰的信号边缘。
更多推荐



所有评论(0)