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

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

一、系统概述

基于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/contentalh/182357.html

五、测试与验证

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

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

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

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

目录
相关文章
|
17小时前
|
人工智能 缓存 BI
Claude Code + DeepSeek V4-Pro 真实评测:除了贵,没别的毛病
JeecgBoot AI专题研究 把 Claude Code 接入 DeepSeek V4Pro,跑完 Skills —— OA 审批、大屏、报表、部署 5 大实战场景后的真实体验 ![](https://oscimg.oschina.net/oscnet/up608d34aeb6bafc47f
152 0
Claude Code + DeepSeek V4-Pro 真实评测:除了贵,没别的毛病
|
19小时前
|
安全 JavaScript 前端开发
Burp Suite Professional 2026.4 发布 - 领先的 Web 渗透测试软件
Burp Suite Professional 2026.4 发布 - 领先的 Web 渗透测试软件
30 1
Burp Suite Professional 2026.4 发布 - 领先的 Web 渗透测试软件
|
17小时前
|
人工智能 自然语言处理 测试技术
DeepSeek V4:百万上下文,万亿参数,以及重新泛起涟漪的开源池塘
DeepSeek V4发布Pro(1.6T参数/49B激活)与Flash(284B/13B)双模型,均支持1M上下文、thinking模式及Agent能力。全栈开源(权重+技术报告+API+定价),采用混合注意力架构显著降本,中文长文本与推理能力突出,是当前少有的万亿级开源系统级发布
161 2
DeepSeek V4:百万上下文,万亿参数,以及重新泛起涟漪的开源池塘
|
20小时前
|
安全 Python Windows
Windows如何安装老版本的Python?
Windows用户安装旧版Python(如3.7)时,官网已下架安装包。可卸载当前版本后,在CMD中执行`winget install python.python.3.7`,自动安全安装该版本最新发布版,支持灵活更换版本号。
|
12小时前
|
运维 Devops 开发工具
生产环境缺陷管理
git-poison是基于go-git的分布式Bug协同管理工具,通过“投毒/解毒/银针”机制自动追溯、阻塞与召回缺陷代码,解决多分支下bug漏修、漏发、漏确认等生产安全问题,已落地验证一年,显著降低人工协同成本。
25 0
生产环境缺陷管理
|
13天前
|
机器学习/深度学习 并行计算
基于MATLAB的HOG+SVM图像二分类实现方案
基于MATLAB的HOG+SVM图像二分类实现方案
128 1
|
11小时前
|
人工智能 弹性计算 机器人
超详细!Hermes Agent一键部署实操教程,快速上手不踩坑
Hermes Agent是Nous Research开源的自主AI智能体,支持自进化、持久记忆与多平台接入。阿里云提供轻量服务器、计算巢、无影云电脑三大一键部署方案,最快两步完成,新手30分钟即可上手实操!
85 0
|
22小时前
|
人工智能 运维 安全
阿里云JVS Claw官网链接在哪?JVSClaw和OpenClaw有啥区别?附阿里版龙虾安装教程
阿里云JVS Claw是基于OpenClaw框架打造的SaaS化AI智能体平台,JVS Claw官网:https://t.aliyun.com/U/IJbaxg 开箱即用、免部署运维,支持云端/本地双模式运行。7天免费试用,39元/月起,内置办公技能与ClawHub生态,适合非技术用户快速落地自动化任务。
|
22小时前
|
物联网 5G 定位技术
室外定位技术补充:蜂窝网络定位底层原理与未来主流
蜂窝网络定位(LBS)是GNSS的重要补充,适用于隧道、高楼遮挡等信号弱区,依托4G/5G基站实现广覆盖、高稳定定位;精度从Cell-ID的500m至5G AOA的1–3m,支持紧急响应与智慧应用。(239字)
|
16小时前
|
移动开发 小程序 容器
知识付费系统源码开发方案:课程、会员、营销一体化实现方案详解
围绕知识付费系统源码开发,本文从课程模块设计、会员体系搭建、营销裂变功能以及一体化架构趋势展开解析,深入探讨内容付费平台源码如何实现课程、会员、营销闭环运营,为教育机构、创业团队和知识变现项目提供参考。