STM32直流无刷电机(BLDC)六拍方波控制程序,包含霍尔传感器检测、PWM驱动、启动控制、速度闭环等功能。
一、系统架构
1.1 硬件连接
STM32F103C8T6 (主控)
├── 三相全桥驱动 (6个MOSFET/IGBT)
│ ├── UH → PA8 (TIM1_CH1) // 上桥U相
│ ├── UL → PA7 (TIM1_CH1N) // 下桥U相
│ ├── VH → PA9 (TIM1_CH2) // 上桥V相
│ ├── VL → PB0 (TIM1_CH2N) // 下桥V相
│ ├── WH → PA10 (TIM1_CH3) // 上桥W相
│ └── WL → PB1 (TIM1_CH3N) // 下桥W相
├── 霍尔传感器输入
│ ├── HALL_U → PA0 (TIM5_CH1) // U相霍尔
│ ├── HALL_V → PA1 (TIM5_CH2) // V相霍尔
│ └── HALL_W → PA2 (TIM5_CH3) // W相霍尔
├── 电流检测
│ ├── ADC1 → PA3 // 电流检测
│ └── 过流保护 → PA4
├── 编码器接口 (可选)
│ ├── ENC_A → PA6 (TIM3_CH1)
│ └── ENC_B → PA7 (TIM3_CH2)
├── 控制接口
│ ├── 启动/停止 → PB12
│ ├── 方向控制 → PB13
│ └── 速度调节 → PA5 (ADC)
└── 状态指示
├── LED_RUN → PC13
├── LED_FAULT → PC14
└── 蜂鸣器 → PC15
1.2 六拍换相顺序
电角度 霍尔状态 通电相 功率管导通
0-60° 101 U+ W- Q1, Q6
60-120° 100 U+ V- Q1, Q2
120-180° 110 W+ V- Q5, Q2
180-240° 010 W+ U- Q5, Q4
240-300° 011 V+ U- Q3, Q4
300-360° 001 V+ W- Q3, Q6
二、核心驱动程序
2.1 主程序框架
c
/**
* @file main.c
* @brief BLDC六拍方波控制器主程序
*/
#include "main.h"
#include "bldc_driver.h"
#include "hall_sensor.h"
#include "pid_controller.h"
#include "fault_handler.h"
#include <stdio.h>
#include <string.h>
/* 全局变量 */
BLDC_Motor motor = {0};
PID_Controller speed_pid = {0};
uint32_t system_tick = 0;
uint8_t system_state = SYS_STOP;
/* 函数声明 */
void SystemClock_Config(void);
void GPIO_Init(void);
void TIM1_PWM_Init(void);
void TIM5_HALL_Init(void);
void ADC_Init(void);
void NVIC_Init(void);
void Motor_Start(void);
void Motor_Stop(void);
void Motor_SetSpeed(uint16_t speed_rpm);
void Motor_SetDirection(uint8_t dir);
void System_Task_10ms(void);
void System_Task_100ms(void);
void System_Task_1000ms(void);
/**
* @brief 主函数
*/
int main(void)
{
/* HAL库初始化 */
HAL_Init();
/* 系统时钟配置 */
SystemClock_Config();
/* 外设初始化 */
GPIO_Init();
TIM1_PWM_Init();
TIM5_HALL_Init();
ADC_Init();
NVIC_Init();
/* 电机初始化 */
BLDC_Init(&motor);
/* PID初始化 */
PID_Init(&speed_pid, 0.5, 0.1, 0.01, 1000, 1000);
printf("BLDC Six-Step Controller Ready!\n");
printf("System Clock: %d Hz\n", SystemCoreClock);
printf("PWM Frequency: %d Hz\n", PWM_FREQUENCY);
/* 主循环 */
while(1)
{
uint32_t current_tick = HAL_GetTick();
/* 1ms任务 */
if(current_tick - system_tick >= 1)
{
system_tick = current_tick;
static uint16_t ms_counter = 0;
ms_counter++;
/* 10ms任务 */
if(ms_counter >= 10)
{
ms_counter = 0;
System_Task_10ms();
}
/* 100ms任务 */
if(ms_counter % 10 == 0)
{
System_Task_100ms();
}
/* 1000ms任务 */
if(ms_counter == 0)
{
System_Task_1000ms();
}
}
/* 空闲处理 */
if(system_state == SYS_STOP)
{
__WFI(); // 进入低功耗模式
}
}
}
/**
* @brief 10ms任务
*/
void System_Task_10ms(void)
{
/* 霍尔传感器处理 */
Hall_Process(&motor);
/* 速度计算 */
BLDC_CalculateSpeed(&motor);
/* 电流检测 */
Current_Protection_Check();
/* 温度检测 */
Temperature_Protection_Check();
}
/**
* @brief 100ms任务
*/
void System_Task_100ms(void)
{
static uint8_t led_counter = 0;
/* 状态指示灯闪烁 */
if(motor.state == MOTOR_RUNNING)
{
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
}
else
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
}
/* 按键扫描 */
static uint32_t last_key_time = 0;
uint32_t current_time = HAL_GetTick();
if(current_time - last_key_time > 200) // 200ms去抖
{
/* 启动/停止按键 */
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == GPIO_PIN_RESET)
{
last_key_time = current_time;
if(system_state == SYS_STOP)
{
Motor_Start();
}
else
{
Motor_Stop();
}
}
/* 方向控制按键 */
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_13) == GPIO_PIN_RESET)
{
last_key_time = current_time;
Motor_SetDirection(!motor.direction);
}
}
}
/**
* @brief 1000ms任务
*/
void System_Task_1000ms(void)
{
/* 状态报告 */
printf("State: %s, Speed: %d RPM, Duty: %d%%, Current: %.2fA\n",
(motor.state == MOTOR_RUNNING) ? "RUN" : "STOP",
motor.speed_rpm,
motor.pwm_duty * 100 / PWM_MAX_DUTY,
motor.current);
/* 故障状态检查 */
if(motor.fault_flags != 0)
{
printf("Fault: 0x%02X\n", motor.fault_flags);
}
}
2.2 BLDC驱动头文件
c
/**
* @file bldc_driver.h
* @brief BLDC六拍方波驱动
*/
#ifndef __BLDC_DRIVER_H
#define __BLDC_DRIVER_H
#include "stm32f1xx_hal.h"
#include <stdint.h>
#include <stdbool.h>
/* 系统配置 */
#define PWM_FREQUENCY 16000 // PWM频率 16kHz
#define PWM_PERIOD (SystemCoreClock / PWM_FREQUENCY) - 1
#define PWM_MAX_DUTY 1000 // 最大占空比
#define PWM_DEAD_TIME 72 // 死区时间 (72/72MHz=1us)
#define MIN_DUTY 50 // 最小占空比
#define MAX_DUTY 950 // 最大占空比
/* 系统状态 */
typedef enum {
SYS_STOP = 0,
SYS_STARTING,
SYS_RUNNING,
SYS_FAULT
} SystemState;
/* 电机状态 */
typedef enum {
MOTOR_STOP = 0,
MOTOR_ALIGN,
MOTOR_START_OPENLOOP,
MOTOR_RUNNING,
MOTOR_FAULT
} MotorState;
/* 旋转方向 */
typedef enum {
DIR_CW = 0, // 顺时针
DIR_CCW = 1 // 逆时针
} Direction;
/* 六拍换相表 */
typedef struct {
uint8_t hall_state; // 霍尔状态
uint8_t uh_state; // U上桥状态
uint8_t ul_state; // U下桥状态
uint8_t vh_state; // V上桥状态
uint8_t vl_state; // V下桥状态
uint8_t wh_state; // W上桥状态
uint8_t wl_state; // W下桥状态
} CommutationStep;
/* 电机参数结构体 */
typedef struct {
MotorState state; // 电机状态
Direction direction; // 旋转方向
uint16_t speed_rpm; // 当前转速
uint16_t target_rpm; // 目标转速
uint16_t pwm_duty; // PWM占空比
uint8_t comm_step; // 当前换相步
uint8_t hall_state; // 霍尔传感器状态
uint32_t hall_timestamp; // 霍尔变化时间戳
uint32_t last_hall_time; // 上次霍尔变化时间
uint16_t electrical_angle; // 电角度
float current; // 相电流
float voltage; // 母线电压
float temperature; // 温度
uint8_t fault_flags; // 故障标志
uint32_t start_time; // 启动时间
uint8_t align_counter; // 对位计数
} BLDC_Motor;
/* 故障标志位 */
#define FAULT_OVERCURRENT (1 << 0)
#define FAULT_OVERVOLTAGE (1 << 1)
#define FAULT_OVERTEMP (1 << 2)
#define FAULT_STALL (1 << 3)
#define FAULT_HALL_ERROR (1 << 4)
#define FAULT_UNDERVOLTAGE (1 << 5)
/* 函数声明 */
void BLDC_Init(BLDC_Motor *motor);
void BLDC_SetCommutation(uint8_t step);
void BLDC_UpdateCommutation(void);
void BLDC_SetPWM(uint16_t duty);
void BLDC_Start(void);
void BLDC_Stop(void);
void BLDC_Brake(void);
void BLDC_SetDirection(Direction dir);
void BLDC_CalculateSpeed(BLDC_Motor *motor);
uint8_t BLDC_GetNextCommStep(uint8_t current_step, Direction dir);
void BLDC_ClearFault(void);
uint8_t BLDC_CheckFault(void);
void BLDC_StartupSequence(void);
/* 外部变量 */
extern BLDC_Motor motor;
extern const CommutationStep comm_table_cw[6];
extern const CommutationStep comm_table_ccw[6];
#endif /* __BLDC_DRIVER_H */
2.3 BLDC驱动实现
c
/**
* @file bldc_driver.c
* @brief BLDC驱动实现
*/
#include "bldc_driver.h"
#include "hall_sensor.h"
/* 全局变量 */
BLDC_Motor motor = {0};
/* 六拍换相表 (顺时针) */
const CommutationStep comm_table_cw[6] = {
// 霍尔101: U+ W- (Q1, Q6)
{0x05, 1, 0, 0, 0, 0, 1},
// 霍尔100: U+ V- (Q1, Q2)
{0x04, 1, 0, 0, 1, 0, 0},
// 霍尔110: W+ V- (Q5, Q2)
{0x06, 0, 0, 0, 1, 1, 0},
// 霍尔010: W+ U- (Q5, Q4)
{0x02, 0, 1, 0, 0, 1, 0},
// 霍尔011: V+ U- (Q3, Q4)
{0x03, 0, 1, 1, 0, 0, 0},
// 霍尔001: V+ W- (Q3, Q6)
{0x01, 0, 0, 1, 0, 0, 1}
};
/* 六拍换相表 (逆时针) */
const CommutationStep comm_table_ccw[6] = {
// 霍尔001: V+ W- (Q3, Q6)
{0x01, 0, 0, 1, 0, 0, 1},
// 霍尔011: V+ U- (Q3, Q4)
{0x03, 0, 1, 1, 0, 0, 0},
// 霍尔010: W+ U- (Q5, Q4)
{0x02, 0, 1, 0, 0, 1, 0},
// 霍尔110: W+ V- (Q5, Q2)
{0x06, 0, 0, 0, 1, 1, 0},
// 霍尔100: U+ V- (Q1, Q2)
{0x04, 1, 0, 0, 1, 0, 0},
// 霍尔101: U+ W- (Q1, Q6)
{0x05, 1, 0, 0, 0, 0, 1}
};
/**
* @brief BLDC初始化
*/
void BLDC_Init(BLDC_Motor *motor)
{
if(motor == NULL) return;
/* 初始化电机参数 */
memset(motor, 0, sizeof(BLDC_Motor));
motor->state = MOTOR_STOP;
motor->direction = DIR_CW;
motor->speed_rpm = 0;
motor->target_rpm = 1000; // 默认目标转速1000RPM
motor->pwm_duty = 0;
motor->comm_step = 0;
motor->hall_state = 0;
motor->fault_flags = 0;
motor->electrical_angle = 0;
/* 关闭所有PWM输出 */
BLDC_Stop();
printf("BLDC Motor initialized\n");
}
/**
* @brief 设置换相步骤
* @param step 换相步骤 (0-5)
*/
void BLDC_SetCommutation(uint8_t step)
{
if(step >= 6) return;
const CommutationStep *comm_table = (motor.direction == DIR_CW) ?
comm_table_cw : comm_table_ccw;
const CommutationStep *comm = &comm_table[step];
/* 设置PWM输出状态 */
if(comm->uh_state)
{
/* U上桥PWM输出 */
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, motor.pwm_duty);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
}
else
{
/* U上桥关闭 */
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
}
if(comm->ul_state)
{
/* U下桥PWM输出 */
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1N, motor.pwm_duty);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1N);
}
else
{
/* U下桥关闭 */
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1N);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);
}
if(comm->vh_state)
{
/* V上桥PWM输出 */
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, motor.pwm_duty);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
}
else
{
/* V上桥关闭 */
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_2);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET);
}
if(comm->vl_state)
{
/* V下桥PWM输出 */
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2N, motor.pwm_duty);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2N);
}
else
{
/* V下桥关闭 */
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_2N);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
}
if(comm->wh_state)
{
/* W上桥PWM输出 */
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, motor.pwm_duty);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
}
else
{
/* W上桥关闭 */
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_3);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_RESET);
}
if(comm->wl_state)
{
/* W下桥PWM输出 */
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3N, motor.pwm_duty);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3N);
}
else
{
/* W下桥关闭 */
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_3N);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
}
motor->comm_step = step;
motor->electrical_angle = step * 60; // 每步60度电角度
}
/**
* @brief 更新换相
*/
void BLDC_UpdateCommutation(void)
{
uint8_t hall_state = Hall_GetState();
if(hall_state != motor.hall_state)
{
motor.hall_state = hall_state;
motor.last_hall_time = motor.hall_timestamp;
motor.hall_timestamp = HAL_GetTick();
/* 根据霍尔状态和方向确定换相步骤 */
uint8_t new_step = 0;
const CommutationStep *comm_table = (motor.direction == DIR_CW) ?
comm_table_cw : comm_table_ccw;
for(uint8_t i = 0; i < 6; i++)
{
if(comm_table[i].hall_state == hall_state)
{
new_step = i;
break;
}
}
/* 执行换相 */
BLDC_SetCommutation(new_step);
}
}
/**
* @brief 设置PWM占空比
* @param duty 占空比 (0-1000)
*/
void BLDC_SetPWM(uint16_t duty)
{
if(duty > PWM_MAX_DUTY) duty = PWM_MAX_DUTY;
motor.pwm_duty = duty;
/* 更新当前PWM占空比 */
switch(motor.comm_step)
{
case 0: // U+ W-
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, duty);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3N, duty);
break;
case 1: // U+ V-
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, duty);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2N, duty);
break;
case 2: // W+ V-
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, duty);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2N, duty);
break;
case 3: // W+ U-
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, duty);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1N, duty);
break;
case 4: // V+ U-
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, duty);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1N, duty);
break;
case 5: // V+ W-
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, duty);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3N, duty);
break;
}
}
/**
* @brief 启动电机
*/
void BLDC_Start(void)
{
if(motor.state != MOTOR_STOP && motor.state != MOTOR_FAULT)
return;
if(motor.fault_flags != 0)
{
printf("Cannot start motor with fault: 0x%02X\n", motor.fault_flags);
return;
}
motor.state = MOTOR_ALIGN;
motor.start_time = HAL_GetTick();
motor.align_counter = 0;
printf("Motor starting...\n");
/* 启动序列 */
BLDC_StartupSequence();
}
/**
* @brief 停止电机
*/
void BLDC_Stop(void)
{
motor.state = MOTOR_STOP;
motor.speed_rpm = 0;
motor.pwm_duty = 0;
/* 关闭所有PWM输出 */
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1N);
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_2);
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_2N);
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_3);
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_3N);
/* 关闭所有GPIO输出 */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
printf("Motor stopped\n");
}
/**
* @brief 刹车
*/
void BLDC_Brake(void)
{
/* 三相下桥全开,上桥全关,实现能耗制动 */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET); // UL
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // VL
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET); // WL
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); // UH
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET); // VH
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_RESET); // WH
motor.state = MOTOR_STOP;
printf("Motor brake applied\n");
}
/**
* @brief 设置旋转方向
* @param dir 方向
*/
void BLDC_SetDirection(Direction dir)
{
if(motor.state == MOTOR_RUNNING)
{
printf("Cannot change direction while motor is running\n");
return;
}
motor.direction = dir;
printf("Direction set to %s\n", (dir == DIR_CW) ? "CW" : "CCW");
}
/**
* @brief 计算转速
* @param motor 电机结构体指针
*/
void BLDC_CalculateSpeed(BLDC_Motor *motor)
{
static uint32_t last_hall_time = 0;
static uint8_t last_hall_state = 0;
if(motor->hall_state != last_hall_state)
{
uint32_t current_time = HAL_GetTick();
uint32_t delta_time = current_time - last_hall_time;
if(delta_time > 0 && delta_time < 1000) // 有效时间范围
{
/* 每6个霍尔状态变化为一圈 (6步换相) */
/* 每个霍尔状态变化对应60度电角度,6个变化为360度 */
/* 计算RPM: RPM = (1 / (delta_time * 6 / 1000 / 60)) */
motor->speed_rpm = 60000 / (delta_time * 6);
}
else
{
motor->speed_rpm = 0;
}
last_hall_time = current_time;
last_hall_state = motor->hall_state;
}
}
/**
* @brief 启动序列
*/
void BLDC_StartupSequence(void)
{
uint32_t current_time = HAL_GetTick();
switch(motor.state)
{
case MOTOR_ALIGN:
/* 预定位阶段 */
if(current_time - motor.start_time < 1000) // 1秒预定位
{
/* 强制定位到0度位置 (U+ V-) */
BLDC_SetCommutation(1); // 霍尔100对应
BLDC_SetPWM(100); // 10%占空比
}
else
{
/* 进入开环启动 */
motor.state = MOTOR_START_OPENLOOP;
motor.start_time = current_time;
printf("Entering open-loop start\n");
}
break;
case MOTOR_START_OPENLOOP:
/* 开环加速阶段 */
if(current_time - motor.start_time < 5000) // 5秒加速
{
static uint32_t last_comm_time = 0;
static uint16_t openloop_speed = 50;
/* 逐步增加占空比 */
if(current_time - motor.start_time < 1000)
{
openloop_speed = 100; // 10%
}
else if(current_time - motor.start_time < 2000)
{
openloop_speed = 200; // 20%
}
else if(current_time - motor.start_time < 3000)
{
openloop_speed = 300; // 30%
}
else
{
openloop_speed = 400; // 40%
}
BLDC_SetPWM(openloop_speed);
/* 强制换相 (固定频率) */
if(current_time - last_comm_time > 20) // 50Hz换相
{
last_comm_time = current_time;
motor.comm_step = (motor.comm_step + 1) % 6;
BLDC_SetCommutation(motor.comm_step);
}
/* 检查是否达到切换速度 */
if(motor.speed_rpm > 300)
{
motor.state = MOTOR_RUNNING;
printf("Entering closed-loop running\n");
}
}
else
{
/* 启动超时 */
motor.state = MOTOR_FAULT;
motor.fault_flags |= FAULT_STALL;
printf("Startup timeout\n");
}
break;
case MOTOR_RUNNING:
/* 正常运行,已由霍尔传感器控制换相 */
break;
default:
break;
}
}
2.4 霍尔传感器驱动
c
/**
* @file hall_sensor.h
* @brief 霍尔传感器驱动
*/
#ifndef __HALL_SENSOR_H
#define __HALL_SENSOR_H
#include "bldc_driver.h"
/* 函数声明 */
void Hall_Init(void);
uint8_t Hall_GetState(void);
void Hall_Process(BLDC_Motor *motor);
uint8_t Hall_ValidateState(uint8_t state);
void Hall_ErrorHandler(uint8_t expected_state, uint8_t actual_state);
uint8_t Hall_GetNextState(uint8_t current_state, Direction dir);
/* 霍尔传感器有效状态 */
#define HALL_STATE_001 0x01
#define HALL_STATE_010 0x02
#define HALL_STATE_011 0x03
#define HALL_STATE_100 0x04
#define HALL_STATE_101 0x05
#define HALL_STATE_110 0x06
/* 霍尔传感器无效状态 */
#define HALL_STATE_000 0x00
#define HALL_STATE_111 0x07
#endif /* __HALL_SENSOR_H */
c
/**
* @file hall_sensor.c
* @brief 霍尔传感器驱动实现
*/
#include "hall_sensor.h"
/* 霍尔传感器引脚定义 */
#define HALL_U_PIN GPIO_PIN_0
#define HALL_U_PORT GPIOA
#define HALL_V_PIN GPIO_PIN_1
#define HALL_V_PORT GPIOA
#define HALL_W_PIN GPIO_PIN_2
#define HALL_W_PORT GPIOA
/* 霍尔传感器状态转换表 (顺时针) */
static const uint8_t hall_next_state_cw[7] = {
0xFF, // 000 - 无效
0x05, // 001 -> 101
0x03, // 010 -> 011
0x06, // 011 -> 110
0x01, // 100 -> 001
0x04, // 101 -> 100
0x02 // 110 -> 010
};
/* 霍尔传感器状态转换表 (逆时针) */
static const uint8_t hall_next_state_ccw[7] = {
0xFF, // 000 - 无效
0x04, // 001 -> 100
0x06, // 010 -> 110
0x02, // 011 -> 010
0x05, // 100 -> 101
0x01, // 101 -> 001
0x03 // 110 -> 011
};
/**
* @brief 霍尔传感器初始化
*/
void Hall_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* 使能GPIOA时钟 */
__HAL_RCC_GPIOA_CLK_ENABLE();
/* 配置霍尔传感器引脚为上拉输入 */
GPIO_InitStruct.Pin = HALL_U_PIN | HALL_V_PIN | HALL_W_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP; // 霍尔传感器通常是开漏输出
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
printf("Hall sensors initialized\n");
}
/**
* @brief 获取霍尔传感器状态
* @return 霍尔状态 (3位: H3 H2 H1)
*/
uint8_t Hall_GetState(void)
{
uint8_t state = 0;
/* 读取霍尔传感器值 (低电平有效) */
if(HAL_GPIO_ReadPin(HALL_U_PORT, HALL_U_PIN) == GPIO_PIN_RESET)
state |= 0x01; // H1
if(HAL_GPIO_ReadPin(HALL_V_PORT, HALL_V_PIN) == GPIO_PIN_RESET)
state |= 0x02; // H2
if(HAL_GPIO_ReadPin(HALL_W_PORT, HALL_W_PIN) == GPIO_PIN_RESET)
state |= 0x04; // H3
return state;
}
/**
* @brief 处理霍尔传感器
* @param motor 电机结构体指针
*/
void Hall_Process(BLDC_Motor *motor)
{
static uint8_t last_valid_state = 0;
static uint32_t error_count = 0;
uint8_t current_state = Hall_GetState();
/* 验证霍尔状态 */
if(Hall_ValidateState(current_state))
{
if(current_state != motor->hall_state)
{
/* 霍尔状态变化 */
motor->hall_state = current_state;
motor->last_hall_time = motor->hall_timestamp;
motor->hall_timestamp = HAL_GetTick();
/* 检查霍尔序列是否正确 */
if(last_valid_state != 0)
{
uint8_t expected_state = Hall_GetNextState(last_valid_state, motor->direction);
if(expected_state != current_state)
{
Hall_ErrorHandler(expected_state, current_state);
error_count++;
if(error_count > 10) // 连续10次错误
{
motor->fault_flags |= FAULT_HALL_ERROR;
printf("Hall sensor sequence error\n");
}
}
else
{
error_count = 0; // 重置错误计数
}
}
last_valid_state = current_state;
/* 更新换相 */
if(motor->state == MOTOR_RUNNING)
{
BLDC_UpdateCommutation();
}
}
}
else
{
/* 无效霍尔状态 */
if(current_state == HALL_STATE_000 || current_state == HALL_STATE_111)
{
error_count++;
if(error_count > 5) // 连续5次无效状态
{
motor->fault_flags |= FAULT_HALL_ERROR;
printf("Invalid hall state: 0x%02X\n", current_state);
}
}
}
}
/**
* @brief 验证霍尔状态
* @param state 霍尔状态
* @return 1:有效, 0:无效
*/
uint8_t Hall_ValidateState(uint8_t state)
{
/* 只允许6个有效状态 */
return (state >= 1 && state <= 6);
}
/**
* @brief 霍尔错误处理
* @param expected_state 期望状态
* @param actual_state 实际状态
*/
void Hall_ErrorHandler(uint8_t expected_state, uint8_t actual_state)
{
printf("Hall sequence error: Expected 0x%02X, Got 0x%02X\n",
expected_state, actual_state);
/* 可以根据错误类型采取不同措施 */
if(actual_state == 0x00 || actual_state == 0x07)
{
/* 霍尔传感器失效 */
}
else
{
/* 霍尔传感器错位 */
}
}
/**
* @brief 获取下一个霍尔状态
* @param current_state 当前状态
* @param dir 旋转方向
* @return 下一个预期状态
*/
uint8_t Hall_GetNextState(uint8_t current_state, Direction dir)
{
if(current_state < 1 || current_state > 6)
return 0xFF;
if(dir == DIR_CW)
return hall_next_state_cw[current_state];
else
return hall_next_state_ccw[current_state];
}
2.5 PWM定时器配置
c
/**
* @file tim_pwm.c
* @brief PWM定时器配置
*/
#include "main.h"
TIM_HandleTypeDef htim1;
/**
* @brief TIM1 PWM初始化
*/
void TIM1_PWM_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
/* 使能TIM1时钟 */
__HAL_RCC_TIM1_CLK_ENABLE();
/* 定时器基础配置 */
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0; // 不分频
htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1; // 中央对齐模式
htim1.Init.Period = PWM_PERIOD; // PWM周期
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
HAL_TIM_PWM_Init(&htim1);
/* 时钟源配置 */
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig);
/* 主输出配置 */
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 (U相上桥) */
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);
/* 配置通道1N (U相下桥) */
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1N);
/* 配置通道2 (V相上桥) */
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2);
/* 配置通道2N (V相下桥) */
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2N);
/* 配置通道3 (W相上桥) */
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3);
/* 配置通道3N (W相下桥) */
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3N);
/* 死区和刹车配置 */
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = PWM_DEAD_TIME; // 死区时间
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_1N);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2N);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3N);
/* 禁用输出,等待启动命令 */
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1N);
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_2);
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_2N);
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_3);
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_3N);
printf("TIM1 PWM initialized: Freq=%dHz, DeadTime=%dns\n",
PWM_FREQUENCY, (PWM_DEAD_TIME * 1000) / 72);
}
2.6 故障保护
c
/**
* @file fault_handler.c
* @brief 故障保护处理
*/
#include "fault_handler.h"
/* 故障阈值 */
#define OVER_CURRENT_THRESHOLD 10.0f // 10A
#define OVER_VOLTAGE_THRESHOLD 60.0f // 60V
#define UNDER_VOLTAGE_THRESHOLD 20.0f // 20V
#define OVER_TEMP_THRESHOLD 85.0f // 85°C
#define STALL_TIME_THRESHOLD 2000 // 2秒堵转
/**
* @brief 电流保护检测
*/
void Current_Protection_Check(void)
{
static float filtered_current = 0;
float current_sample = ADC_GetCurrent();
/* 一阶低通滤波 */
filtered_current = filtered_current * 0.9 + current_sample * 0.1;
/* 过流检测 */
if(filtered_current > OVER_CURRENT_THRESHOLD)
{
motor.fault_flags |= FAULT_OVERCURRENT;
BLDC_Stop();
printf("Over current protection: %.2fA\n", filtered_current);
}
}
/**
* @brief 电压保护检测
*/
void Voltage_Protection_Check(void)
{
float voltage = ADC_GetVoltage();
if(voltage > OVER_VOLTAGE_THRESHOLD)
{
motor.fault_flags |= FAULT_OVERVOLTAGE;
BLDC_Stop();
printf("Over voltage protection: %.2fV\n", voltage);
}
else if(voltage < UNDER_VOLTAGE_THRESHOLD)
{
motor.fault_flags |= FAULT_UNDERVOLTAGE;
BLDC_Stop();
printf("Under voltage protection: %.2fV\n", voltage);
}
}
/**
* @brief 温度保护检测
*/
void Temperature_Protection_Check(void)
{
float temperature = ADC_GetTemperature();
if(temperature > OVER_TEMP_THRESHOLD)
{
motor.fault_flags |= FAULT_OVERTEMP;
BLDC_Stop();
printf("Over temperature protection: %.1fC\n", temperature);
}
}
/**
* @brief 堵转检测
*/
void Stall_Protection_Check(void)
{
static uint32_t last_speed_time = 0;
static uint16_t last_speed = 0;
if(motor.state == MOTOR_RUNNING)
{
uint32_t current_time = HAL_GetTick();
if(motor.speed_rpm < 50) // 速度低于50RPM
{
if(current_time - last_speed_time > STALL_TIME_THRESHOLD)
{
motor.fault_flags |= FAULT_STALL;
BLDC_Stop();
printf("Stall protection triggered\n");
}
}
else
{
last_speed_time = current_time;
}
last_speed = motor.speed_rpm;
}
}
/**
* @brief 清除故障
*/
void Clear_Fault(void)
{
if(motor.fault_flags != 0)
{
printf("Clearing faults: 0x%02X\n", motor.fault_flags);
motor.fault_flags = 0;
}
}
三、PID速度控制
3.1 PID控制器
c
/**
* @file pid_controller.c
* @brief PID速度控制器
*/
#include "pid_controller.h"
/**
* @brief PID初始化
*/
void PID_Init(PID_Controller *pid, float kp, float ki, float kd,
float max_output, float max_integral)
{
pid->Kp = kp;
pid->Ki = ki;
pid->Kd = kd;
pid->max_output = max_output;
pid->max_integral = max_integral;
pid->integral = 0;
pid->prev_error = 0;
pid->output = 0;
}
/**
* @brief PID计算
*/
float PID_Calculate(PID_Controller *pid, float target, float feedback, float dt)
{
float error = target - feedback;
/* 比例项 */
float P_out = pid->Kp * error;
/* 积分项 */
pid->integral += error * dt;
/* 积分限幅 */
if(pid->integral > pid->max_integral)
pid->integral = pid->max_integral;
else if(pid->integral < -pid->max_integral)
pid->integral = -pid->max_integral;
float I_out = pid->Ki * pid->integral;
/* 微分项 */
float derivative = (error - pid->prev_error) / dt;
float D_out = pid->Kd * derivative;
pid->prev_error = error;
/* 计算输出 */
pid->output = P_out + I_out + D_out;
/* 输出限幅 */
if(pid->output > pid->max_output)
pid->output = pid->max_output;
else if(pid->output < 0)
pid->output = 0;
return pid->output;
}
/**
* @brief 速度控制任务
*/
void Speed_Control_Task(void)
{
static uint32_t last_control_time = 0;
uint32_t current_time = HAL_GetTick();
float dt = (current_time - last_control_time) / 1000.0f; // 转换为秒
if(dt >= 0.01f) // 100Hz控制频率
{
last_control_time = current_time;
/* PID计算 */
float duty_output = PID_Calculate(&speed_pid,
motor.target_rpm,
motor.speed_rpm,
dt);
/* 转换为PWM占空比 */
uint16_t pwm_duty = (uint16_t)duty_output;
/* 设置PWM */
if(pwm_duty > MAX_DUTY) pwm_duty = MAX_DUTY;
if(pwm_duty < MIN_DUTY) pwm_duty = MIN_DUTY;
BLDC_SetPWM(pwm_duty);
/* 调试输出 */
static uint32_t debug_counter = 0;
if(debug_counter++ >= 10) // 每10次输出一次
{
debug_counter = 0;
printf("PID: Target=%d, Actual=%d, Output=%.1f, Duty=%d\n",
motor.target_rpm, motor.speed_rpm, duty_output, pwm_duty);
}
}
}
四、测试程序
4.1 电机测试程序
c
/**
* @file motor_test.c
* @brief 电机测试程序
*/
#include "bldc_driver.h"
/**
* @brief 测试换相序列
*/
void Test_Commutation_Sequence(void)
{
printf("Testing commutation sequence...\n");
/* 测试顺时针换相 */
printf("\nClockwise commutation:\n");
motor.direction = DIR_CW;
for(int i = 0; i < 6; i++)
{
BLDC_SetCommutation(i);
printf("Step %d: Hall=0x%02X\n", i, comm_table_cw[i].hall_state);
HAL_Delay(500);
}
/* 测试逆时针换相 */
printf("\nCounter-clockwise commutation:\n");
motor.direction = DIR_CCW;
for(int i = 0; i < 6; i++)
{
BLDC_SetCommutation(i);
printf("Step %d: Hall=0x%02X\n", i, comm_table_ccw[i].hall_state);
HAL_Delay(500);
}
BLDC_Stop();
printf("Commutation test completed\n");
}
/**
* @brief 测试霍尔传感器
*/
void Test_Hall_Sensors(void)
{
printf("Testing Hall sensors...\n");
printf("Manually rotate the motor and check Hall states\n");
uint8_t last_state = 0;
uint32_t start_time = HAL_GetTick();
while(HAL_GetTick() - start_time < 10000) // 测试10秒
{
uint8_t state = Hall_GetState();
if(state != last_state)
{
last_state = state;
printf("Hall state: 0x%02X\n", state);
if(state == 0x00 || state == 0x07)
{
printf("Warning: Invalid Hall state!\n");
}
}
HAL_Delay(10);
}
printf("Hall sensor test completed\n");
}
/**
* @brief 测试PWM输出
*/
void Test_PWM_Output(void)
{
printf("Testing PWM output...\n");
/* 逐步增加占空比 */
for(uint16_t duty = 0; duty <= 1000; duty += 100)
{
BLDC_SetPWM(duty);
printf("Duty: %d\n", duty);
HAL_Delay(1000);
}
/* 逐步减少占空比 */
for(uint16_t duty = 1000; duty > 0; duty -= 100)
{
BLDC_SetPWM(duty);
printf("Duty: %d\n", duty);
HAL_Delay(1000);
}
BLDC_SetPWM(0);
printf("PWM test completed\n");
}
/**
* @brief 完整电机测试
*/
void Complete_Motor_Test(void)
{
printf("=== Complete Motor Test ===\n");
/* 1. 霍尔传感器测试 */
Test_Hall_Sensors();
HAL_Delay(1000);
/* 2. 换相测试 */
Test_Commutation_Sequence();
HAL_Delay(1000);
/* 3. PWM测试 */
Test_PWM_Output();
HAL_Delay(1000);
/* 4. 启动测试 */
printf("\nStarting motor...\n");
BLDC_Start();
/* 运行10秒 */
uint32_t start_time = HAL_GetTick();
while(HAL_GetTick() - start_time < 10000)
{
printf("Speed: %d RPM, Duty: %d\n", motor.speed_rpm, motor.pwm_duty);
HAL_Delay(100);
}
/* 停止电机 */
BLDC_Stop();
printf("\nMotor test completed\n");
}
参考代码 直流无刷电机六拍方波控制器程序 www.youwenfan.com/contentcsv/70758.html
五、硬件配置
5.1 系统时钟配置
c
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/* 配置HSE 8MHz */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; // 8MHz * 9 = 72MHz
HAL_RCC_OscConfig(&RCC_OscInitStruct);
/* 配置系统时钟 */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // HCLK = 72MHz
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; // PCLK1 = 36MHz
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // PCLK2 = 72MHz
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
}
六、使用说明
6.1 基本操作
- 初始化 :调用
BLDC_Init()初始化电机 - 启动 :调用
BLDC_Start()启动电机 - 停止 :调用
BLDC_Stop()停止电机 - 设置方向 :调用
BLDC_SetDirection()设置旋转方向 - 设置速度 :调用
BLDC_SetPWM()设置PWM占空比 - 故障清除 :调用
Clear_Fault()清除故障标志
6.2 参数调整
c
/* PWM频率调整 */
#define PWM_FREQUENCY 16000 // 常用范围8-20kHz
/* 死区时间调整 */
#define PWM_DEAD_TIME 72 // 1us (72MHz时钟)
/* 保护阈值调整 */
#define OVER_CURRENT_THRESHOLD 10.0f // 根据电机额定电流调整
#define OVER_VOLTAGE_THRESHOLD 60.0f // 根据电源电压调整
#define OVER_TEMP_THRESHOLD 85.0f // 根据器件耐温调整
/* PID参数调整 */
float Kp = 0.5; // 比例系数
float Ki = 0.1; // 积分系数
float Kd = 0.01; // 微分系数