基于霍尔传感器的BLDC控制源码

基于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.cmain.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

知识点补充:

  1. 霍尔接线与换相表匹配
    代码中的 switch(hall_state) 换相顺序是基于特定的霍尔安装方式(常见的120度间隔霍尔)。如果你发现电机在某一个方向震动但不转,或者转动时有顿挫感,说明你的霍尔UVW线序或者换相表顺序不对 。此时只需将霍尔信号的读取顺序调换,或者重新排列 case 里的导通逻辑即可。
  2. 死区时间(Dead Time)
    上下管导通切换时,必须留出一个极短的空白时间(通常几百纳秒),防止上下管直通导致电源对地短路烧毁MOS管。在 sBreakDeadTimeConfig.DeadTime 中需要根据你的STM32主频精确计算。
  3. 无感控制(反电动势)
    上述代码适用于有霍尔传感器 的电机。如果你想做无感(Sensorless)控制,需要将霍尔读取部分替换为三个 ADC通道 实时采样电机悬空相的电压(反电动势),当采样值过零点时(由正变负或由负变正),触发定时器中断进行换相。无感控制的难点在于启动算法(通常采用强行拖拽同步启动)。
相关推荐
ytttr8732 小时前
DSP 28335 CAN总线通信程序
开发语言·stm32·单片机
一枝小雨4 小时前
RISC-V架构sp寄存器 & RISC-V架构下FreeRTOS任务上下文保存与恢复
单片机·架构·嵌入式·risc-v·rtos·内核原理
BW.SU5 小时前
PackagingTool 嵌入式资源打包合并工具
单片机·二进制·嵌入式开发·资源合并软件·图片打包
长安第一美人6 小时前
工业级实时监控系统开发:PHP+ZMQ+JS 前后端分离架构全解析
前端·嵌入式硬件·架构·交互·rk3588·zmq后端
田甲6 小时前
STM32开发环境迁移实践:从 CubeMX 生成 CMake 工程到 VS Code 编译与调试
stm32·单片机·嵌入式硬件
hoiii1876 小时前
在 STM32F1上读取 BMX055 三轴加速度
stm32·单片机·嵌入式硬件
嵌入式小站7 小时前
STM32 零基础可移植教程 04:按键输入,为什么按下去读到的是 0 或 1
chrome·stm32·嵌入式硬件
三佛科技-187366133977 小时前
BP8522D贴片SOP7,5V150mA高集成度无VCC电容降压型恒压芯片解析
单片机·嵌入式硬件
csg11077 小时前
MSP430F149驱动T8650北斗模块实现短报文通信实战
单片机·嵌入式硬件·物联网·自动化