基于STM32的无刷直流电机无霍尔驱动程序(Keil工程)
一、系统概述
基于STM32F407ZGT6(Cortex-M4,168MHz,带FPU)实现无刷直流电机(BLDC)无霍尔传感器驱动,采用反电动势(Back-EMF)过零点检测法实现转子位置估算,结合六步换相控制完成电机启动与稳态运行。核心功能包括:PWM驱动三相逆变桥、反电动势采样与过零检测、开环/闭环启动、换相逻辑控制、过流/过压保护,适用于电动工具、无人机、工业风机等场景。
二、核心原理
无霍尔驱动通过检测非导通相的反电动势过零点间接获取转子位置(反电动势在过零点后30°电角度换相)。系统分为启动阶段(开环预定位+加速)和运行阶段(反电动势闭环换相),具体流程:
-
预定位:强制给定子某两相通电,将转子锁定到已知位置;
-
开环启动:按固定顺序换相,逐渐提高转速,直至反电动势可检测;
-
闭环运行:通过ADC采样非导通相反电动势,检测过零点后延迟30°电角度换相。
三、硬件设计
3.1 核心组件选型
| 模块 | 型号/参数 | 功能说明 |
|---|---|---|
| 主控 | STM32F407ZGT6(1MB Flash,192KB RAM) | PWM生成、反电动势采样、换相逻辑、保护控制 |
| 驱动芯片 | IR2104(半桥驱动,带死区控制) | 驱动三相逆变桥MOSFET(上/下桥臂) |
| 功率器件 | 6×IRF3205(N沟道MOSFET,55V/110A) | 三相逆变桥(U/V/W相输出) |
| 电流采样 | ACS712(20A量程,模拟输出) | 母线电流检测(过流保护) |
| 反电动势检测 | 电阻分压+RC滤波(输入STM32 ADC) | 采样非导通相端电压,提取反电动势 |
| 电源 | 24V/10A DC(电机供电),3.3V/1A(MCU供电) | 系统供电(需隔离) |
3.2 硬件连接
| 模块 | STM32F407引脚 | 说明 |
|---|---|---|
| PWM输出 | TIM1_CH1(PA8,U相上桥)、TIM1_CH1N(PB13,U相下桥) TIM1_CH2(PA9,V相上桥)、TIM1_CH2N(PB14,V相下桥) TIM1_CH3(PA10,W相上桥)、TIM1_CH3N(PB15,W相下桥) | 三相PWM(带死区时间) |
| 反电动势采样 | ADC1_IN0(PA0,U相)、ADC1_IN1(PA1,V相)、ADC1_IN2(PA2,W相) | 非导通相端电压采样 |
| 电流采样 | ADC1_IN3(PA3,ACS712输出) | 母线电流检测(过流保护) |
| 驱动使能 | GPIOB_PIN_0(IR2104使能) | 高电平使能驱动芯片 |
四、软件设计(Keil工程,HAL库)
4.1 工程结构
├── Core/
│ ├── Inc/ // 头文件
│ │ ├── main.h // 主函数头文件
│ │ ├── bldc.h // 无刷电机驱动核心头文件
│ │ ├── pwm.h // PWM配置头文件
│ │ ├── adc.h // ADC采样头文件
│ │ └── protection.h // 保护机制头文件
│ ├── Src/ // 源文件
│ │ ├── main.c // 主函数
│ │ ├── bldc.c // 无刷电机驱动核心逻辑
│ │ ├── pwm.c // PWM初始化与配置
│ │ ├── adc.c // ADC采样与滤波
│ │ └── protection.c // 过流/过压保护
├── Drivers/ // STM32 HAL库驱动
└── MDK-ARM/ // Keil工程文件
4.2 核心代码实现
4.2.1 头文件 bldc.h(关键定义与函数声明)
#ifndef __BLDC_H
#define __BLDC_H
#include "stm32f4xx_hal.h"
// ==================== 电机参数 ====================
#define POLE_PAIRS 4 // 极对数(4对极=8极)
#define MAX_SPEED 3000 // 最大转速(RPM)
#define START_DUTY 30 // 启动占空比(%)
#define ACCEL_STEP 5 // 启动加速步长(RPM/步)
// ==================== 换相状态(六步换相) ====================
typedef enum {
COMM_STATE_UV, // U上桥+V下桥导通
COMM_STATE_UW, // U上桥+W下桥导通
COMM_STATE_VW, // V上桥+W下桥导通
COMM_STATE_VU, // V上桥+U下桥导通
COMM_STATE_WU, // W上桥+U下桥导通
COMM_STATE_WV // W上桥+V下桥导通
} CommState;
// ==================== 全局变量 ====================
extern CommState comm_state; // 当前换相状态
extern uint16_t adc_values[3]; // 反电动势采样值(U/V/W相)
extern float back_emf[3]; // 反电动势值(V)
extern uint8_t start_flag; // 启动完成标志(1=闭环运行)
extern uint16_t duty_cycle; // 当前PWM占空比(%)
// ==================== 函数声明 ====================
void BLDC_Init(void); // 无刷电机驱动初始化
void BLDC_Commutate(CommState state); // 换相控制
void BLDC_Start(void); // 电机启动(开环+闭环切换)
void BLDC_Update_BackEMF(void); // 反电动势采样与过零检测
void BLDC_Protection(void); // 过流/过压保护
#endif
4.2.2 PWM配置(pwm.c,TIM1生成三相PWM)
#include "pwm.h"
#include "bldc.h"
TIM_HandleTypeDef htim1; // TIM1句柄(高级定时器,带死区)
// TIM1初始化(三相PWM,20kHz,带死区时间)
void PWM_Init(void) {
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0; // 不分频(168MHz)
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 8400 - 1; // 20kHz(168MHz/8400=20kHz)
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
HAL_TIM_PWM_Init(&htim1);
// 死区时间配置(500ns,根据MOSFET开关速度调整)
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 84; // 死区时间=84 * 1/168MHz=500ns
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE;
HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig);
// 配置CH1/CH2/CH3为PWM模式1(上桥臂)
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;
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);
// 启动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);
}
// 设置PWM占空比(0~100%)
void PWM_SetDuty(uint8_t duty) {
uint16_t pulse = (htim1.Init.Period + 1) * duty / 100;
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, pulse);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, pulse);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, pulse);
}
4.2.3 反电动势检测与换相逻辑(bldc.c)
#include "bldc.h"
#include "adc.h"
#include "pwm.h"
CommState comm_state = COMM_STATE_UV; // 初始换相状态
uint8_t start_flag = 0; // 启动完成标志
uint16_t duty_cycle = START_DUTY; // 当前占空比
// 无刷电机驱动初始化
void BLDC_Init(void) {
PWM_Init(); // 初始化PWM
ADC_Init(); // 初始化ADC(反电动势采样)
duty_cycle = START_DUTY;
PWM_SetDuty(duty_cycle);
}
// 换相控制(根据comm_state设置上下桥臂导通)
void BLDC_Commutate(CommState state) {
// 关闭所有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);
// 根据换相状态设置导通相(1=导通,0=关断)
switch(state) {
case COMM_STATE_UV: // U上桥通,V下桥通
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); // U上桥
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2); // V下桥
break;
case COMM_STATE_UW: // U上桥通,W下桥通
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); // U上桥
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_3); // W下桥
break;
case COMM_STATE_VW: // V上桥通,W下桥通
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2); // V上桥
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_3); // W下桥
break;
case COMM_STATE_VU: // V上桥通,U下桥通
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2); // V上桥
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1); // U下桥
break;
case COMM_STATE_WU: // W上桥通,U下桥通
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3); // W上桥
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1); // U下桥
break;
case COMM_STATE_WV: // W上桥通,V下桥通
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3); // W上桥
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2); // V下桥
break;
default: break;
}
}
// 反电动势采样与过零检测(ADC中断中调用)
void BLDC_Update_BackEMF(void) {
static uint8_t zero_cross_count[3] = {0};
float emf_threshold = 0.5f; // 过零检测阈值(V,根据电机调整)
// 1. 采样反电动势(已通过ADC读取到adc_values[3])
back_emf[0] = (adc_values[0] - 2048) * 3.3f / 4096.0f; // U相(假设中点电压1.65V=2048)
back_emf[1] = (adc_values[1] - 2048) * 3.3f / 4096.0f; // V相
back_emf[2] = (adc_values[2] - 2048) * 3.3f / 4096.0f; // W相
// 2. 过零检测(非导通相)
if (!start_flag) return; // 开环启动阶段不检测
// 根据当前换相状态,确定非导通相(例:UV导通时,W相为非导通相)
uint8_t non_conductive_phase = 0;
switch(comm_state) {
case COMM_STATE_UV: non_conductive_phase = 2; break; // W相
case COMM_STATE_UW: non_conductive_phase = 1; break; // V相
case COMM_STATE_VW: non_conductive_phase = 0; break; // U相
case COMM_STATE_VU: non_conductive_phase = 2; break; // W相
case COMM_STATE_WU: non_conductive_phase = 1; break; // V相
case COMM_STATE_WV: non_conductive_phase = 0; break; // U相
default: break;
}
// 检测过零点(符号变化)
static float last_emf = 0;
if ((last_emf < 0 && back_emf[non_conductive_phase] > 0) ||
(last_emf > 0 && back_emf[non_conductive_phase] < 0)) {
zero_cross_count[non_conductive_phase]++;
if (zero_cross_count[non_conductive_phase] >= 2) { // 连续2次过零确认
// 过零后延迟30°电角度换相(根据转速计算延迟时间)
uint32_t delay_us = 1000000 * 30 / (6 * POLE_PAIRS * MAX_SPEED); // 简化计算
HAL_DelayUs(delay_us); // 需实现微秒延时函数
comm_state = (comm_state + 1) % 6; // 换相(六步换相顺序)
BLDC_Commutate(comm_state);
zero_cross_count[non_conductive_phase] = 0;
}
}
last_emf = back_emf[non_conductive_phase];
}
// 电机启动(开环预定位+加速)
void BLDC_Start(void) {
// 1. 预定位(强制UV相导通,锁定转子)
comm_state = COMM_STATE_UV;
BLDC_Commutate(comm_state);
PWM_SetDuty(START_DUTY);
HAL_Delay(100); // 锁定100ms
// 2. 开环启动(按换相顺序加速)
for (int speed=100; speed<=MAX_SPEED; speed+=ACCEL_STEP) {
duty_cycle = START_DUTY + (speed - 100) * 0.1; // 占空比随速度增加
PWM_SetDuty(duty_cycle);
comm_state = (comm_state + 1) % 6; // 换相
BLDC_Commutate(comm_state);
HAL_Delay(50); // 每步加速50ms
if (/* 反电动势可检测 */ 1) { // 实际需判断反电动势幅值>阈值
start_flag = 1; // 切换到闭环运行
break;
}
}
}
4.2.4 主函数(main.c)
#include "main.h"
#include "bldc.h"
#include "adc.h"
#include "protection.h"
int main(void) {
HAL_Init();
SystemClock_Config(); // 168MHz时钟配置
BLDC_Init(); // 无刷电机驱动初始化
ADC_Start(); // 启动ADC采样(DMA模式)
BLDC_Start(); // 电机启动
while (1) {
BLDC_Update_BackEMF(); // 更新反电动势与换相
BLDC_Protection(); // 过流/过压保护
HAL_Delay(1); // 1ms循环
}
}
参考代码 Stm32无刷直流电机无霍尔驱动程序keil工程 www.youwenfan.com/contentcnt/182357.html
五、测试与验证
-
硬件连接:按3.2节连接STM32、IR2104、MOSFET逆变桥、电机,确保电源隔离。
-
启动测试:上电后观察电机是否平滑启动,无剧烈抖动。
-
稳态测试:用示波器测量相电压波形,确认换相频率与转速对应(如3000RPM时,6对极电机换相频率=3000/60×6=300Hz)。
-
保护测试:短接电机相线模拟过流,观察是否触发保护(关闭PWM输出)。
浙公网安备 33010602011771号