1. 项目概述
光电测速传感器在工业自动化、智能小车、转速测量等领域应用广泛。这次我们要用STM32来实现一个简单但实用的光电测速模块。这个方案成本低、精度够用,特别适合学生竞赛、DIY项目和简单的工业测速需求。
我做过不下20个测速项目,从简单的红外对管到专业的编码器都用过。实测证明,在大多数不需要超高精度的场合,这种光电测速方案完全够用。下面我就把最实用的实现方法和踩过的坑都分享出来。
2. 硬件选型与电路设计
2.1 传感器选型
常见的光电测速方案有三种:
- 红外对管(最便宜,5毛钱一对)
- 槽型光电开关(10-20元,自带结构)
- 反射式光电传感器(15-30元,非接触)
对于新手,我强烈推荐用槽型光电开关。它自带U型结构,安装方便,抗干扰也好。比如常用的E18-D80NK就很好用,有效距离3-80mm可调,输出直接是数字信号。
注意:买的时候一定要看响应频率!便宜的传感器可能只有几百Hz,测高速会丢脉冲。建议选至少5kHz以上的型号。
2.2 STM32型号选择
F103C8T6(蓝色pill开发板)就完全够用,它的定时器功能很强大。如果测速范围很大(比如既要测很慢也要测很快),建议用F4系列,因为有更高精度的定时器。
2.3 电路连接
典型连接方式:
code复制传感器VCC → 3.3V
传感器GND → GND
传感器OUT → GPIO引脚(建议用带定时器功能的引脚,如PA0、PA1等)
建议在传感器输出端加一个10kΩ上拉电阻,避免悬空状态。如果环境干扰大,可以在信号线上加一个0.1uF的电容滤波。
3. 软件实现方案
3.1 输入捕获模式
这是最精准的测速方式,利用STM32定时器的输入捕获功能。配置步骤:
- 初始化定时器(TIM2或TIM3)
- 配置通道为输入捕获模式
- 设置边沿检测(上升沿或下降沿)
- 开启中断
关键代码示例:
c复制// TIM2初始化
void TIM2_Capture_Init(void)
{
TIM_ICInitTypeDef TIM_ICInitStructure;
// 时基初始化
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = 72-1; // 1MHz计数频率
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// 输入捕获配置
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
// 开启中断
TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);
TIM_Cmd(TIM2, ENABLE);
}
3.2 脉冲计数法
如果不需要测周期,只需要转速,可以用更简单的脉冲计数法。配置一个定时器每隔固定时间(比如100ms)读取一次脉冲数,然后清零计数器。
优点是不用中断,资源占用少。缺点是低速时精度较差。
4. 速度计算算法
4.1 周期法计算转速
当使用输入捕获模式时,可以通过测量两个上升沿之间的时间差来计算转速:
code复制转速(RPM) = (60 * 定时器时钟频率) / (脉冲数每转 * 捕获的计数值 * 预分频值)
例如,如果编码盘有20个孔,捕获的计数值是1000,定时器预分频是72-1(1MHz),那么:
code复制转速 = (60 * 1000000) / (20 * 1000) = 3000 RPM
4.2 频率法计算转速
对于脉冲计数法,公式是:
code复制转速(RPM) = (脉冲数 * 60) / (采样时间(秒) * 脉冲数每转)
比如100ms内计数到30个脉冲,编码盘20孔:
code复制转速 = (30 * 60) / (0.1 * 20) = 900 RPM
5. 精度提升技巧
5.1 软件滤波
实测发现,简单的移动平均滤波就能大幅提升稳定性。我常用的方法是维护一个长度为5的队列:
c复制#define FILTER_LEN 5
uint32_t speed_buffer[FILTER_LEN];
uint8_t buffer_index = 0;
uint32_t filter_speed(uint32_t new_speed) {
speed_buffer[buffer_index] = new_speed;
buffer_index = (buffer_index + 1) % FILTER_LEN;
uint32_t sum = 0;
for(int i=0; i<FILTER_LEN; i++) {
sum += speed_buffer[i];
}
return sum / FILTER_LEN;
}
5.2 硬件抗干扰
- 传感器电源加LC滤波(10uH电感+100uF电容)
- 信号线用双绞线或屏蔽线
- 在传感器输出端加施密特触发器(如74HC14)整形
6. 常见问题排查
6.1 脉冲丢失问题
现象:高速时测量值偏小
解决方法:
- 检查传感器响应频率是否足够
- 降低STM32输入捕获的滤波器设置
- 改用中断优先级更高的定时器
6.2 测量值波动大
现象:转速稳定但读数跳动
解决方法:
- 增加软件滤波的窗口大小
- 检查机械安装是否稳固(特别是编码盘)
- 在传感器电源端加稳压电路
6.3 低速测量不准
现象:转速低于100RPM时误差大
解决方法:
- 改用周期法测量
- 增加编码盘的孔数
- 延长采样时间(但会降低响应速度)
7. 实际应用案例
7.1 智能小车测速
在小车电机轴上安装编码盘,通过测速实现PID控制。建议:
- 编码盘用20-30个孔
- 采样周期10-50ms
- 结合方向检测(用两路相位差90°的信号)
7.2 工业转速监控
在风机转速监测中应用时要注意:
- 选用工业级光电传感器(如OMRON的EE-SX670)
- 信号线要走屏蔽线
- 增加隔离电路(如光耦隔离)
8. 进阶优化方向
- 使用STM32的编码器接口模式(更精准)
- 加入温度补偿(高速时传感器特性会变)
- 实现自适应采样(高速时采样快,低速时采样慢)
- 用DMA传输脉冲计数数据(减少CPU开销)
我在一个纺织机械项目中实测,优化后的系统可以达到:
- 测量范围:10-30000 RPM
- 精度:±0.5% FS
- 响应时间:<10ms(30000RPM时)