基于STM32的BLDC(无刷直流电机)控制,其核心原理是"六步换相法"(6-Step Commutation)。根据转子位置(通过霍尔传感器或无感反电动势检测),按顺序导通/关断6个MOS管,驱动电机旋转。
1. 核心宏定义与全局变量 (bldc.h)
首先定义电机运行的三种模式以及PWM句柄(假设你使用HAL库,如果是标准库只需替换TIM_HandleTypeDef)。
c
#ifndef __BLDC_H__
#define __BLDC_H__
#include "stm32f1xx_hal.h" // 根据实际芯片型号修改,如 stm32f4xx_hal.h
// 电机运行状态枚举
typedef enum {
MOTOR_STOP = 0,
MOTOR_RUN,
MOTOR_BRAKE
} Motor_State_t;
// PWM频率与占空比相关
#define PWM_PERIOD 1000 // PWM周期,决定分辨率 (0~1000 对应 0%~100%)
#define DEAD_TIME_NS 1000 // 死区时间(单位:纳秒),根据驱动板调整
// 霍尔传感器引脚定义 (示例:PB6, PB7, PB8)
#define HALL_GPIO_PORT GPIOB
#define HALL_U_PIN GPIO_PIN_6
#define HALL_V_PIN GPIO_PIN_7
#define HALL_W_PIN GPIO_PIN_8
void BLDC_Init(void);
void BLDC_SetSpeed(uint16_t speed);
void BLDC_Stop(void);
void BLDC_Brake(void);
#endif
2. PWM与换相控制核心源码 (bldc.c)
这是最核心的部分,包含了高级定时器(TIM1/TIM8)的PWM互补输出配置,以及根据霍尔信号进行的6步换相逻辑。
c
#include "bldc.h"
#include "math.h"
// 定义高级定时器句柄 (在main.c中定义,这里用extern声明)
extern TIM_HandleTypeDef htim1; // 假设使用TIM1作为PWM生成定时器
static uint16_t motor_speed_target = 0;
static Motor_State_t motor_state = MOTOR_STOP;
/**
* @brief PWM互补输出初始化
* 配置CH1/CH2/CH3的互补PWM输出,并插入死区时间
*/
void MX_TIM1_PWM_Init(void) {
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = PWM_PERIOD;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
HAL_TIM_PWM_Init(&htim1);
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig);
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0; // 初始占空比为0
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
// 配置通道1、2、3
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2);
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3);
// 配置死区时间
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = (uint8_t)(DEAD_TIME_NS / 1000 * 72); // 72MHz主频下计算死区
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig);
// 启动PWM互补输出
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_3);
}
/**
* @brief 核心换相函数
* 根据霍尔传感器的值(U/V/W)决定下一步的导通相序
*/
void BLDC_Commutate(void) {
uint8_t hall_state = 0;
// 1. 读取霍尔传感器状态 (组合成 0~7 的值)
hall_state |= (HAL_GPIO_ReadPin(HALL_GPIO_PORT, HALL_U_PIN) == GPIO_PIN_SET) ? 1 : 0;
hall_state |= (HAL_GPIO_ReadPin(HALL_GPIO_PORT, HALL_V_PIN) == GPIO_PIN_SET) ? 2 : 0;
hall_state |= (HAL_GPIO_ReadPin(HALL_GPIO_PORT, HALL_W_PIN) == GPIO_PIN_SET) ? 4 : 0;
// 2. 根据霍尔状态进行6步换相
switch (hall_state) {
case 0b101: // 霍尔状态5 -> 导通 V(上) W(下)
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, motor_speed_target);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 0);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, 0);
break;
case 0b001: // 霍尔状态1 -> 导通 U(上) W(下)
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, motor_speed_target);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, 0);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, 0);
break;
case 0b011: // 霍尔状态3 -> 导通 U(上) V(下)
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, motor_speed_target);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, 0);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, 0);
break;
case 0b010: // 霍尔状态2 -> 导通 W(上) V(下)
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, motor_speed_target);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 0);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, 0);
break;
case 0b110: // 霍尔状态6 -> 导通 W(上) U(下)
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, motor_speed_target);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, 0);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 0);
break;
case 0b100: // 霍尔状态4 -> 导通 V(上) U(下)
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, motor_speed_target);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, 0);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 0);
break;
default:
break;
}
}
/**
* @brief 设置电机目标速度
* @param speed 0 ~ PWM_PERIOD (如 0~1000)
*/
void BLDC_SetSpeed(uint16_t speed) {
if (speed > PWM_PERIOD) speed = PWM_PERIOD;
motor_speed_target = speed;
motor_state = MOTOR_RUN;
}
/**
* @brief 电机停止 (惰行)
*/
void BLDC_Stop(void) {
motor_speed_target = 0;
motor_state = MOTOR_STOP;
// 关闭所有PWM输出
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 0);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, 0);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, 0);
}
/**
* @brief 电机刹车 (三相下桥臂短路)
*/
void BLDC_Brake(void) {
motor_state = MOTOR_BRAKE;
// 开启所有下桥臂,短接电机三相线圈
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, PWM_PERIOD);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, PWM_PERIOD);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, PWM_PERIOD);
}
3. 霍尔传感器外部中断处理 (stm32f1xx_it.c 或 main.c)
当霍尔传感器电平发生变化时,代表转子到达了新的换相点,需要在中断中立刻调用换相函数。
c
// 在 main.c 中重写 EXTI 回调函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
// 判断是否是霍尔传感器引脚触发的中断
if (GPIO_Pin == HALL_U_PIN || GPIO_Pin == HALL_V_PIN || GPIO_Pin == HALL_W_PIN) {
// 调用换相函数
BLDC_Commutate();
}
}
4. 主函数调用示例 (main.c)
在main函数中初始化硬件,并设定一个目标转速。
c
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM1_Init(); // 初始化高级定时器PWM
// 初始化霍尔传感器引脚的外部中断
HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
// 启动电机转动 (设定速度为 500/1000 = 50% 占空比)
BLDC_SetSpeed(500);
while (1) {
// 主循环中可以做其他事情,比如接收串口指令改变速度
// BLDC_SetSpeed(new_speed);
HAL_Delay(1000);
}
}
参考代码 BLDC 电机控制源码 www.youwenfan.com/contentcsu/70150.html
知识点补充:
- 霍尔接线与换相表匹配 :
代码中的switch(hall_state)换相顺序是基于特定的霍尔安装方式(常见的120度间隔霍尔)。如果你发现电机在某一个方向震动但不转,或者转动时有顿挫感,说明你的霍尔UVW线序或者换相表顺序不对 。此时只需将霍尔信号的读取顺序调换,或者重新排列case里的导通逻辑即可。 - 死区时间(Dead Time) :
上下管导通切换时,必须留出一个极短的空白时间(通常几百纳秒),防止上下管直通导致电源对地短路烧毁MOS管。在sBreakDeadTimeConfig.DeadTime中需要根据你的STM32主频精确计算。 - 无感控制(反电动势) :
上述代码适用于有霍尔传感器 的电机。如果你想做无感(Sensorless)控制,需要将霍尔读取部分替换为三个 ADC通道 实时采样电机悬空相的电压(反电动势),当采样值过零点时(由正变负或由负变正),触发定时器中断进行换相。无感控制的难点在于启动算法(通常采用强行拖拽同步启动)。