51单片机编码器测速入门实战:从硬件连接到软件滤波全解析

1次阅读
没有评论

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

image.webp

增量式编码器测速原理

增量式编码器通过输出两路相位差 90°的方波信号(A/ B 相),配合 51 单片机的定时器捕获功能,可以实现电机转速的精确测量。这种测速方法在智能小车、步进电机控制等场景中尤为重要——它不仅能反馈实时转速,还能通过脉冲数计算位移量。

51 单片机编码器测速入门实战:从硬件连接到软件滤波全解析

硬件计数 vs 软件计数方案对比

  • 硬件计数(PCA 模块)
  • 优点:不占用 CPU 资源,适合高频脉冲(>10kHz)
  • 缺点:51 单片机多数型号仅 1 个 PCA 模块,难以同时捕获 A / B 相

  • 软件计数(定时器捕获)

  • 优点:灵活配置,可同时处理多路信号
  • 缺点:高频时可能丢失脉冲(建议 <5kHz)

推荐初学者优先使用定时器捕获方案,其实现更直观且资源占用少。

硬件电路设计要点

  1. 信号上拉
    编码器输出端需接 10kΩ 上拉电阻至 VCC,避免悬空状态导致误触发

  2. RC 消抖电路
    在 A / B 相线上并联 100nF 电容 +100Ω 电阻组成低通滤波,可有效抑制毛刺

  3. 接线示意图

  4. 编码器 A 相 → P3.2(INT0)
  5. 编码器 B 相 → P3.3(INT1)
  6. GND 共地处理

定时器配置与中断实现

// 定时器 1 初始化(1ms 时基)void Timer1_Init() {
    TMOD &= 0x0F;  // 清除高 4 位
    TMOD |= 0x10;  // 16 位定时模式
    TH1 = 0xFC;    // 1ms@11.0592MHz
    TL1 = 0x66;
    ET1 = 1;       // 允许中断
    TR1 = 1;       // 启动定时器
}

// 外部中断 0 服务函数(A 相下降沿触发)void EX0_ISR() interrupt 0 {
    static uint16_t last_capture;
    uint16_t current_capture = TH1 << 8 | TL1;
    pulse_interval = current_capture - last_capture;  // 计算脉冲间隔
    last_capture = current_capture;
}

转速计算公式

假设编码器线数为 N(脉冲数 / 转),测得脉冲间隔为 t(ms):

 转速 (rpm) = 60000 / (N × t)

例如:500 线编码器测得脉冲间隔 2ms → 转速 =60000/(500×2)=60rpm

软件滤波实战

采用移动平均滤波算法,建立 10 组数据的滑动窗口:

#define FILTER_WINDOW 10
volatile uint16_t speed_buf[FILTER_WINDOW];
volatile uint8_t buf_index = 0;

uint16_t Moving_Average_Filter(uint16_t new_val) {
    static uint32_t sum = 0;

    sum -= speed_buf[buf_index];  // 减去最旧数据
    sum += new_val;               // 加入新数据
    speed_buf[buf_index] = new_val;
    buf_index = (buf_index + 1) % FILTER_WINDOW;

    return sum / FILTER_WINDOW;   // 返回平均值
}

窗口大小选择原则:
– 低速场景(<100rpm):建议 15-20 点
– 高速场景(>1000rpm):5- 8 点即可

避坑指南

  1. 信号抖动问题
  2. 在中断入口添加 10ms 延时消抖
  3. 采用两次采样法确认有效边沿

  4. 高低速参数调整

  5. 低速时增大定时器周期(如 10ms)
  6. 高速时改用 PCA 计数模式

  7. 中断响应优化

  8. 关闭其他不必要中断
  9. 关键变量加 volatile 修饰

完整代码框架

#include <reg52.h>

volatile uint16_t pulse_interval = 0;

void main() {Timer1_Init();
    EX0 = 1;  // 允许 INT0 中断
    IT0 = 1;  // 下降沿触发
    EA = 1;   // 总中断允许

    while(1) {uint16_t rpm = 60000 / (500 * pulse_interval);
        rpm = Moving_Average_Filter(rpm);
    }
}

拓展思考

要实现双向测速,可通过检测 A / B 相的相位关系:
– A 相领先 B 相 90° → 正转
– B 相领先 A 相 90° → 反转

可在中断函数中添加如下判断逻辑:

if(P3.2 && !P3.3) direction = FORWARD;
else if(!P3.2 && P3.3) direction = BACKWARD;

通过这篇教程,你应该已经掌握了 51 单片机编码器测速的核心方法。接下来可以尝试结合 PID 算法实现闭环速度控制,这将让你的电机控制项目更上一层楼。

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