STM32无刷电机驱动实战:从定时器PWM到六步换向的完整实现

发布时间:2026/9/16 18:17:30
STM32无刷电机驱动实战:从定时器PWM到六步换向的完整实现 简介这套面向STM32的BLDC无刷直流电机控制资料包以原理图设计和驱动源码为主线适用于正在学习电机电子换向、脉宽调制或准备落地电机控制项目的嵌入式开发者。压缩包共收录93个文件、约247KB主要包含30个头文件与27个C源文件以及IAR工程文件.eww/.ewp/.ewd、链接脚本.icf、启动文件.s等工程配置同时附有编译生成的可执行文件.hex/.out和调试辅助文件.jlink/.bat目录区分inc、src、settings等模块便于定位关键代码。内容围绕STM32F10x系列展开涵盖PWM占空比调节、霍尔传感器位置检测、六步换相逻辑以及FOC磁场定向控制策略配合中断服务函数、库函数封装和调试脚本支持直接打开工程进行仿真与下载从而打通从理论到实测的路径。目前已有190人学习下载可作为课程设计、项目预研或入门无刷电机控制的实用参考资料。1. 为什么 STM32 是 BLDC 无刷电机控制的首选平台STM32.zip 里的东西拆开之后并不是“RGB 点灯 Demo”而是一份可以直接导入 IAR 的裸机工程加一张完整的无刷电机驱动原理图。STM32F103C8T6 这类 Cortex-M3 芯片能在定时器级别实现三相 PWM 的自动死区控制又能把霍尔传感器的三路变化映射成外部中断正好卡在 BLDC 控制最需要确定性的位置上。很多人在入门无刷直流电机驱动时第一反应是去看算法、看状态方程但真正动手调一块 48V 驱动板时会发现硬件连接错误远比 PID 参数更致命。这套资料的价值就在这里原理图把功率管、栅极驱动、采样电阻和 MCU 引脚的关系画清楚了代码部分则告诉你初始化之后怎么一步步跑起来。适合想要快速落地 BLDC 项目的嵌入式工程师也适合想从有刷电机升级到无刷方案的学生和开发人员。2. 从原理图看 BLDC 驱动硬件链路霍尔、栅极驱动与采样电阻2.1 霍尔传感器与梯形换向的对应关系无刷直流电机的定子绕组通常采用星形接法转子是一对或多对永磁体。要做到转子任意位置都有正确的转矩必须知道转子此刻的磁极落在哪里。霍尔传感器就是最简单的手段三个霍尔元件按 120° 或 60° 电角度安装在定子上转子转动时输出三路方波信号三路信号编码成 6 种有效状态。读取这 6 个状态就能确定当前时刻应该让哪两相绕组通电这就是所谓的梯形波六步换向。注意这里的角度是电角度而不是机械角度。电机极对数不同机械 360° 对应的霍尔状态变化次数也不同。我的习惯是先算出电角度步距再看霍尔传感器的安装电气角度避免把 60° 和 120° 的安装方式搞混。原理图里霍尔输出的三根线通常经过上拉电阻后直接进入 STM32 的 GPIO例如 PB4、PB5、PB6也可以接到支持外部中断的管脚上好处是转速较高时不会因为轮询延迟错过换向。2.2 STM32 最小系统与三相 H 桥的引脚连接STM32_Demo 对应的原理图一般会从 48V 母线电压开始先经过防反接二极管和滤波电容再通过 DC-DC 降到 12V 给栅极驱动芯片、降到 5V 给霍尔电源最后用 LDO 得到 3.3V 给 MCU 核心电路。STM32 的普通 GPIO 并不适合直接驱动功率管所以中间一定有一级栅极驱动电路常见的是 IR2101、EG2134 这种半桥驱动三相一共三片每片输出互补的高低边驱动信号。以下是这类 Demo 中最常见的 STM32F103C8T6 引脚映射逆变电路用六个 N-MOSFET 组成三相全桥信号MCU 引脚说明TIM1_CH1PA8U 相上桥 PWMTIM1_CH1NPB13U 相下桥互补 PWMTIM1_CH2PA9V 相上桥 PWMTIM1_CH2NPB14V 相下桥互补 PWMTIM1_CH3PA10W 相上桥 PWMTIM1_CH3NPB15W 相下桥互补 PWM霍尔 U/V/WPB4/PB5/PB6三相霍尔输入带上拉母线电流采样PA1ADC 采样低端电流反电动势采样PA0/PA1/PA2分压后进 ADC 或比较器这里需要特别留意的是上下桥 PWM 的映射。TIM1 的六个通道正好对应三相全桥的三对互补输出把它们接在栅极驱动芯片的 HIN/LIN 输入端驱动芯片内部再去控制高压侧的管子。原理图里如果看到 PA8 直接连了六个三极管或者达林顿管说明是低压小功率电机方案48V 无刷直流电机驱动的原理图则一定会出现自举电容和栅极电阻。2.3 续流回路、自举电容和硬件过流保护BLDC 电机是感性负载当开关管关断时绕组电流会继续流动这时必须给电流一个续流通道。原理图中会看到每个 MOSFET 的漏源极之间并联一个快恢复二极管或者使用 MOS 管内部寄生的二极管。实际设计时下管常开、上管 PWM 的换向方式下续流路径完全依赖栅极驱动和 MOSFET 的配合所以低边采样电阻的位置也很有讲究。常见的采样方案是三相下桥源极共同接一个毫欧级采样电阻到 GND电阻两端电压经过运放放大后送入 STM32 的 ADC用来做电流环或者过流保护。更粗暴一点的做法是把运放输出接在 TIM1_BKIN 引脚上一旦电流超过阈值外部比较器直接触发刹车功能硬件立刻封锁全部 PWM 输出不需要软件响应。这个细节值得你在看原理图时重点确认如果图上只有一个运放加一个 LM393那就说明是硬件快速保护如果运放输出直接进 ADC那过流保护就依赖中断程序里的限幅处理。注意自举电容太小或栅极电阻太大时上管开通瞬间会因驱动能力不足而发热表现为“空载能转带载掉相”。这是 BLDC 驱动板最容易误判为程序问题的硬件坑。3. STM32 定时器生成三相 PWM 与六步换向配置3.1 为什么选择 TIM1 高级定时器BLDC 控制要求三个半桥的上下管按照一定顺序工作不能出现同一桥臂直通。普通定时器虽然也能输出 PWM但无法从硬件层面保证互补信号的死区时间。STM32F103 的 TIM1 和 TIM8 是高级定时器自带互补输出、死区插入和刹车输入只需要初始化一次BKIN 信号到达时所有 PWM 输出立即进入安全电平。这对无刷驱动尤为重要因为换向瞬间如果上管还没关干净、下管已经打开母线电压就会直接通过两个管子短路瞬间烧掉 MOS 管。软件延时保护不可靠必须用定时器硬件死区。死区时间的大小取决于栅极驱动芯片的传播延迟和 MOSFET 的关断延迟。低压小功率板用 1us 左右比较稳妥高压大电流方案里可以先取 2us再用示波器看上下管栅极波形的交叉点逐步往小调。不要一上来就把死区设成 0这样手一滑就烧管子。3.2 TIM1 三相互补 PWM 初始化代码在 STM32 标准外设库中初始化 TIM1 的代码大致是这样注意使用 GPIO 复用推挽输出模式设为 PWM1void TIM1_3Phase_PWM_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_BDTRInitTypeDef TIM_BDTRInitStructure; /* 使能时钟 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); /* PA8/PA9/PA10 作为 TIM1_CH1/CH2/CH3 复用推挽输出 */ GPIO_InitStructure.GPIO_Pin GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); /* PB13/PB14/PB15 作为互补通道 CH1N/CH2N/CH3N */ GPIO_InitStructure.GPIO_Pin GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; GPIO_Init(GPIOB, GPIO_InitStructure); /* 定时器时钟 72MHz分频后计数频率 1MHz */ TIM_TimeBaseStructure.TIM_Prescaler 72 - 1; TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_Period 50 - 1; /* 20kHz PWM */ TIM_TimeBaseStructure.TIM_ClockDivision 0; TIM_TimeBaseInit(TIM1, TIM_TimeBaseStructure); /* PWM 模式 1预装载使能 */ TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OutputNState TIM_OutputNState_Enable; TIM_OCInitStructure.TIM_Pulse 15; /* 初始占空比 30% */ TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OCNPolarity TIM_OCNPolarity_High; TIM_OCInitStructure.TIM_OCIdleState TIM_OCIdleState_Set; TIM_OCInitStructure.TIM_OCNIdleState TIM_OCIdleState_Reset; TIM_OC1Init(TIM1, TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); /* CH2/CH3 相同配置略 */ /* 死区时间设置为约 1us */ TIM_BDTRInitStructure.TIM_OSSRState TIM_OSSRState_Enable; TIM_BDTRInitStructure.TIM_OSSIState TIM_OSSIState_Enable; TIM_BDTRInitStructure.TIM_LOCKLevel TIM_LOCKLevel_OFF; TIM_BDTRInitStructure.TIM_DeadTime 72; /* 72 * 1us 1us */ TIM_BDTRInitStructure.TIM_Break TIM_Break_Disable; TIM_BDTRInitStructure.TIM_AutomaticOutput TIM_AutomaticOutput_Enable; TIM_BDTRConfig(TIM1, TIM_BDTRInitStructure); TIM_Cmd(TIM1, ENABLE); TIM_CtrlPWMOutputs(TIM1, ENABLE); }这段代码里有几个关键参数TIM_Prescaler72-1把 72MHz 的 APB2 时钟分频成 1MHz 计数频率TIM_Period50-1让 PWM 周期为 50us对应 20kHz 的载波频率。TIM_Pulse是 CCR 比较寄存器的值15/50 就是 30% 占空比实际运行时由换向表修改。TIM_DeadTime72的含义要结合TIM_ClockDivision来看在 1MHz 计数频率下每个 tick 为 1us所以 72 对应 1us 死区。具体多少合适要看功率管的关断延迟和栅极驱动芯片的传输延迟。代码中TIM_OCIdleState和TIM_OCNIdleState是空闲状态下 PWM 输出的电平在 BLDC 换向和刹车场景下建议把上下桥设置为相反电平避免电机意外进入制动状态。没有挂电机时如果发现输出引脚一直是高电平先检查TIM_CtrlPWMOutputs有没有调用这是新手最容易漏的地方。3.3 六步换向状态表与转速更新PWM 配置好之后BLDC 控制的核心是换向表。每读到一组霍尔状态就把三个 PWM 通道的占空比更新为对应的开关组合。以 120° 霍尔安装为例换向表的 C 语言实现长这样const uint8_t hall_to_drive[8][6] { {0, 0, 0, 0, 0, 0}, /* 非法状态或停机 */ {0, 0, 0, 0, 0, 0}, /* 实际值由电机相序决定 */ /* ... 共 8 组每组对应 6 个功率管的开关状态 */ };完整表格在这里不能直接抄因为不同电机霍尔相序差异很大。推荐的做法是先用手缓慢转动电机通过串口打印霍尔状态记录一个完整电周期下的 6 个状态顺序再结合功率管编号写出换向表。这种“先测序、后填表”的流程能避免很多电机反转和扭矩不足的问题。转速更新就是修改对应定时器通道的TIM_Pulse值。六步换向中通常是高边 PWM、低边恒通因此改变 PWM 占空比就是在改变导通相的电流平均值。占空比从软启动时的 10% 慢慢往上加如果加得太快母线电流瞬态过大会触发过流保护表现为“一启动就停”。此时应该检查换向表顺序和过流阈值而不是盲目调 PI 参数。4. STM32_Demo 工程文件结构与无刷电机驱动状态机4.1 从 EWP 文件看懂 IAR 工程的关键文件STM32.zip 解压后STM32_Project.eww是工作区文件双击它可以在 IAR Embedded Workbench 中打开整个工程STM32_Project.ewp是工程文件内部记录了源文件列表、预处理宏和调试器配置stm32f10x_flash.icf和stm32f10x_ram.icf是链接脚本分别对应 Flash 调试和 RAM 调试。STM32_Project.ewd是 C-SPY 调试器描述文件STM32_Project.cspy.bat可以从命令行启动调试STM32_Project_Debug.jlink则是 J-Link 的命令行脚本适合产线烧录。很多人拿到工程第一件事是直接编译如果报错找不到stm32f10x.h需要检查工程里的stm32f10x_conf.h有没有放在 include 路径里。这个配置文件里会统一打开需要的标准外设库头文件比如stm32f10x_tim.h、stm32f10x_gpio.h、stm32f10x_adc.h。另外cortexm3_macro.s是 Cortex-M3 内核启动文件里面定义了复位向量和中断向量stm32f10x_vector.c则在 C 语言层面补充声明了中断处理函数两者一个都不能少。4.2 main.c 里 BLDC 换向状态机的工作方式打开main.c典型的初始化顺序是先延时和配置时钟树然后初始化 GPIO、ADC、TIM1、串口再进入主循环。主循环里不做实时换向换向动作放在霍尔信号变化触发的 EXTI 中断中执行。这样处理是因为 BLDC 在高速转动时换向周期可能只有几十微妙主循环里的串口打印或 LED 刷新根本赶不上。简化后的状态机如下volatile uint8_t hall_state; volatile uint8_t comm_step; volatile uint16_t target_duty; void EXTI4_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line4) ! RESET) { hall_state (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4) | (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_5) 1) | (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_6) 2)); comm_step hall_to_step[hall_state]; UpdatePwmDuty(comm_step, target_duty); EXTI_ClearITPendingBit(EXTI_Line4); } }这个中断函数的重点是“先读状态再找换向表最后更新 PWM”。comm_step不是霍尔状态的二进制值而是换向表的索引。如果实际接线里霍尔信号不是按 PB4/PB5/PB6 顺序排列表内索引和开关管组合的关系就会错位。判断的方法很简单不接负载手动缓慢转动电机听有没有“哒哒哒”的顿挫声。换向顺序不对时会出现明显的反扭矩甚至锁死这比看逻辑分析仪更快。主循环中只需要做软启动和速度调节while (1) { for (duty 10; duty 80; duty 2) { target_duty duty; delay_ms(10); } }这里target_duty是全局变量中断里写主循环里读必须用volatile修饰否则编译器可能直接优化到寄存器导致运行不一致。软启动每 10ms 增加 2% 占空比实际项目的启动斜率要根据负载惯量调惯量大的电机要再放慢 5 到 10 倍。4.3 通过 UART 在线调速与监控原理图里如果有 MAX3232 或 USB-TTL 芯片串口就能承担实时调参任务。用串口接收一帧简单的SPEED 50文本指令在 main 循环中解析出数值后更新target_duty比每次改参数重新编译工程高效得多。进阶一点的做法是把换向状态、母线电压和电流打包成结构体发送例如typedef struct __packed { uint16_t speed; uint16_t bus_voltage; uint16_t current; uint8_t hall; uint8_t error; } motor_debug_t;发送时直接把这个结构体的二进制字节流通过 DMA 发给串口上位机用同样结构体解析。注意结构体对齐问题最好加上__packed或者按字节拆开发送否则 Windows 上位机和 IAR 的默认对齐不一致时会出现解析错位。串口波特率一般用 115200一帧 12 字节1ms 发送一次也不会阻塞主循环。5. 霍尔相位偏置角度标定与反电动势过零验证5.1 相位偏置角度对 BLDC 驱动的影响霍尔传感器安装位置难以做到绝对精确若霍尔信号的边沿与反电动势过零点之间不是严格的 30° 电角度换向就会过早或过晚。反映到电机上是相电流明显增大、效率降低、高速时转矩波动加剧。很多工程师遇到“带负载能转但电流大”的问题第一反应是加大滤波电容其实先做个相位偏置角度的标定更治本。标定方法断开 PWM 输出给电机一个直流力矩使转子停在某一点然后手动缓慢旋转电机通过 ADC 同时采集三相端电压和霍尔信号记录霍尔跳变对应的线反电动势相位。两者角度差就是换向相位偏置。实际项目中不需要精确到每个角度只需要在固件里加一个随转速查表的补偿值。常见做法是给换向状态做一个 1 到 2 次霍尔中断的延迟转速越高补偿角度覆盖的电角度越大。5.2 用示波器验证三相 PWM 和反电动势最直接的验证方法是把示波器探头接到电机三根相线的分压电阻端观察梯形波反电动势的平顶位置。每一个 60° 电角度区间内应该有一相呈现明显的平台。如果看不到平台大概率霍尔安装位置错误或换向表状态跳变顺序不对。再测量 TIM1 的六路输出用示波器观察死区时间确认上下桥没有直通。这里不建议只测一路 PWM要把 CH1 和 CH1N 一起测两路信号之间必须有明显的死区间隔。5.3 常见故障定位与处理对照现象原因处理方法电机不转有电流冲击换向表顺序错误串口打印霍尔状态重新标定低速正常高速掉相死区时间过大或 PWM 频率低减小死区提高到 20k 以上空载电流大且发热相位偏置角度误差大增加换向延迟或角度补偿一启动就过流保护软启动斜率太陡或阈值低降低启动占空比加大采样滤波上管容易烧毁自举电容不足或死区太小检查栅极驱动电源和死区时间实际执行时我一般先把电机拖到最高转速的 20%用串口把hall_state和comm_step同步打印出来对照霍尔状态顺序画出波形这一步能过滤掉七成以上的换向问题。整套工程跑通之后再把停机逻辑接到 BKIN 引脚上才算是真正把 BLDC 无刷电机控制链路完整收口。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询