STM32 与无刷电机(BLDC):六步换相开环控制实战指南
👁 3 阅读 · 2026-08-17 · STM32 电机
无刷直流电机(BLDC)凭借高效率、长寿命和低噪音,在无人机、机器人、电动工具等领域广泛应用。本文面向有一定基础的嵌入式开发者,深入讲解基于STM32的BLDC六步换相开环控制原理,从电机结构、换相逻辑到PWM调制策略,并给出完整的代码实现(含霍尔传感器模拟和定时器配置),帮助读者快速搭建自己的电机驱动系统。
## 1. 为什么需要六步换相?
无刷直流电机(BLDC)的转子是永磁体,定子绕组为三相(A、B、C)。与有刷电机不同,BLDC必须通过电子换相来改变定子磁场方向,从而驱动转子连续旋转。六步换相(Trapezoidal Control)是最基础的控制方式,每60°电角度切换一次导通状态,一个电气周期内完成6次换相。其优点是控制简单、成本低,适合对噪音和扭矩波动要求不高的场景。
## 2. 六步换相原理
### 2.1 电机模型与反电动势
BLDC的定子绕组通常为星形连接,反电动势(Back-EMF)呈梯形波。六步换相的关键是:在任意时刻,只有两相导通(一相高边、一相低边),第三相悬空。通过检测悬空相的反电动势过零点,可以获取转子位置(闭环),但开环控制则直接按固定顺序换相,无需传感器。
### 2.2 换相顺序表
以A、B、C三相为例,定义高边为H,低边为L,悬空为Z。六步换相顺序如下(电角度0°~360°):
| 步骤 | 导通相(高边→低边) | 悬空相 |
|------|---------------------|--------|
| 1 | A→B | C |
| 2 | A→C | B |
| 3 | B→C | A |
| 4 | B→A | C |
| 5 | C→A | B |
| 6 | C→B | A |
注意:换相顺序与电机旋转方向相关,若反转则逆序执行。
### 2.3 PWM调制策略
开环控制中,通常采用上桥臂PWM、下桥臂恒通(或反之)的方式。例如步骤1中,A相上桥臂PWM,B相下桥臂常开,C相悬空。PWM占空比决定平均电压,从而控制转速。常见调制方式有:
- **ON-PWM**:高边PWM,低边常通,简单但开关损耗不均。
- **PWM-ON**:高边常通,低边PWM,适用于低压大电流。
- **互补PWM**:上下桥臂互补,带死区,适合正弦波驱动,但六步控制中较少用。
本文采用**高边PWM,低边恒通**,便于实现。
## 3. STM32硬件配置
### 3.1 硬件资源
- MCU:STM32F103C8T6(或其他系列)
- 电机驱动:三相全桥(如IR2104+MOSFET)
- 定时器:TIM1(高级定时器,产生6路PWM)
- GPIO:用于控制换相逻辑(或直接使用PWM通道)
### 3.2 定时器配置
TIM1可产生6路互补PWM(CH1/CH1N, CH2/CH2N, CH3/CH3N),但六步控制中同一时刻只有两相导通,因此我们只需使用3个PWM通道(高边),低边用GPIO控制。配置TIM1为中央对齐模式或边沿对齐模式,频率20kHz(避免噪声)。
```c
// 定时器初始化(简化)
void TIM1_PWM_Init(uint16_t arr, uint16_t psc) {
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
// 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 | RCC_APB2Periph_GPIOA, 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);
// 定时器基础配置
TIM_TimeBaseStructure.TIM_Period = arr;
TIM_TimeBaseStructure.TIM_Prescaler = psc;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
// PWM模式配置
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
TIM_OC2Init(TIM1, &TIM_OCInitStructure);
TIM_OC3Init(TIM1, &TIM_OCInitStructure);
// 使能MOE(主输出使能)
TIM_CtrlPWMOutputs(TIM1, ENABLE);
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);
TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM1, ENABLE);
TIM_Cmd(TIM1, ENABLE);
}
```
### 3.3 低边控制GPIO
低边MOSFET用普通GPIO控制,例如PB0, PB1, PB2分别对应A、B、C低边。注意:必须确保同一桥臂上下管不能同时导通,否则短路。
```c
// 低边GPIO初始化
void LowSide_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
```
## 4. 六步换相代码实现
### 4.1 换相状态表
定义换相状态结构体,包含高边PWM通道、低边GPIO引脚。
```c
// 换相状态结构体
typedef struct {
uint8_t high_side_ch; // 高边PWM通道:1,2,3
uint16_t low_side_pin; // 低边GPIO引脚:GPIO_Pin_0/1/2
} Commutation_State;
// 六步换相表(顺序:A-B, A-C, B-C, B-A, C-A, C-B)
const Commutation_State comm_table[6] = {
{1, GPIO_Pin_1}, // A高,B低
{1, GPIO_Pin_2}, // A高,C低
{2, GPIO_Pin_2}, // B高,C低
{2, GPIO_Pin_0}, // B高,A低
{3, GPIO_Pin_0}, // C高,A低
{3, GPIO_Pin_1} // C高,B低
};
```
### 4.2 换相函数
```c
// 设置换相状态
void Set_Commutation(uint8_t step) {
// 关闭所有低边
GPIO_ResetBits(GPIOB, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2);
// 关闭所有高边PWM
TIM_SetCompare1(TIM1, 0);
TIM_SetCompare2(TIM1, 0);
TIM_SetCompare3(TIM1, 0);
// 设置当前状态
uint8_t ch = comm_table[step].high_side_ch;
uint16_t low_pin = comm_table[step].low_side_pin;
// 使能对应高边PWM(占空比由全局变量duty决定)
if (ch == 1) TIM_SetCompare1(TIM1, duty);
else if (ch == 2) TIM_SetCompare2(TIM1, duty);
else if (ch == 3) TIM_SetCompare3(TIM1, duty);
// 使能低边
GPIO_SetBits(GPIOB, low_pin);
}
```
### 4.3 主循环与换相定时
开环控制中,换相时间由转速决定。若目标电转速为RPM,则电气频率f = RPM * 极对数 / 60,换相周期T = 1 / (6 * f)。使用定时器中断或延时实现。
```c
// 全局变量
volatile uint16_t duty = 500; // 占空比0-1000
volatile uint8_t step = 0;
// 定时器中断服务函数(假设TIM2用于换相定时)
void TIM2_IRQHandler(void) {
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
// 换相
Set_Commutation(step);
step = (step + 1) % 6;
}
}
// 主函数示例
int main(void) {
// 初始化系统、GPIO、定时器等
SystemInit();
TIM1_PWM_Init(999, 71); // 72MHz/(72*1000)=1kHz? 实际20kHz需调整
LowSide_GPIO_Init();
// 配置TIM2为换相定时器,例如1ms中断(对应电转速1000rpm,极对数为1)
// 计算:换相周期 = 1/(6*1000/60)=10ms,但实际需根据极对数调整
// 此处简化,使用固定1ms
TIM2_Init(999, 71); // 1ms中断
while(1) {
// 可调节占空比或转速
// 例如:duty = 500; // 50%占空比
}
}
```
注意:上述代码中TIM2初始化未给出,需根据实际需求配置。换相时间必须精确,否则电机可能失步。
## 5. 注意事项
- **死区时间**:虽然六步控制中同一桥臂上下管不会同时导通,但为了安全,建议在PWM输出中加入死区(TIM1的BDTR寄存器),防止MOSFET开关延迟导致直通。
- **电流限制**:启动时电流可能很大,应设置软启动(逐渐增加占空比)或硬件限流。
- **换相时机**:开环控制下,换相频率必须与电机转速匹配。若负载变化导致转速下降,可能失步,因此开环仅适用于轻载或恒速场景。
- **反电动势检测**:若要实现闭环,可在悬空相上检测过零点,但需要额外的比较器电路或ADC采样。
- **PWM频率**:推荐20kHz以上,避免 audible noise。
- **电源去耦**:在电机电源端加足够容量的电解电容和陶瓷电容,抑制反电动势尖峰。
## 6. 总结
本文详细介绍了基于STM32的BLDC六步换相开环控制,从原理到代码实现。通过定时器产生PWM,GPIO控制低边,配合换相表即可驱动电机旋转。开环控制简单易行,适合入门学习,但实际应用中建议结合霍尔传感器或反电动势检测实现闭环,以提高可靠性和动态性能。希望本文能为你后续的电机控制开发打下坚实基础。