基于STM32的无刷直流电机无霍尔驱动程序(Keil工程)

一、系统概述

基于STM32F407ZGT6(Cortex-M4,168MHz,带FPU)实现无刷直流电机(BLDC)无霍尔传感器驱动,采用反电动势(Back-EMF)过零点检测法实现转子位置估算,结合六步换相控制完成电机启动与稳态运行。核心功能包括:PWM驱动三相逆变桥、反电动势采样与过零检测、开环/闭环启动、换相逻辑控制、过流/过压保护,适用于电动工具、无人机、工业风机等场景。

二、核心原理

无霍尔驱动通过检测非导通相的反电动势过零点间接获取转子位置(反电动势在过零点后30°电角度换相)。系统分为启动阶段(开环预定位+加速)和运行阶段(反电动势闭环换相),具体流程:

  1. 预定位:强制给定子某两相通电,将转子锁定到已知位置;

  2. 开环启动:按固定顺序换相,逐渐提高转速,直至反电动势可检测;

  3. 闭环运行:通过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

五、测试与验证

  1. 硬件连接:按3.2节连接STM32、IR2104、MOSFET逆变桥、电机,确保电源隔离。

  2. 启动测试:上电后观察电机是否平滑启动,无剧烈抖动。

  3. 稳态测试:用示波器测量相电压波形,确认换相频率与转速对应(如3000RPM时,6对极电机换相频率=3000/60×6=300Hz)。

  4. 保护测试:短接电机相线模拟过流,观察是否触发保护(关闭PWM输出)。

posted @ 2026-04-05 09:13  anpijj  阅读(25)  评论(0)    收藏  举报