共计 1588 个字符,预计需要花费 4 分钟才能阅读完成。
痛点分析
在 51 单片机编码器测速项目中,开发者常遇到几个典型问题:

- 机械抖动干扰:编码器输出的脉冲信号容易因机械振动产生毛刺,导致误触发计数
- 低速测量盲区:当转速过低时,两次脉冲间隔可能超过定时器最大计数值,造成溢出错误
- CPU 资源占用:传统的轮询检测方式会持续消耗处理器资源,影响系统整体性能
技术方案设计
硬件捕获架构
采用定时器 0 的输入捕获功能,硬件自动记录边沿触发时的计数器值,相比软件轮询方案具有三大优势:
- 精确记录脉冲到达的瞬间时刻
- 不占用主循环处理资源
- 支持高频信号采集(最高 1 /12 晶振频率)
信号处理流程
flowchart TD
A[编码器脉冲输入] --> B{边沿触发?}
B -->| 是 | C[记录定时器捕获值]
C --> D[软件消抖判断]
D -->| 有效信号 | E[计算时间差]
D -->| 噪声信号 | F[丢弃本次触发]
E --> G[转换转速值]
转速算法推导
对于每转产生 $PPR$ 个脉冲的编码器,转速计算公式为:
$$ RPM = \frac{60 \times f_{osc}}{N \times PPR \times (CAPTURE_{n} – CAPTURE_{n-1})} $$
其中:
– $f_{osc}$:系统时钟频率(Hz)
– $N$:定时器分频系数
– $CAPTURE_{n}$:第 n 次捕获时的定时器值
代码实现详解
工程配置
在 Keil 中建立工程时需注意:
- 设置 XTAL 频率与硬件一致
- 开启定时器 0 的捕获模式
- 配置中断优先级(建议给捕获中断较高优先级)
核心代码片段
// 定时器 0 初始化
void Timer0_Init(void)
{
TMOD &= 0xF0; // 清零 T0 控制位
TMOD |= 0x09; // 设置为模式 1,门控模式
TH0 = 0; // 初始值清零
TL0 = 0;
TR0 = 1; // 启动定时器
ET0 = 1; // 使能定时器中断
PT0 = 1; // 设置高优先级
}
// 捕获中断服务程序
void Timer0_ISR() interrupt 1
{
static uint16_t last_capture;
uint16_t current_capture = (TH0 << 8) | TL0;
// 消抖处理(20us 内变化视为噪声)if((current_capture - last_capture) > 20)
{rpm = 60000000UL / (PPR * (current_capture - last_capture));
last_capture = current_capture;
}
TF0 = 0; // 清除中断标志
}
避坑指南
中断响应优化
- 保持 ISR 函数简洁,避免复杂运算
- 临界代码段使用
#pragma disable临时关闭中断 - 高频信号采集时关闭不必要的全局中断
参数适配技巧
对于不同 PPR 值的编码器:
- 200PPR 以下:可直接使用公式计算
- 200-1000PPR:建议增加定时器预分频
- 1000PPR 以上:需考虑信号频率是否超出捕获上限
硬件设计建议
- 信号线并联 100nF 电容滤波
- 串联 100Ω 电阻抑制振铃
- 使用双绞线传输信号
实测数据
| 设定转速(RPM) | 实测值(RPM) | 误差率(%) |
|---|---|---|
| 300 | 298 | 0.67 |
| 800 | 802 | 0.25 |
| 1500 | 1495 | 0.33 |
| 50 | 49 | 2.00 |
延伸应用
多编码器扩展
- 使用定时器 1 的捕获功能实现第二路编码器采集
- 通过分时复用方案(需增加外部多路器)
- 采用带硬件捕获功能的增强型 51 芯片(如 STC15 系列)
方向检测实现
对于增量式编码器(A/ B 相):
- 将两相信号分别接入两个捕获通道
- 通过相位差判断旋转方向
- 典型判断逻辑:
- A 相上升沿时检测 B 相电平
- B= 0 正向旋转,B= 1 反向旋转
总结
该方案在 STC89C52RC 芯片上实测,配合 600PPR 编码器可实现 30-2000RPM 范围内的稳定测量。关键点在于捕获中断的快速响应和合理的软件滤波设计。对于需要更高精度的场景,建议改用硬件正交解码器方案。
完整的工程源码已上传至 GitHub 仓库(示例链接),包含可配置的 PPR 参数和测量范围设置接口,开发者可快速移植到自己的项目中。
正文完
