news 2026/9/26 23:50:45

STM32F1编码器模式实战:平衡小车电机测速全解析(HAL库/CubeMX/直流减速电机)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32F1编码器模式实战:平衡小车电机测速全解析(HAL库/CubeMX/直流减速电机)

1. 平衡小车电机测速的核心原理

做平衡小车的朋友都知道,电机测速是整个系统的"眼睛"。就像我们骑自行车时需要知道车轮转得多快才能保持平衡一样,平衡小车也需要实时掌握电机转速。这里我们用STM32F1的编码器模式来实现这个功能,实测下来精度可以达到±2转/分钟,完全能满足平衡控制的需求。

直流减速电机自带霍尔编码器,每转会产生固定数量的脉冲。以常见的GM25-370电机为例,电机本身转速12000转/分钟,经过34:1的减速箱后输出转速约350转/分钟。编码器每转产生15个脉冲,经过减速箱后每输出轴转一圈实际产生510个脉冲(15×34)。STM32的编码器模式还能进行4倍频,最终每转能得到2040个脉冲信号。

测速原理很简单:定时采集脉冲数量,比如每0.1秒读取一次计数器值。假设读到的脉冲数是1020,那么转速就是1020÷2040÷0.1=5转/秒(即300转/分钟)。这个计算过程会在代码部分详细展开。

2. 硬件准备与安全接线

2.1 必备硬件清单

我用的核心硬件包括:

  • STM32F103C8T6最小系统板(蓝色药丸板)
  • DRV8848电机驱动模块(比TB6612电流更大)
  • 带15线霍尔编码器的GM25-370直流减速电机
  • 12V锂电池供电系统
  • 0.96寸OLED显示屏(I2C接口)
  • HC-08蓝牙模块(用于无线调试)

特别要注意电机选择。市面上常见的有光电编码器和霍尔编码器两种,霍尔编码器抗干扰能力更强,更适合电机应用。编码器线数也不是越多越好,15线在减速后已经能提供足够的分辨率。

2.2 生死攸关的接线技巧

这里我踩过坑:曾经因为接线错误烧了三块单片机。关键注意事项:

  1. 电机驱动板的电源GND和信号GND要分开处理。建议只将信号GND与单片机共地,大电流的电源GND单独走线。
  2. STM32绝对不能直接给电机驱动板供电!电机驱动需要单独电源。
  3. 编码器信号线建议加10K上拉电阻,避免信号抖动。
  4. 电机电源线上一定要加0.1μF的消噪电容。

具体接线图示:

  • 编码器A相接TIM3_CH1(PA6)
  • 编码器B相接TIM3_CH2(PA7)
  • 电机PWM接TIM4_CH1(PB6)
  • 电机方向控制接任意GPIO

3. CubeMX关键配置详解

3.1 时钟树配置

先配置HSE为8MHz外部晶振,PLL倍频到72MHz系统时钟。这是STM32F1的黄金频率,所有外设都基于这个时钟工作。特别注意APB1总线时钟要设为36MHz,因为定时器挂载在这个总线上。

3.2 PWM配置(TIM4)

  1. 选择TIM4,Clock Source选Internal Clock
  2. Channel1配置为PWM Generation CH1
  3. 参数设置:
    • Prescaler: 71(得到1MHz计数频率)
    • Counter Period: 199(生成10kHz PWM)
    • Pulse: 初始值设为0

PWM频率建议设置在8-16kHz之间,超出这个范围要么会有可闻噪音,要么电机响应变慢。

3.3 编码器模式配置(TIM4)

这是最关键的配置:

  1. 选择TIM3,Combined Channels设为Encoder Mode
  2. 参数设置:
    • Encoder Mode: TI1 and TI2(4倍频模式)
    • Counter Period: 65535(16位计数器最大值)
    • Polarity: Rising Edge(常规配置)

特别注意:Polarity设置不影响计数方向,只影响触发边沿。计数方向由编码器相位差决定。

3.4 定时器中断配置(TIM1)

配置TIM1产生100ms中断:

  • Prescaler: 7199
  • Counter Period: 999 这样得到的定时器频率是72MHz/(7199+1)/(999+1)=10Hz

4. 代码实现与优化技巧

4.1 编码器数据处理

// encoder.c void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(htim == &htim1) { short counter = (short)__HAL_TIM_GET_COUNTER(&htim3); __HAL_TIM_SET_COUNTER(&htim3, 0); // 计算转速(转/秒) float speed = (float)counter / 2040.0f / 0.1f; // OLED显示 OLED_ShowDecimal(0, 4, speed, 2, 2, 12, 0); } }

这段代码有三个优化点:

  1. 使用short类型强制转换处理计数器溢出
  2. 2040是4倍频后的每转脉冲数(510×4)
  3. 0.1是定时器中断周期

4.2 电机控制实现

// motor.c void Motor_SetSpeed(uint8_t percentage) { uint16_t pulse = 7200 * percentage / 100; // ARR=7200 __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, pulse); }

建议做成开环速度曲线,不同电压下电机特性不同,可以实测后建立速度-占空比对照表。

4.3 抗干扰处理

实际测试中发现编码器会受到电机干扰,加入以下滤波代码:

// 在定时器中断中加入移动平均滤波 #define FILTER_SIZE 5 static float speed_buffer[FILTER_SIZE] = {0}; static uint8_t filter_index = 0; speed_buffer[filter_index] = (float)counter / 2040.0f / 0.1f; filter_index = (filter_index + 1) % FILTER_SIZE; float filtered_speed = 0; for(int i=0; i<FILTER_SIZE; i++) { filtered_speed += speed_buffer[i]; } filtered_speed /= FILTER_SIZE;

5. 实测数据与常见问题

5.1 性能测试结果

在不同PWM占空比下测得转速:

占空比实测转速(rpm)理论值(rpm)误差
20%6870-2.8%
40%142140+1.4%
60%208210-0.9%
80%278280-0.7%
100%348350-0.5%

5.2 常见故障排查

  1. 计数器值不变化:

    • 检查编码器供电(通常是5V)
    • 用示波器看PA6/PA7是否有波形
    • 确认CubeMX配置了编码器模式
  2. 转速显示跳动大:

    • 增加软件滤波
    • 检查编码器连接线是否太长
    • 在编码器信号线加100Ω电阻和100pF电容滤波
  3. 电机转动但转速显示为零:

    • 检查编码器方向是否接反
    • 尝试交换A相B相接线

6. 进阶应用:为PID控制做准备

测速最终是为PID控制服务的,这里先打好基础。后续PID需要:

  1. 稳定的速度采样(本文已实现)
  2. 合适的控制周期(建议5-10ms)
  3. 速度-占空比转换关系

建议先建立电机特性表,记录不同PWM下的空载转速和带载转速,这对PID参数整定很有帮助。在我的平衡小车项目中,这套测速方案最终实现了±1rpm的稳定控制精度。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 23:50:20

FOC 算法笔记【三】磁链观测器:从理论到离散化实现

1. 磁链观测器基础&#xff1a;从电磁学原理到电机控制 第一次接触磁链观测器这个概念时&#xff0c;我也被各种专业术语绕得头晕。直到把电机想象成旋转的磁铁玩具&#xff0c;才突然开窍。简单来说&#xff0c;磁链就是描述电机内部磁场强弱的"计量单位"&#xff0…

作者头像 李华
网站建设 2026/8/23 9:41:53

PHP使用 APCu 存储配置、字典数据,减少 Redis 网络 IO。

PHP 借助 APCu 存储配置、字典类静态数据来减少 Redis 网络 IO&#xff0c;核心是将高频访问、变更极少的“热点静态数据”下沉到 PHP 进程本地内存&#xff08;APCu&#xff09;&#xff0c;替代每次请求都通过网络访问 Redis 的方式——既规避了 Redis 网络往返的延迟&#x…

作者头像 李华