共计 2076 个字符,预计需要花费 6 分钟才能阅读完成。
背景痛点
在电机控制系统中,AB 相编码器是最常见的位置反馈元件。它通过两路相位差 90°的方波信号,不仅能测量转速和位置,还能判断旋转方向。但对新手来说,方向判断逻辑容易出错——信号抖动、相位关系理解偏差、高速漏脉冲等问题,经常导致电机失控。我曾在一个舵机项目里,因为方向误判导致电机反复震荡,烧毁了驱动芯片。

原理图解
理解方向判断的核心,是抓住 AB 两相的相位关系。想象两个正弦波,彼此错开 1 / 4 周期:
- 正转时序 :A 相上升沿时,B 相为低电平;A 相下降沿时,B 相为高电平
- 反转时序 :A 相上升沿时,B 相为高电平;A 相下降沿时,B 相为低电平
用示波器抓取信号时,正转的 AB 相信号像向右爬升的楼梯,反转则是向左下降的楼梯。这个特征就是方向判断的黄金法则。
硬件设计
STM32 定时器配置(以 TIM3 为例)
-
寄存器版配置 :
// 启用 TIM3 时钟 RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; // 配置编码器模式 3(双边沿计数)TIM3->SMCR |= TIM_SMCR_SMS_0 | TIM_SMCR_SMS_1; // 通道 1 / 2 输入滤波(4 个时钟周期)TIM3->CCMR1 |= (0x04 << 4) | (0x04 << 12); -
库函数版配置 :
TIM_Encoder_InitTypeDef encoder = { .EncoderMode = TIM_ENCODERMODE_TI12, .IC1Filter = 0x04, .IC2Filter = 0x04 }; HAL_TIM_Encoder_Init(&htim3, &encoder);
外围电路设计
- 上拉电阻 :通常选用 4.7kΩ,避免悬空时引入噪声
- RC 滤波 :信号线上串联 100Ω 电阻,并联 100pF 电容(截止频率≈16MHz)
- 布局要点 :AB 相走线等长,远离电机电源线
核心代码
方向检测状态机
// 防抖时间常数 = RC 时间常数 * 2(经验公式)#define DEBOUNCE_TICKS 5
typedef enum {
DIR_UNKNOWN,
DIR_CW, // 顺时针
DIR_CCW // 逆时针
} EncoderDir;
EncoderDir GetEncoderDirection(void) {
static uint8_t last_A = 0, last_B = 0;
static uint16_t debounce_cnt = 0;
uint8_t curr_A = HAL_GPIO_ReadPin(ENC_A_GPIO_Port, ENC_A_Pin);
uint8_t curr_B = HAL_GPIO_ReadPin(ENC_B_GPIO_Port, ENC_B_Pin);
// 边沿检测
if ((curr_A ^ last_A) || (curr_B ^ last_B)) {
debounce_cnt++;
if (debounce_cnt >= DEBOUNCE_TICKS) {if (curr_A && !last_B) return DIR_CW; // A 上升沿时 B 为低
if (!curr_A && last_B) return DIR_CCW; // A 下降沿时 B 为高
debounce_cnt = 0;
}
} else {debounce_cnt = 0;}
last_A = curr_A;
last_B = curr_B;
return DIR_UNKNOWN;
}
避坑指南
- 高速漏脉冲 :
- 现象:转速超过 1 / 4 采样频率时丢步
-
解决:改用硬件编码器接口(如 STM32 的 TIMx_ETR 引脚)
-
EMI 干扰 :
- 现象:长线传输时方向随机跳变
-
解决:改用差分信号(如 RS422 电平转换芯片)
-
电源噪声 :
- 现象:电机启停时误触发
- 解决:编码器电源加 π 型滤波(10μF+0.1μF 并联)
进阶优化:四倍频计数
通过检测 AB 相的上升 / 下降沿,可将分辨率提高 4 倍:
// 在定时器中断中实现
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {if (htim->Instance == TIM3) {
uint8_t A = ENC_A_GPIO_Port->IDR & ENC_A_Pin;
uint8_t B = ENC_B_GPIO_Port->IDR & ENC_B_Pin;
static uint8_t old_AB = 0;
uint8_t new_AB = (A << 1) | B;
// 状态变化查表(格雷码顺序)const int8_t quad_table[16] = {0,1,-1,0,-1,0,0,1,1,0,0,-1,0,-1,1,0};
position += quad_table[old_AB << 2 | new_AB];
old_AB = new_AB;
}
}
验证方法
用逻辑分析仪抓包时注意:
- 设置采样率≥10 倍编码器最高频率
- 添加 AB 相异或触发(XOR),便于捕捉方向变化
- 测量相位差时,用光标对齐过零点而非边沿
动手实验
建议用 STM32F103C8T6 核心板 +100 线编码器验证:
- 低速测试(<100RPM):观察方向判断是否稳定
- 快速正反转切换:检查状态机响应时间
- 用金属镊子触碰信号线,测试抗干扰能力
遇到问题时,先检查电源纹波(示波器 AC 耦合档),再逐个屏蔽噪声源。记住:稳定的方向检测,是运动控制的地基。
正文完
