基于 STM32F405RGT6 的有霍尔无刷直流电机(BLDC)六步换向与速度闭环控制工程。项目支持按键启停、正反转、目标转速调节、开环测试、增量式 PI 调速,以及通过 VOFA+ 实时观察目标转速、原始转速、滤波转速和 PWM 输出。
| 项目 | 参数 |
|---|---|
| MCU | STM32F405RGT6,Cortex-M4 |
| 开发板 | 匠心科技 STM32F405 电机控制开发板 |
| 电源 | 调试时使用 24 V 直流电源 |
| 电机类型 | 三相有霍尔 BLDC |
| 电机极对数 | 4 极对 |
| 霍尔传感器 | 3 路数字霍尔 |
| 每机械圈有效霍尔边沿 | 4 × 6 = 24 个 |
| PWM 频率 | 20 kHz |
| 霍尔输入 | PC6、PC7、PC8 |
| PWM 上桥臂 | TIM1 CH1/CH2/CH3,PA8/PA9/PA10 |
| 下桥臂控制 | PB13、PB14、PB15 |
| 调试串口 | USART1,PB6/PB7,115200-8-N-1 |
- 编辑器/集成环境:Visual Studio Code
- 工程管理插件:EIDE
- 实际编译器:ARM Compiler 5(AC5)
- 下载器:OpenOCD,CMSIS-DAP
- 串口上位机:VOFA+ 1.3.10
- VOFA+ 数据协议:FireWater 文本协议
- 工程同时保留 Keil MDK 工程文件,入口为
USER/BLDC_Driver.uvprojx
VSCode 本身不是编译器,本工程由 EIDE 调用 AC5 完成编译。
驱动方式为一相上桥臂 PWM、另一相下桥臂常导通、第三相悬空。换相前先关闭全部桥臂,再根据霍尔状态打开新的电流路径。
手动旋转电机测得的霍尔序列为:
- 一个方向:
3 → 1 → 5 → 4 → 6 → 2 - 反方向:
3 → 2 → 6 → 4 → 5 → 1
当前正转换向表:
| 霍尔状态 | 上桥臂 PWM | 下桥臂常导通 |
|---|---|---|
| 2 | U | V |
| 6 | U | W |
| 4 | V | W |
| 5 | V | U |
| 1 | W | U |
| 3 | W | V |
换向在 TIM1 PWM 周期中点采样中断中执行,避免主循环和串口输出延迟换相。
TIM5 配置为 1 μs 自由运行计时器。测速只接受连续同方向的合法霍尔跳变,每累计 6 个边沿计算一次机械转速:
RPM = 60,000,000 × 6 / (4 × 6 × 周期时间[μs])
= 15,000,000 / 周期时间[μs]
相关处理:
- 小于 300 μs 的边沿视为毛刺并拒绝。
- 跳扇区或方向改变时重新建立测速周期。
- 连续 300 ms 没有有效霍尔边沿时,转速清零并在闭环模式停机。
- 原始转速经过 5 点滑动平均后送入 PI 控制器。
TIM3 每 10 ms 产生一次控制节拍,中断中只置标志,PI 计算在主循环执行。
当前 PI 参数:
| 参数 | 数值 |
|---|---|
| Kp | 0.020 |
| Ki | 0.0025 |
| Kd | 0 |
| 最小输出 | 5.0% |
| 最大输出 | 11.0% |
| 输出分辨率 | 0.1% |
| 每 10 ms 最大增加量 | 0.2% |
| 每 10 ms 最大减少量 | 0.5% |
| 目标转速范围 | 700~3500 RPM |
| 按键调速步长 | 100 RPM |
PID 输入使用 5 点滑动平均后的转速,不使用原始转速。启动阶段先输出 10% 占空比,检测到 6 个连续同方向霍尔边沿后再进入速度闭环。
本工程同时保留开环和速度闭环控制。当前采用编译期宏切换,宏定义位于 HARDWARE/MotorControl.c:
#define SPEED_CLOSED_LOOP_DEFAULT 1- 设置为
0:使用开环占空比控制。 - 设置为
1:使用速度闭环 PI 控制,工程默认为该模式。
修改宏后需要重新编译并烧录程序,不支持电机运行过程中直接切换模式。切换前应先停机,防止目标转速和占空比发生突变。
两种模式的区别:
| 项目 | 开环模式 | 闭环模式 |
|---|---|---|
| 控制量 | PWM 占空比 | 目标转速 |
| 初始设定 | 5% | 1000 RPM |
| UP/DOWN 按键 | 每次增减 1% | 每次增减 100 RPM |
| 可调范围 | 5%~12% | 700~3500 RPM |
| PI 控制器 | 不执行 | 每 10 ms 执行一次 |
| VOFA 第一列 | 固定为 0 | 当前目标转速 |
| 测速与滤波 | 正常运行 | 正常运行并作为 PI 反馈 |
两种模式启动时都会先使用 10% 占空比,检测到 6 个连续同方向霍尔边沿后,再切换到对应模式的实际输出。
开环模式主要用于验证霍尔换向表、PWM 导通方式、占空比与转速关系、电流和温升。只有开环运行稳定后,才应切换到闭环模式调整 PI 参数和进行负载测试。
电机运行时,每 50 ms 发送一帧;停机时不发送数据。
目标转速,原始转速,滤波转速,占空比x10
例如:
3500,3529,3512,105
其中 105 表示实际占空比为 10.5%。
本工程提供霍尔状态与三相导通矢量自检功能,用于在电机 U/V/W 相线与霍尔线对应关系未知时,自动测试并打印每个静态导通矢量对应的 Hall 状态,辅助生成或验证六步换向表。
有感 BLDC 的霍尔信号只能表示转子所处的电气位置。不同电机以及不同相线、霍尔线接法下,Hall 状态与三相导通组合并不存在统一对应关系。换向表不匹配时,可能出现低占空比可以转动但效率较低、占空比升高后转速突变、电机抖动或噪声增大、发热明显以及速度闭环难以稳定等问题。
程序依次强制输出六个静态导通矢量:
Step0: U+ V-
Step1: U+ W-
Step2: V+ W-
Step3: V+ U-
Step4: W+ U-
Step5: W+ V-
U+ 表示 U 相上桥输出 PWM,V- 表示 V 相下桥常通,未参与的第三相保持悬空。每个矢量保持一小段时间,使转子吸合到稳定位置,然后读取 PC6、PC7、PC8 上的三路霍尔信号并输出组合状态。
自检作为独立的 MOTOR_MODE_SELF_CHECK 模式实现,不改变正常开环和闭环控制路径:
main.c
接收串口 H/h 指令,并在电机停机时触发自检
MotorControl.c
管理自检模式、六步测试流程、Hall 读取和结果打印
Bldc.c
通过 BLDC_Force_Vector() 强制输出指定导通矢量
Hall.c
读取 PC6/PC7/PC8,返回 1~6 的 Hall 状态
自检期间,TIM1_CC_IRQHandler() 只清除中断标志并返回,不执行正常霍尔换相、测速和 PI 控制。自检结束后程序关闭全部桥臂,并恢复 MOTOR_MODE_STOP。
电机完全停机后,通过串口发送 H 或 h 即可开始自检。运行状态下发送该指令不会执行自检。
#define SELF_CHECK_DUTY_X10 50
#define SELF_CHECK_HOLD_MS 300
#define SELF_CHECK_GAP_MS 500SELF_CHECK_DUTY_X10 = 50:自检占空比为 5.0%。SELF_CHECK_HOLD_MS:每个导通矢量的保持时间。SELF_CHECK_GAP_MS:相邻矢量之间关闭全部桥臂的时间。
吸合完成后不会只读取一次 Hall,而是每隔 2 ms 采样一次,共采样 30 次。只有某个状态至少出现 20 次时才接受该众数,降低霍尔边界抖动和瞬时误读对静态表的影响。
实测中,2.0% 占空比的吸合力不足,六个 Step 读取到相同 Hall 状态;提高到 5.0% 后,转子能够完成静态对齐并得到有效结果。
当前电机在 5.0% 自检占空比下得到:
=== Hall-Phase Self Check ===
Step0 U+ V- -> Hall=1
Step1 U+ W- -> Hall=3
Step2 V+ W- -> Hall=2
Step3 V+ U- -> Hall=6
Step4 W+ U- -> Hall=4
Step5 W+ V- -> Hall=5
=== Self Check End ===
反向整理为 Hall 到静态导通矢量的关系:
Hall 1 -> U+ V-
Hall 2 -> V+ W-
Hall 3 -> U+ W-
Hall 4 -> W+ U-
Hall 5 -> W+ V-
Hall 6 -> V+ U-
自检结果表示转子与定子磁场的静态对齐关系,不一定能直接作为运行换向表。电机运行时需要持续产生转矩,实际导通矢量通常需要在静态结果基础上前移或后移一个或多个电气 Step:
running_step = static_step + offset
offset = 0, 1, 2, 3, 4, 5
应从较低占空比开始测试不同 offset,比较启动是否顺畅、运行声音、电流、温升、占空比与转速关系以及转速稳定性,选择声音最顺、电流最低且转速变化最平滑的组合。
电机停机时发送串口指令 O 或 o,程序会重新执行静态吸合并建立 hall_to_static_step[],然后进入 MOTOR_MODE_OFFSET_SCAN,依次测试 offset 0~5。静态采集会打印全部六个 Step -> Hall 结果;若出现非法、重复或缺失状态,会输出具体原因并终止扫描。静态表有效时,程序还会打印由 step_to_hall[] 自动生成的 Hall 序列。扫描期间不执行原固定换向表和 PI 控制,TIM1 中断只负责候选矢量换向及 Hall 统计。
#define OFFSET_SCAN_DUTY_X10 50
#define OFFSET_SCAN_RUN_MS 1200
#define OFFSET_SCAN_GAP_MS 800
#define OFFSET_SCAN_STALL_MS 300每个候选 offset 使用 5.0% 占空比测试,最长运行 1.2 秒,测试之间断电 800 ms。若 300 ms 内没有有效 Hall 变化,或者跳步、非法 Hall、反向边沿明显过多,程序会立即停止当前候选项。
串口结果中的字段含义如下:
F 正向相邻Hall边沿数
R 反向相邻Hall边沿数
J 非相邻跳步数
INV Hall=0或Hall=7出现次数
RPM 根据有效Hall边沿估算的机械转速
score 综合评分
程序会打印评分最高的 generated-forward 候选 offset,以及由该 offset 计算出的 Hall -> Step 表。这里的 generated-forward 是基于静态自检生成的 Hall sequence 所定义的程序正方向,不保证等于电机的物理顺时针方向。
扫描结果只作为调试识别工具,不会自动修改或覆盖 BLDC_Commutate() 中的正式换向表。正式使用的 dir=0 和 dir=1 换向关系,仍需观察电机实际旋转方向后人工确认,再将验证过的表写入 Bldc.c。由于工程尚未加入电流采样,自动评分只能反映 Hall 连续性和转速,最终仍需低占空比验证旋向、电流、温升、声音和转速稳定性。
- 测试时保持电机空载,并确保转轴可以自由转动。
- 占空比应从 2% 开始,吸合力不足时逐步增加到 3%、4%、5%。
- 不要让单个导通矢量长时间保持。
- 每个 Step 之间必须调用
BLDC_Stop(),避免桥臂持续通电。 - 若出现明显抖动、异常发热、电源保护或驱动板过流保护,应立即停止测试。
- 过流保护只能作为最后保护,不能代替正确的换向关系和测试流程。
该功能适用于更换电机、调整三相线顺序或霍尔线顺序不明确的情况,可以快速建立静态对应关系,减少因换向表错误导致的效率低、转速突变、震荡和发热问题。
CORE/ Cortex-M4 启动文件和核心支持
HARDWARE/ BLDC、霍尔、按键、串口、定时器和电机控制模块
Library/ STM32F4 标准外设库
SYSTEM/ 延时和 PI 控制器
USER/ main.c、中断文件和 Keil 工程
.eide/ EIDE 工程配置
.vscode/ VSCode 调试配置
主要模块职责:
HARDWARE/Bldc.c:PWM 初始化、桥臂控制和六步换向表。HARDWARE/Hall.c:霍尔 GPIO 初始化与状态读取。HARDWARE/MotorControl.c:启动、换向事件判断、测速、滤波和闭环调度。SYSTEM/Pid.c:0.1% 分辨率增量式 PI。USER/main.c:系统初始化、按键分发和 VOFA+ 输出。
项目调试中最关键的两个问题都发生在功率驱动和换向层,而不是 PID 参数本身。
第一个问题是霍尔状态与实际相线对应的换向表不匹配。
错误换向表曾导致以下现象:
- 低占空比堵转或启动困难。
- 占空比增加到某个阈值后转速突然跃升。
- 高速区转速剧烈震荡。
- 电机和功率器件明显发热。
- 调整滤波和 PID 后效果反而更混乱。
最终采用以下方法定位:
- 暂时关闭速度闭环,先进行固定占空比开环测试。
- 用手正反向旋转电机,记录完整的六状态霍尔序列。
- 对照同型号开发板的开环例程,重新建立霍尔状态与三相导通关系。
- 逐级增加开环占空比,同时记录转速、电流和温升。
- 确认开环换向稳定后,再加入测速、滑动平均和 PI。
修正换向表后,开环和闭环性能均明显改善,证明换向关系必须先于 PID 调参完成验证。
第二个问题是误把定时器的互补 PWM 输出直接当成六步换向中的下桥臂常导通。
TIM1 的 CHx 与 CHxN 是同一个相桥臂的一对互补输出,适合控制同一桥臂的上管和下管;但六步换向需要导通的是两个不同相:一个相的上管输出 PWM,另一个相的下管在该换相区间内保持导通,第三相必须悬空。
如果三相 CCR 使用相同占空比,再打开某一相的 CCxE 和另一相的 CCyNE,低侧得到的是其所属通道的互补 PWM,并不等价于“下管常导通”。这种导通关系可能造成:
- 相电流路径不符合预期。
- 占空比与转速关系严重非线性。
- 某个占空比附近转速突然跃升。
- 高速震荡、电流增大和电机发热。
- 即使继续调整 PID,也无法消除根本问题。
当前工程采用的方式是:
- PA8、PA9、PA10 分别作为三相上桥臂 PWM。
- PB13、PB14、PB15 分别作为三相下桥臂 GPIO 控制。
- 每次换相前先关闭全部 TIM1 通道并复位三个下桥臂 GPIO。
- 根据换向表,仅使能一个上桥臂 PWM,同时置位另一个相的下桥臂 GPIO。
- 第三相上下桥臂均保持关闭,实现悬空。
该方式明确形成“一相上管 PWM + 另一相下管常导通 + 第三相悬空”的六步电流路径。PWM 导通方式修正后,再进行开环占空比扫描,转速随占空比变化才恢复为可预测、可调的关系。
更换电机、霍尔线序或相线连接后,建议按以下顺序重新调试:
- 检查静态霍尔状态:状态只能是 1~6,不能长期出现 0 或 7。
- 手动测量霍尔序列:分别记录正转和反转的六状态循环。
- 核对导通方式:确认任一换相状态只有一个上桥臂 PWM、另一个相的下桥臂常通、第三相悬空。
- 低占空比开环换向:从能够可靠起转的占空比开始测试。
- 建立占空比—转速表:逐级增加占空比,记录转速、电流和温升。
- 核对测速公式:极对数变化后必须修改
MOTOR_POLE_PAIRS。 - 确认原始与滤波转速:先保证测速可信,再将滤波转速送入 PI。
- 先 P 后 I:先用 P 调整响应,再逐步加入 I 消除静差,D 默认保持为 0。
- 进行负载测试:观察加负载掉速、卸载超调、占空比变化和温升。
不要在开环换向尚未稳定时反复调整 PID,否则容易把换向错误误判为控制器参数问题。
- 打开根目录的
速度闭环控制.code-workspace。 - 在 EIDE 项目中选择构建配置
AC5。 - 点击锤子编译。
- 使用 OpenOCD 配置烧录。
- 打开
USER/BLDC_Driver.uvprojx。 - 执行 Rebuild,确认
0 Error(s), 0 Warning(s)。 - 执行 Download,并确保启用
Reset and Run。
由于工程中可能存在名称相同的历史副本,烧录前应确认 Keil 打开的工程路径正确。
可以点击 EIDE 项目右侧的扫帚按钮。它会清理 build 中的编译产物,不会删除 C 源码、头文件或工程配置,重新编译即可生成。
当前目录中体积较大的生成内容主要是:
build/:EIDE 编译产物,可以清理。Output/:Keil 编译产物,可以重新生成;建议仅保留需要发布的 HEX。.pack/:STM32F4 设备包。保留后工程更自包含,删除或忽略后仓库更小,但其他使用者需要重新安装对应设备包。
推荐上传源码和工程配置,不提交 .o、.axf、.map、.lst 等中间文件。如果需要提供可直接烧录的固件,可将最终 HEX 放在 GitHub Release 中。
目前已经实现:
- 稳定六步换向。
- 4 极对霍尔周期法测速。
- 5 点滑动平均。
- 0.1% 占空比分辨率增量式 PI。
- 700~3500 RPM 目标调速。
- VOFA+ 实时曲线显示。
- 停机时停止串口数据发送。
后续可以继续增加目标转速斜坡、过流保护、过温保护、欠压保护、堵转状态机,以及更规范的固定负载测试。
调试电机时应设置电源限流,并避免直接用手接触旋转部件。提高最大占空比前,需要同步观察电流和温升。