基于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输出)。

目录
相关文章
|
2月前
|
安全 JavaScript 前端开发
Burp Suite Professional 2026.4 发布 - 领先的 Web 渗透测试软件
Burp Suite Professional 2026.4 发布 - 领先的 Web 渗透测试软件
260 1
Burp Suite Professional 2026.4 发布 - 领先的 Web 渗透测试软件
|
2月前
|
人工智能 小程序 机器人
超详细!OpenClaw一键部署实操教程,快速上手不踩坑
OpenClaw是开源AI智能体,可处理文件、操控浏览器、接入钉钉等IM工具。本文详解阿里云三大一键部署方案(轻量服务器/计算巢/无影云电脑),2步完成部署,零代码配置,助你快速启用“数字员工”!
681 5
|
2月前
|
缓存 小程序 算法
外卖配送小程序开发核心难点:调度系统与订单分发机制解析
外卖配送小程序开发的核心不在前端界面,而在后端两大能力:智能调度系统(决定配送效率)与科学订单分发机制(保障稳定性和骑手体验)。多数项目“能用但跑不动”,症结恰在此——缺乏多约束实时优化、动态评分派单、多单路径规划及高并发架构设计。
|
2月前
|
人工智能 IDE 开发工具
Zed 编辑器小修小补:让 diff 颜色终于“说人话“了!
本文详解Zed IDE在diff颜色语义化上的精妙改进:新增行用绿色、删除行用红色,真正符合直觉;通过专属token解耦样式与语义,提升主题兼容性与可维护性,并为未来扩展预留接口。小改动,大体验!
177 1
|
2月前
|
安全 Python Windows
Windows如何安装老版本的Python?
Windows用户安装旧版Python(如3.7)时,官网已下架安装包。可卸载当前版本后,在CMD中执行`winget install python.python.3.7`,自动安全安装该版本最新发布版,支持灵活更换版本号。
271 1
|
2月前
|
物联网 5G 定位技术
室外定位技术补充:蜂窝网络定位底层原理与未来主流
蜂窝网络定位(LBS)是GNSS的重要补充,适用于隧道、高楼遮挡等信号弱区,依托4G/5G基站实现广覆盖、高稳定定位;精度从Cell-ID的500m至5G AOA的1–3m,支持紧急响应与智慧应用。(239字)
|
2月前
|
人工智能 弹性计算 机器人
超详细!Hermes Agent一键部署实操教程,快速上手不踩坑
Hermes Agent是Nous Research开源的自主AI智能体,支持自进化、持久记忆与多平台接入。阿里云提供轻量服务器、计算巢、无影云电脑三大一键部署方案,最快两步完成,新手30分钟即可上手实操!
1054 1
|
2月前
|
人工智能 缓存 BI
Claude Code + DeepSeek V4-Pro 真实评测:除了贵,没别的毛病
JeecgBoot AI专题研究 把 Claude Code 接入 DeepSeek V4Pro,跑完 Skills —— OA 审批、大屏、报表、部署 5 大实战场景后的真实体验 ![](https://oscimg.oschina.net/oscnet/up608d34aeb6bafc47f
8753 23
Claude Code + DeepSeek V4-Pro 真实评测:除了贵,没别的毛病
|
6天前
|
算法 安全 新能源
基于 STM32 的数字控制实现双向 DC-DC 电源
双向 DC-DC 电源(Bidirectional DC-DC Converter)是一种能够在两个直流电压等级之间进行能量双向流动的电力电子变换装置。它集升压(Boost)和降压(Buck)功能于一体,广泛应用于新能源储能系统、电动汽车、电池化成设备以及 UPS 系统中
234 0
|
2月前
|
传感器 数据可视化 Python
太极场生命能量模型:用科学重新发现“气”
本文介绍了“太极场生命能量模型”,旨在用量子相干、心率变异性(HRV)和信息场理论,将传统太极、气功中的“气”概念转化为可计算、可验证的科学模型。作者基于对127位长期练习者的生理信号测量,发现深度放松时 HRV 相干性显著提升,且皮肤电导呈现约0.1Hz的阴阳交替振荡,由此提出太极场是一种不同于电磁场的信息-能量耦合场,并以相干因子 Z(可通过 HRV 相干比测量)为核心变量,用非线性函数描述阴阳平衡。项目已发布理论框架和 Python 模拟器,正在设计低成本探测仪,并公开数据模板。文章鼓励编程、硬件、爱好者等多方参与,未来希望验证太极场的隔空影响、开发太极能量手
212 1