STM32F103实战:用CubeMX+HAL库搞定编码器测速,精准读取电机转速(附完整代码)

张开发
2026/4/18 10:13:37 15 分钟阅读

分享文章

STM32F103实战:用CubeMX+HAL库搞定编码器测速,精准读取电机转速(附完整代码)
STM32F103编码器测速实战从CubeMX配置到PID闭环控制在智能小车、机械臂和云台等嵌入式项目中精确获取电机转速是实现闭环控制的关键。本文将手把手带您完成基于STM32F103和HAL库的编码器测速全流程涵盖硬件选型、CubeMX避坑配置、M/T法测速实现以及数据验证等核心环节。1. 编码器选型与参数解析选择适合的编码器是项目成功的第一步。市面上常见的增量式旋转编码器主要分为光电式和磁电式两种它们在智能车竞赛和工业应用中最为普遍。关键参数解读参数名称说明典型值示例线数(PPR)编码器旋转一圈产生的脉冲数直接影响分辨率500线、1024线输出相位A/B两相输出相位差90度用于判断方向正交方波供电电压常见5V或3.3V需与控制器匹配5V±10%最大响应频率决定可测量的最高转速100kHz机械安装方式轴型或孔型影响与电机的连接方式6mm轴径实际项目中选择编码器时需要特别注意线数与电机最高转速的匹配关系。例如500线编码器在10000RPM时输出频率为500×10000/60≈83.3kHz应确保编码器的最大响应频率高于此值。减速电机参数换算带减速箱的电机需要额外考虑减速比参数。例如某电机参数为电机空载转速10000 RPM减速比30:1编码器线数500 PPR则输出轴的理论分辨率为每转脉冲数 编码器线数 × 减速比 × 倍频数 500 × 30 × 4 60,000 脉冲/转2. CubeMX配置避坑指南使用STM32CubeMX配置编码器接口时有几个关键设置点容易出错2.1 定时器基础配置选择支持编码器模式的定时器TIM1-TIM5设置预分频器(Prescaler)为0 - 确保计数器直接使用输入时钟自动重装载值(AutoReload)设为最大值65535计数模式选择Encoder Mode TI1 and TI2常见配置误区误将Polarity理解为边沿触发实际为信号反相设置忽略滤波器设置导致噪声干扰建议2-5个时钟滤波未启用定时器溢出中断影响长周期测量2.2 引脚配置示例// 典型引脚配置以TIM4为例 TIM4_CH1 - PB6 // 编码器A相 TIM4_CH2 - PB7 // 编码器B相特别注意编码器模式仅适用于通道1和通道2通道3和4无法使用此功能。3. 编码器测速算法实现3.1 M法测速适合高速场景// 宏定义 #define ENCODER_PPR 500 // 编码器线数 #define GEAR_RATIO 30 // 减速比 #define SAMPLE_TIME 0.1f // 采样时间100ms float calculate_speed_method(uint32_t pulse_count) { // 四倍频模式下实际脉冲数 原始计数/4 float real_pulses pulse_count / 4.0f; // 转轴转速 (脉冲数/线数) / 采样时间 float shaft_rps (real_pulses / ENCODER_PPR) / SAMPLE_TIME; // 输出轴转速 转轴转速 / 减速比 return shaft_rps / GEAR_RATIO; }3.2 T法测速适合低速场景float calculate_speed_t_method(uint32_t period_ticks, uint32_t timer_freq) { // 脉冲周期(秒) 计数值/定时器频率 float pulse_period period_ticks / (float)timer_freq; // 转轴转速 (1/线数) / 脉冲周期 float shaft_rps (1.0f / ENCODER_PPR) / pulse_period; return shaft_rps / GEAR_RATIO; }3.3 方向判断与溢出处理// 在定时器溢出中断中处理方向计数 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(htim htim4) { if(__HAL_TIM_IS_TIM_COUNTING_DOWN(htim)) { overflow_count--; // 反向溢出 } else { overflow_count; // 正向溢出 } } } // 获取完整32位计数值 int32_t get_encoder_total() { return (overflow_count * 65536) __HAL_TIM_GET_COUNTER(htim4); }4. 数据验证与调试技巧4.1 示波器验证信号质量检查A/B相信号的相位差是否为90度观察信号上升/下降时间是否符合要求确认无毛刺和信号抖动常见问题排查表现象可能原因解决方案计数方向不稳定信号相位差偏离90度检查编码器安装或更换编码器高速时计数丢失信号边沿质量差增加RC滤波或使用差分编码器低速时测量不准采样时间过长改用T法或M/T混合法计数突然归零未处理定时器溢出启用溢出中断并扩展计数器位数4.2 软件滤波处理// 移动平均滤波实现 #define FILTER_WINDOW 5 typedef struct { float buffer[FILTER_WINDOW]; uint8_t index; } SpeedFilter; float filter_speed(SpeedFilter* filter, float new_speed) { filter-buffer[filter-index] new_speed; filter-index (filter-index 1) % FILTER_WINDOW; float sum 0; for(int i0; iFILTER_WINDOW; i) { sum filter-buffer[i]; } return sum / FILTER_WINDOW; }5. 与PID控制的集成应用将编码器测速结果用于电机PID速度控制时需要注意以下几点采样时间匹配PID计算周期应与速度测量周期一致单位统一确保设定值与反馈值使用相同单位如RPM或RPS抗积分饱和电机停止时需处理积分项累积问题典型PID速度控制代码框架typedef struct { float kp, ki, kd; float integral; float prev_error; uint32_t last_time; } PIDController; float pid_update(PIDController* pid, float setpoint, float measurement) { uint32_t now HAL_GetTick(); float dt (now - pid-last_time) / 1000.0f; pid-last_time now; float error setpoint - measurement; pid-integral error * dt; float derivative (error - pid-prev_error) / dt; pid-prev_error error; return pid-kp * error pid-ki * pid-integral pid-kd * derivative; }在实际云台控制项目中采用编码器测速配合PID控制可将速度波动控制在±2%以内显著提升系统稳定性。一个常见的调试技巧是先用纯P控制确定大致参数范围再逐步加入I和D参数进行精细调节。

更多文章