共计 1942 个字符,预计需要花费 5 分钟才能阅读完成。
增量式编码器基础认知
ABZ 编码器(Quadrature Encoder)是工业运动控制中的 ” 眼睛 ”,通过两路相位差 90°的方波信号(A/ B 相)和零位信号(Z 相)反馈机械位置。实际项目中常遇到:

- 信号抖动 :电机启停时因振动导致边沿畸变(示波器可见毛刺)
- 高速漏脉冲 :2000RPM 以上时,MCU 可能丢失沿跳变事件
- 电磁干扰 :变频器附近出现信号幅值衰减或相位失真
三大解算方案对比
- 查表法 (适合低速场景)
- 优点:代码简单,仅需 4 ×4 状态转移表
-
缺点:无法处理 AB 同时跳变的异常情况
// 典型状态转移表 const int8_t state_table[4][4] = {{0, +1, -1, 0}, // 前一状态 00 {-1, 0, 0, +1}, // 前一状态 01 {+1, 0, 0, -1}, // 前一状态 10 {0, -1, +1, 0} // 前一状态 11 }; -
状态机法 (平衡方案)
- 优点:可识别非法状态(如 00→11 跳变)
-
缺点:需要严格时序约束(检测窗口<1/ 4 信号周期)
-
硬件计数器法 (推荐方案)
- 利用 STM32 定时器的 Encoder Mode,TI1/TI2 引脚自动计数
- 典型配置代码:
// GPIO 初始化(以 TIM3 为例)GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7; // PA6/PA7 GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; GPIO_InitStructure.Pull = GPIO_PULLUP; // 关键!启用上拉 HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); // 定时器编码器模式配置 TIM_Encoder_InitTypeDef encoder_config = {0}; encoder_config.EncoderMode = TIM_ENCODERMODE_TI12; // 双沿计数 encoder_config.IC1Polarity = TIM_ICPOLARITY_RISING; encoder_config.IC2Polarity = TIM_ICPOLARITY_RISING; HAL_TIM_Encoder_Init(&htim3, &encoder_config); HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);
抗干扰实战技巧
硬件设计要点
- 双绞线传输 :A/ B 信号线必须双绞(Z 相可单走),实测可降低 30% 辐射干扰
- 终端匹配电阻 :根据传输线特征阻抗选择,常用 120Ω 端接(电缆阻抗典型值)
- 施密特触发器 :信号入口处增加 SN74LVC1G17 等器件整形
软件滤波方案
对于 1MHz 高速信号,推荐移动平均窗口滤波:
#define FILTER_WINDOW_SIZE 5
int32_t filter_buffer[FILTER_WINDOW_SIZE] = {0};
int32_t moving_average(int32_t new_val) {
static uint8_t idx = 0;
filter_buffer[idx++] = new_val;
if(idx >= FILTER_WINDOW_SIZE) idx = 0;
int64_t sum = 0;
for(uint8_t i=0; i<FILTER_WINDOW_SIZE; i++) {sum += filter_buffer[i];
}
return (int32_t)(sum / FILTER_WINDOW_SIZE);
}
Z 相归零扩展应用
实现多圈绝对位置需结合 Z 相信号:
- 在 Z 相下降沿触发中断,读取当前计数器值
- 校验位置是否在±1LSB 误差范围内(应对干扰导致的误触发)
- 圈数计数器增减需与 A / B 相方向关联:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {if(GPIO_Pin == Z_PIN_PIN) {
int16_t cnt = TIM3->CNT;
if(abs(cnt) < 2) { // 有效零位附近
__disable_irq(); // 进入临界区
if(TIM3->CR1 & TIM_CR1_DIR) total_turns--;
else total_turns++;
__enable_irq();}
}
}
实测数据对比
在 1.5 米电缆传输环境下,不同方案的误码率:
| 方案 | 500RPM 误码率 | 3000RPM 误码率 |
|---|---|---|
| 纯软件查表法 | 0.1% | 4.7% |
| 硬件计数 + 滤波 | <0.01% | 0.2% |
避坑清单
- 致命错误 :未启用 GPIO 内部上拉导致悬空状态跳变
- 时序陷阱 :中断服务函数超过 1μs 执行时间引发脉冲丢失
- 隐式 BUG:圈数计数器未使用 volatile 声明导致数据不同步
通过本文介绍的方法,我们在 AGV 小车项目中将位置检测误差控制在±0.5mm 内(对应 1000 线编码器)。希望这些实战经验能帮助开发者少走弯路。
正文完
