共计 1867 个字符,预计需要花费 5 分钟才能阅读完成。
增量式编码器基础
增量式编码器通过 A / B 两相正交脉冲信号输出旋转信息,每转产生固定数量的脉冲。其核心优势在于:

- 实时反馈机械位置变化
- 通过脉冲相位差判定旋转方向(A 相领先为顺时针)
- 成本低廉且分辨率可调(200-6000PPR 常见)
典型应用场景包括:
- 伺服电机位置闭环控制
- 数控机床进给量检测
- 工业仪表旋钮输入
开发者常见痛点
实际项目中主要存在三类问题:
- 机械抖动 :触点振动导致单次物理转动产生多个脉冲
-
测试数据:未处理时抖动脉冲宽度约 50-200μs
-
脉冲丢失 :高速旋转时 MCU 未能及时响应边沿
-
典型案例:12MHz 晶振下,5000RPM 电机脉冲间隔仅 40μs
-
方向误判 :A/ B 相时序解析错误导致计数反向
- 根本原因:信号边沿采样时机不当
硬件设计优化
推荐滤波电路
[编码器] --10kΩ--+--||--- MCU_GPIO
| 100nF
GND
- 截止频率计算:fc=1/(2πRC)≈160Hz
- 实测可滤除 >95% 的抖动噪声
- 注意:电阻值过大会降低信号上升速度
软件实现方案
中断服务程序(Keil C51)
// 端口定义
#define ENC_A P3_2 // INT0
#define ENC_B P3_3
volatile long encoder_count = 0;
void EXT0_ISR() interrupt 0 {
static unsigned char last_state;
unsigned char new_state = (ENC_A << 1) | ENC_B;
// 状态机实现正交解码
switch(last_state) {case 0x00: if(new_state == 0x02) encoder_count++;
else if(new_state == 0x01) encoder_count--; break;
case 0x01: if(new_state == 0x00) encoder_count++;
else if(new_state == 0x03) encoder_count--; break;
case 0x02: if(new_state == 0x03) encoder_count++;
else if(new_state == 0x00) encoder_count--; break;
case 0x03: if(new_state == 0x01) encoder_count++;
else if(new_state == 0x02) encoder_count--; break;
}
last_state = new_state;
}
关键点说明:
- 使用状态机而非简单边沿检测,避免方向误判
- volatile 修饰确保编译器不优化计数器变量
- 4 个完整状态切换才完成 1 个计数周期
消抖算法优化
对比三种方案性能:
| 方法 | 响应延迟 | 资源占用 |
|---|---|---|
| 纯硬件滤波 | 1ms | 低 |
| 软件延时 10μs | 可变 | 中 |
| 状态机 + 时间戳 | <50μs | 较高 |
推荐组合方案:
// 在中断中添加时间戳检查
static unsigned long last_time;
if((TIMER0 - last_time) > 100) { // 100 timer ticks 阈值
// 执行正常解码逻辑
last_time = TIMER0;
}
工程级注意事项
中断配置要点
- 设置 IT0=1(下降沿触发)
- 优先级寄存器 IP 中 PX0=1(高于定时器中断)
- 总中断 EA 尽早开启
32 位计数器处理
// 读取时关闭中断保证原子性
long get_encoder() {
long val;
EA = 0;
val = encoder_count;
EA = 1;
return val;
}
PCB 布局建议
- 编码器信号线走等长差分对
- 靠近 MCU 放置 0.1μF 去耦电容
- 避免与 PWM 信号平行走线
移植到 ARM 平台
STM32 移植关键修改:
- 启用硬件编码器接口(TIMx_CR1 SMS=3)
- 利用 32 位定时器自动计数
- 通过 DMA 传输计数值降低 CPU 负载
示例配置代码:
// STM32CubeMX 生成代码片段
TIM_Encoder_InitTypeDef config = {
.EncoderMode = TIM_ENCODERMODE_TI12,
.IC1Polarity = TIM_ICPOLARITY_RISING,
.IC2Polarity = TIM_ICPOLARITY_RISING
};
HAL_TIM_Encoder_Init(&htim2, &config);
__HAL_TIM_SET_COUNTER(&htim2, 0);
HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_ALL);
通过本文方案,实测在 1000RPM 转速下可实现±1 个脉冲的误差控制,满足大多数工业场景需求。实际项目中还需根据具体编码器 PPR 值和机械特性调整参数。
正文完
