共计 2045 个字符,预计需要花费 6 分钟才能阅读完成。
1. 旋转编码器基础认知
增量式编码器 就像自行车码表:通过两个相位差 90°的脉冲信号(A/ B 相)判断转动方向和步数。常见 EC11 型号每圈产生 20 个脉冲(PPR=20),这意味着每个脉冲对应 18°的机械旋转。

- AB 相信号特点:
- 顺时针旋转时 A 相领先 B 相 90°
- 逆时针时 B 相领先 A 相
- 信号抖动通常在 5 -10ms 内(机械触点特性)
2. 硬件连接实战
使用 EC11 编码器与 Arduino Uno 的典型连接方案:
EC11 引脚 → Arduino 引脚
CLK → D2(中断 0)DT → D3(中断 1)SW → D4(按钮功能)+ → 5V
GND → GND
关键细节:
- 必须添加 10KΩ 上拉电阻(内部上拉可能不够稳定)
- 信号线并联 0.1μF 电容可减少高频干扰
- 长导线传输时应采用双绞线
3. 核心代码实现
3.1 中断服务程序(ISR)
#include <Arduino.h>
volatile int counter = 0;
volatile bool lastCLK;
void setup() {pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
attachInterrupt(0, encoderISR, CHANGE);
Serial.begin(115200);
lastCLK = digitalRead(2);
}
void encoderISR() {bool currentCLK = digitalRead(2);
if(currentCLK != lastCLK) {
// 状态变化时检测 DT 电平判断方向
if(digitalRead(3) != currentCLK) {counter++;} else {counter--;}
lastCLK = currentCLK;
}
}
3.2 消抖处理方案对比
| 方法 | 响应速度 | CPU 占用 | 实现复杂度 |
|---|---|---|---|
| 硬件 RC 滤波 | 中 | 低 | 简单 |
| 软件延时法 | 慢 | 中 | 简单 |
| 状态机实现 | 快 | 低 | 中等 |
推荐的状态机消抖实现:
enum {STATE_STABLE, STATE_CHANGED, STATE_DEBOUNCE};
byte encoderState = STATE_STABLE;
void checkEncoder() {
static unsigned long lastTime;
bool current = digitalRead(2);
switch(encoderState) {
case STATE_STABLE:
if(current != lastCLK) {encoderState = STATE_CHANGED;}
break;
case STATE_CHANGED:
if(millis() - lastTime > 5) { // 5ms 消抖窗口
encoderState = STATE_DEBOUNCE;
}
break;
case STATE_DEBOUNCE:
if(current == digitalRead(2)) { // 确认稳定状态
// 执行计数逻辑
encoderState = STATE_STABLE;
}
lastTime = millis();
break;
}
}
4. 进阶技巧
4.1 四倍频计数
通过检测 A / B 相的上升沿和下降沿,可将分辨率提高 4 倍:
void encoderISR() {
static byte oldAB = 0;
oldAB <<= 2; // 移位保留历史状态
oldAB |= (digitalRead(2) | (digitalRead(3) << 1));
// 状态变化表:0b00011101 → 有效脉冲模式
if((oldAB & 0x0F) == 0x0D) counter++;
if((oldAB & 0x0F) == 0x07) counter--;
}
4.2 定时器中断优化
对于高速旋转场景(>300RPM),建议使用 Timer1 定时采样:
#include <TimerOne.h>
void setup() {Timer1.initialize(1000); // 1ms 采样周期
Timer1.attachInterrupt(encoderSampler);
}
void encoderSampler() {
static byte lastState;
byte currentState = digitalRead(2) | (digitalRead(3) << 1);
// 格雷码状态转换检测
if((lastState == 0 && currentState == 2) ||
(lastState == 2 && currentState == 3) ||
(lastState == 3 && currentState == 1) ||
(lastState == 1 && currentState == 0)) {counter++;}
// 反向转换检测代码略...
lastState = currentState;
}
5. 实践练习题
- 速度计算功能:扩展代码使其能计算并串口输出转速(RPM)
- 按键复合功能:实现长按 3 秒重置计数器功能
- EEPROM 存储:每次重启后能恢复上次的计数值
调试建议:
– 使用逻辑分析仪观察 AB 相信号时序
– 在 ISR 内添加 digitalWrite(13, !digitalRead(13))可视化中断触发
– 通过串口绘图仪观察计数器变化曲线
正文完
