ABZ编码器解析:线与四倍频的技术原理与工程实践

1次阅读
没有评论

共计 2813 个字符,预计需要花费 8 分钟才能阅读完成。

image.webp

ABZ 编码器解析:线与四倍频的技术原理与工程实践

背景痛点:为什么我们需要四倍频?

旋转编码器在工业控制领域扮演着至关重要的角色,从数控机床到机器人关节,它们负责将机械运动转化为电信号。但原始 AB 相脉冲存在一个明显问题——分辨率不足。

ABZ 编码器解析:线与四倍频的技术原理与工程实践

  • 原始信号限制 :标准正交编码器每转仅产生固定数量的脉冲(如 1000 线编码器每转产生 1000 个 A 相和 1000 个 B 相脉冲)。
  • 高精度需求 :现代运动控制系统往往要求亚微米级定位精度,这就需要对原始信号进行倍频处理。

技术对比:2 倍频 vs 4 倍频

2 倍频方案

  • 优点
  • 实现简单,仅需检测单相信号的边沿
  • 对 MCU 资源要求低
  • 缺点
  • 分辨率提升有限(仅 2 倍)
  • 无法利用正交信号的全部信息

4 倍频方案

  • 优点
  • 最大程度利用正交信号(分辨率提升 4 倍)
  • 提高抗干扰能力(通过状态校验)
  • 缺点
  • 需要更复杂的处理逻辑
  • 对 MCU 性能要求更高

核心原理:正交编码与四倍频

正交编码相位关系

 A 相: __|¯¯|__|¯¯|__
B 相: ¯¯|__|¯¯|__|¯¯(超前 90°相位差)

四倍频状态转换

  1. A 上升沿 + B 低电平 :正向计数 +1
  2. B 上升沿 + A 高电平 :正向计数 +1
  3. A 下降沿 + B 高电平 :正向计数 +1
  4. B 下降沿 + A 低电平 :正向计数 +1
    (反向运动时对应状态减 1)

代码实现:STM32 硬件接口配置

定时器编码器模式初始化

// GPIO 配置(以 TIM3 为例)GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7; // PA6(A), PA7(B)
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

// 定时器编码器模式配置
TIM_Encoder_InitTypeDef sConfig = {0};
TIM_HandleTypeDef htim3;
htim3.Instance = TIM3;
htim3.Init.Prescaler = 0;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 0xFFFF;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
sConfig.EncoderMode = TIM_ENCODERMODE_TI12; // 双通道模式
sConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
sConfig.IC1Filter = 0x0F; // 数字滤波
// 重复上述配置 IC2...
HAL_TIM_Encoder_Init(&htim3, &sConfig);
HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);

软件四倍频状态机

// 状态变量定义
typedef enum {
    STATE_0 = 0, // A=0,B=0
    STATE_1,     // A=0,B=1
    STATE_2,     // A=1,B=1
    STATE_3      // A=1,B=0
} EncoderState;

EncoderState prevState = STATE_0;
int32_t pulseCount = 0;

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {uint8_t currA = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6);
    uint8_t currB = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7);
    EncoderState currState = (currA << 1) | currB;

    switch(prevState) {
        case STATE_0:
            if(currState == STATE_1) pulseCount--;
            else if(currState == STATE_3) pulseCount++;
            break;
        case STATE_1:
            if(currState == STATE_2) pulseCount--;
            else if(currState == STATE_0) pulseCount++;
            break;
        case STATE_2:
            if(currState == STATE_3) pulseCount--;
            else if(currState == STATE_1) pulseCount++;
            break;
        case STATE_3:
            if(currState == STATE_0) pulseCount--;
            else if(currState == STATE_2) pulseCount++;
            break;
    }
    prevState = currState;
}

避坑指南:工程实践要点

机械抖动消除

  • 数字滤波 :配置定时器输入捕获滤波(见 IC1Filter 参数)
  • 软件消抖 :连续采样三次确认稳定状态
    #define DEBOUNCE_SAMPLES 3
    uint8_t stableRead(uint16_t pin) {uint8_t samples[DEBOUNCE_SAMPLES];
        for(int i=0; i<DEBOUNCE_SAMPLES; i++) {samples[i] = HAL_GPIO_ReadPin(GPIOA, pin);
            delay_us(10);
        }
        // 取多数一致值
        return (samples[0]+samples[1]+samples[2]) > DEBOUNCE_SAMPLES/2;
    }

临界区保护

  • 关闭中断 :在读写全局计数变量时禁用中断
  • 原子操作 :使用__LDREX/__STREX 指令(Cortex-M)

性能验证与实测数据

信号质量对比

  • 原始 AB 相 :示波器显示标准 90°相位差方波
  • 四倍频输出 :每个 AB 周期内出现 4 个计数脉冲

误差率测试(1000 线编码器)

转速 (RPM) 理论脉冲数 实测脉冲数 误差率
60 240,000 239,997 0.001%
600 2,400,000 2,399,876 0.005%
3000 12,000,000 11,998,521 0.012%

开放性问题

在极端转速(如 10,000RPM 以上)情况下,如何解决以下问题:
1. 信号边沿过于密集导致 MCU 无法及时响应中断
2. 电缆传输延迟引起的相位失真
3. 高频噪声干扰导致的状态误判

(欢迎读者在评论区分享实战经验)

正文完
 0
评论(没有评论)