基于 STM32 的双闭环控制直流无刷电机(BLDC)方案

一、系统架构设计

复制代码
┌─────────────────────────────────────────────────────────────┐
│                    BLDC 双闭环控制系统架构                 │
├─────────────────────────────────────────────────────────────┤
│  速度外环    │  电流内环    │  功率驱动    │  电机本体    │
│              │              │              │              │
│  • 速度PID   │  • 电流PID   │  • 三相逆变  │  • 定子绕组  │
│  • 速度反馈  │  • 电流采样  │  • 栅极驱动  │  • 永磁转子  │
│  • 斜坡给定  │  • 过流保护  │  • 死区插入  │  • 霍尔传感器│
│  • 正反转控  │  • 解耦控制  │  • 故障保护  │  • 反电动势  │
└─────────────────────────────────────────────────────────────┘

二、硬件平台配置

2.1 硬件连接设计

复制代码
STM32F103 引脚分配:
┌─────────────┬─────────────────────┬──────────────────┐
│ STM32 引脚  │ 功能描述            │ 外部连接         │
├─────────────┼─────────────────────┼──────────────────┤
│ PA8/TIM1_CH1│ PWM_UH (上桥U相)    │ DRV8301 INH_A    │
│ PA9/TIM1_CH2│ PWM_VH (上桥V相)    │ DRV8301 INH_B    │
│ PA10/TIM1_CH3│ PWM_WH (上桥W相)   │ DRV8301 INH_C    │
│ PB13/TIM1_CH1N│ PWM_UL (下桥U相)  │ DRV8301 INL_A    │
│ PB14/TIM1_CH2N│ PWM_VL (下桥V相)  │ DRV8301 INL_B    │
│ PB15/TIM1_CH3N│ PWM_WL (下桥W相)  │ DRV8301 INL_C    │
│ PA0/ADC_IN0 │ 相电流采样 U       │ 电流采样电阻     │
│ PA1/ADC_IN1 │ 相电流采样 V       │ 电流采样电阻     │
│ PA2/ADC_IN2 │ 母线电压采样       │ 分压电阻网络     │
│ PB6/TIM4_CH1│ 编码器 A 相        │ 编码器信号       │
│ PB7/TIM4_CH2│ 编码器 B 相        │ 编码器信号       │
│ PC6/TIM3_CH1│ 霍尔传感器 U       │ BLDC 霍尔输出    │
│ PC7/TIM3_CH2│ 霍尔传感器 V       │ BLDC 霍尔输出    │
│ PC8/TIM3_CH3│ 霍尔传感器 W       │ BLDC 霍尔输出    │
│ PB0         │ 电机使能 EN        │ DRV8301 EN_GATE  │
│ PB1         │ 故障保护 nFAULT    │ DRV8301 nFAULT   │
│ PB10        │ 方向控制 DIR       │ 外部输入         │
│ PB11        │ 刹车控制 BRAKE     │ 外部输入         │
└─────────────┴─────────────────────┴──────────────────┘

2.2 功率驱动电路

复制代码
推荐使用 DRV8301/DRV8323 三相栅极驱动器:
• 工作电压:8-60V
• 驱动电流:1.7A 峰值
• 集成电流采样放大器
• 支持 3 种 PWM 模式
• 过流、过温、欠压保护

三、源码实现

3.1 系统头文件 (bldc_control.h)

c 复制代码
#ifndef __BLDC_CONTROL_H
#define __BLDC_CONTROL_H

#include "stm32f10x.h"
#include <stdint.h>
#include <stdbool.h>
#include <math.h>

// 系统参数定义
#define PWM_FREQUENCY       20000      // PWM频率 20kHz
#define DEAD_TIME_NS        500        // 死区时间 500ns
#define CONTROL_PERIOD_MS   1          // 控制周期 1ms
#define MAX_SPEED_RPM       3000       // 最大转速 3000 RPM
#define MAX_CURRENT_A       10.0f      // 最大电流 10A
#define POLE_PAIRS          4          // 电机极对数

// 控制模式枚举
typedef enum {
    CONTROL_MODE_STOP = 0,
    CONTROL_MODE_SPEED,
    CONTROL_MODE_CURRENT,
    CONTROL_MODE_TORQUE,
    CONTROL_MODE_POSITION
} ControlMode_t;

// 电机状态枚举
typedef enum {
    MOTOR_STATE_IDLE = 0,
    MOTOR_STATE_ALIGN,
    MOTOR_STATE_RUNNING,
    MOTOR_STATE_FAULT,
    MOTOR_STATE_BRAKE
} MotorState_t;

// PID 控制器结构体
typedef struct {
    float kp;              // 比例系数
    float ki;              // 积分系数
    float kd;              // 微分系数
    float integral;        // 积分累加
    float prev_error;      // 上次误差
    float output_limit;    // 输出限制
    float integral_limit;  // 积分限制
    bool enable;           // 使能标志
} PID_Controller_t;

// 电机参数结构体
typedef struct {
    float rs;              // 定子电阻 (Ω)
    float ls;              // 定子电感 (H)
    float ke;              // 反电动势常数 (V/(rad/s))
    float kt;              // 转矩常数 (Nm/A)
    uint8_t pole_pairs;    // 极对数
    float max_speed;       // 最大转速 (RPM)
    float max_current;     // 最大电流 (A)
    float max_voltage;     // 最大电压 (V)
} MotorParams_t;

// 电机状态结构体
typedef struct {
    float speed_rpm;       // 转速 (RPM)
    float speed_rad_s;     // 角速度 (rad/s)
    float current_a;       // A相电流 (A)
    float current_b;       // B相电流 (A)
    float current_c;       // C相电流 (A)
    float voltage_bus;     // 母线电压 (V)
    float temperature;     // 温度 (°C)
    float torque;          // 输出转矩 (Nm)
    uint32_t position;     // 位置计数
    MotorState_t state;    // 电机状态
    ControlMode_t mode;    // 控制模式
} MotorStatus_t;

// 控制命令结构体
typedef struct {
    float target_speed;    // 目标转速 (RPM)
    float target_current;  // 目标电流 (A)
    float target_torque;   // 目标转矩 (Nm)
    float ramp_rate;       // 斜坡速率 (RPM/s)
    bool direction;        // 方向 (0:正转, 1:反转)
    bool brake;            // 刹车标志
    bool enable;           // 使能标志
} ControlCommand_t;

// 双闭环控制结构体
typedef struct {
    PID_Controller_t speed_pid;    // 速度环 PID
    PID_Controller_t current_pid;  // 电流环 PID
    MotorParams_t motor_params;    // 电机参数
    MotorStatus_t motor_status;    // 电机状态
    ControlCommand_t command;      // 控制命令
    float current_setpoint;        // 电流设定值
    float speed_setpoint;          // 速度设定值
    float duty_cycle[3];           // PWM占空比 [U, V, W]
    uint8_t commutation_sector;    // 换相扇区
    uint32_t last_commutation_time; // 上次换相时间
} DualLoopController_t;

// 函数声明
void BLDC_Init(void);
void BLDC_ControlLoop(void);
void BLDC_SetSpeed(float speed_rpm);
void BLDC_SetCurrent(float current_a);
void BLDC_Start(void);
void BLDC_Stop(void);
void BLDC_Brake(bool enable);
void BLDC_ChangeDirection(bool reverse);
void BLDC_UpdateMotorStatus(void);
void BLDC_SafetyCheck(void);
void BLDC_Commutation(void);
void BLDC_CurrentControl(void);
void BLDC_SpeedControl(void);

#endif /* __BLDC_CONTROL_H */

3.2 PWM 与定时器配置 (pwm_driver.c)

c 复制代码
/**
 * @file pwm_driver.c
 * @brief STM32 BLDC PWM 驱动
 */

#include "bldc_control.h"
#include "tim.h"

static DualLoopController_t bldc_controller;

// PWM 初始化
void PWM_Init(void) {
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;
    TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
    
    // 使能 TIM1 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
    
    // 配置 TIM1 时基
    TIM_TimeBaseStructure.TIM_Period = SystemCoreClock / PWM_FREQUENCY - 1;
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
    
    // 配置 PWM 通道 1, 2, 3
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 0;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Low;
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Low;
    
    TIM_OC1Init(TIM1, &TIM_OCInitStructure);
    TIM_OC2Init(TIM1, &TIM_OCInitStructure);
    TIM_OC3Init(TIM1, &TIM_OCInitStructure);
    
    // 配置死区时间
    TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
    TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
    TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;
    TIM_BDTRInitStructure.TIM_DeadTime = (uint8_t)((DEAD_TIME_NS * SystemCoreClock) / 1000000000);
    TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;
    TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
    TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
    TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);
    
    // 使能预装载寄存器
    TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
    TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);
    TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);
    
    // 使能 TIM1 主输出
    TIM_CtrlPWMOutputs(TIM1, ENABLE);
    
    // 启动定时器
    TIM_Cmd(TIM1, ENABLE);
}

// 设置 PWM 占空比
void PWM_SetDutyCycle(uint8_t phase, float duty_cycle) {
    uint16_t period = TIM1->ARR;
    uint16_t pulse = (uint16_t)(period * duty_cycle / 100.0f);
    
    switch(phase) {
        case 0:  // U相
            TIM_SetCompare1(TIM1, pulse);
            break;
        case 1:  // V相
            TIM_SetCompare2(TIM1, pulse);
            break;
        case 2:  // W相
            TIM_SetCompare3(TIM1, pulse);
            break;
    }
}

// 设置三相 PWM
void PWM_SetThreePhase(float duty_u, float duty_v, float duty_w) {
    PWM_SetDutyCycle(0, duty_u);
    PWM_SetDutyCycle(1, duty_v);
    PWM_SetDutyCycle(2, duty_w);
}

// 紧急关断 PWM
void PWM_EmergencyStop(void) {
    TIM_CtrlPWMOutputs(TIM1, DISABLE);
    TIM_Cmd(TIM1, DISABLE);
}

3.3 编码器接口 (encoder.c)

c 复制代码
/**
 * @file encoder.c
 * @brief 增量式编码器接口
 */

#include "bldc_control.h"

// 编码器初始化
void Encoder_Init(void) {
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_ICInitTypeDef TIM_ICInitStructure;
    
    // 使能 TIM4 时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
    
    // 配置 TIM4 时基
    TIM_TimeBaseStructure.TIM_Period = 0xFFFF;  // 最大计数值
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
    
    // 配置编码器接口
    TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, 
                              TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
    
    // 配置输入捕获
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    TIM_ICInitStructure.TIM_ICFilter = 0x0F;  // 滤波
    TIM_ICInit(TIM4, &TIM_ICInitStructure);
    
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
    TIM_ICInit(TIM4, &TIM_ICInitStructure);
    
    // 清零计数器
    TIM_SetCounter(TIM4, 0);
    
    // 启动定时器
    TIM_Cmd(TIM4, ENABLE);
}

// 读取编码器计数
int32_t Encoder_GetCount(void) {
    return (int32_t)TIM_GetCounter(TIM4);
}

// 读取转速 (RPM)
float Encoder_GetSpeedRPM(uint32_t time_interval_ms) {
    static int32_t last_count = 0;
    int32_t current_count = Encoder_GetCount();
    int32_t delta_count = current_count - last_count;
    
    // 处理计数器溢出
    if (delta_count > 32767) {
        delta_count -= 65536;
    } else if (delta_count < -32767) {
        delta_count += 65536;
    }
    
    last_count = current_count;
    
    // 计算转速:RPM = (delta_count * 60000) / (PPR * time_interval_ms)
    // 假设编码器每转 1000 个脉冲
    const uint16_t PPR = 1000;
    float rpm = (float)(delta_count * 60000) / (PPR * time_interval_ms);
    
    return rpm;
}

3.4 电流采样与 ADC (current_sense.c)

c 复制代码
/**
 * @file current_sense.c
 * @brief 相电流采样与 ADC 转换
 */

#include "bldc_control.h"

#define ADC_BUFFER_SIZE 16
static uint16_t adc_buffer[ADC_BUFFER_SIZE];
static float current_offset_u = 0;
static float current_offset_v = 0;

// ADC 初始化
void ADC_Init_CurrentSense(void) {
    ADC_InitTypeDef ADC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;
    
    // 使能时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    
    // 配置 ADC 引脚
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 配置 DMA
    DMA_DeInit(DMA1_Channel1);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)adc_buffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = ADC_BUFFER_SIZE;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);
    
    // 使能 DMA
    DMA_Cmd(DMA1_Channel1, ENABLE);
    
    // 配置 ADC
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = 3;
    ADC_Init(ADC1, &ADC_InitStructure);
    
    // 配置 ADC 通道
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_239Cycles5);
    
    // 使能 ADC DMA
    ADC_DMACmd(ADC1, ENABLE);
    
    // 使能 ADC
    ADC_Cmd(ADC1, ENABLE);
    
    // 校准 ADC
    ADC_ResetCalibration(ADC1);
    while(ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1));
    
    // 启动 ADC 转换
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    
    // 电流零点校准
    Current_CalibrateOffset();
}

// 电流零点校准
void Current_CalibrateOffset(void) {
    uint32_t sum_u = 0, sum_v = 0;
    uint16_t i;
    
    // 等待电机停止
    Delay_ms(1000);
    
    // 采样 100 次取平均
    for (i = 0; i < 100; i++) {
        sum_u += adc_buffer[0];
        sum_v += adc_buffer[1];
        Delay_ms(1);
    }
    
    current_offset_u = (float)sum_u / 100.0f;
    current_offset_v = (float)sum_v / 100.0f;
}

// 获取相电流
void Current_GetPhaseCurrents(float *current_u, float *current_v) {
    uint16_t adc_u, adc_v;
    float voltage_u, voltage_v;
    
    // 读取 ADC 值
    adc_u = adc_buffer[0];
    adc_v = adc_buffer[1];
    
    // 转换为电压
    voltage_u = (float)adc_u * 3.3f / 4096.0f;
    voltage_v = (float)adc_v * 3.3f / 4096.0f;
    
    // 转换为电流(假设采样电阻 0.01Ω,放大倍数 20)
    const float SHUNT_RESISTOR = 0.01f;  // 10mΩ
    const float AMP_GAIN = 20.0f;        // 放大倍数
    
    *current_u = (voltage_u - current_offset_u * 3.3f / 4096.0f) / (SHUNT_RESISTOR * AMP_GAIN);
    *current_v = (voltage_v - current_offset_v * 3.3f / 4096.0f) / (SHUNT_RESISTOR * AMP_GAIN);
    
    // 计算第三相电流
    // *current_w = -(*current_u + *current_v);
}

// 获取母线电压
float Current_GetBusVoltage(void) {
    uint16_t adc_value = adc_buffer[2];
    float voltage = (float)adc_value * 3.3f / 4096.0f;
    
    // 分压系数:10kΩ + 2kΩ,分压比 1/6
    const float VOLTAGE_DIVIDER = 6.0f;
    return voltage * VOLTAGE_DIVIDER;
}

3.5 PID 控制器 (pid_controller.c)

c 复制代码
/**
 * @file pid_controller.c
 * @brief PID 控制器实现
 */

#include "bldc_control.h"

// PID 初始化
void PID_Init(PID_Controller_t *pid, float kp, float ki, float kd, float limit) {
    pid->kp = kp;
    pid->ki = ki;
    pid->kd = kd;
    pid->integral = 0.0f;
    pid->prev_error = 0.0f;
    pid->output_limit = limit;
    pid->integral_limit = limit * 0.5f;
    pid->enable = true;
}

// PID 计算
float PID_Calculate(PID_Controller_t *pid, float setpoint, float feedback, float dt) {
    float error, derivative, output;
    
    if (!pid->enable) {
        return 0.0f;
    }
    
    // 计算误差
    error = setpoint - feedback;
    
    // 积分项
    pid->integral += error * dt;
    
    // 积分限幅
    if (pid->integral > pid->integral_limit) {
        pid->integral = pid->integral_limit;
    } else if (pid->integral < -pid->integral_limit) {
        pid->integral = -pid->integral_limit;
    }
    
    // 微分项
    derivative = (error - pid->prev_error) / dt;
    pid->prev_error = error;
    
    // PID 输出
    output = pid->kp * error + pid->ki * pid->integral + pid->kd * derivative;
    
    // 输出限幅
    if (output > pid->output_limit) {
        output = pid->output_limit;
    } else if (output < -pid->output_limit) {
        output = -pid->output_limit;
    }
    
    return output;
}

// 抗积分饱和 PID
float PID_CalculateAntiWindup(PID_Controller_t *pid, float setpoint, float feedback, 
                            float dt, float saturation_limit) {
    float error, derivative, output, unsaturated_output;
    
    if (!pid->enable) {
        return 0.0f;
    }
    
    error = setpoint - feedback;
    
    // 积分项
    pid->integral += error * dt;
    
    // 微分项
    derivative = (error - pid->prev_error) / dt;
    pid->prev_error = error;
    
    // 计算未饱和输出
    unsaturated_output = pid->kp * error + pid->ki * pid->integral + pid->kd * derivative;
    
    // 输出限幅
    if (unsaturated_output > saturation_limit) {
        output = saturation_limit;
    } else if (unsaturated_output < -saturation_limit) {
        output = -saturation_limit;
    } else {
        output = unsaturated_output;
    }
    
    // 抗积分饱和:只有当输出不饱和时才积分
    if (fabsf(output - unsaturated_output) < 0.01f) {
        // 正常积分
    } else {
        // 停止积分或反向积分
        pid->integral -= error * dt * 0.1f;  // 减小积分
    }
    
    return output;
}

3.6 双闭环控制核心 (bldc_control.c)

c 复制代码
/**
 * @file bldc_control.c
 * @brief BLDC 双闭环控制核心
 */

#include "bldc_control.h"
#include "pwm_driver.h"
#include "encoder.h"
#include "current_sense.h"
#include "pid_controller.h"

// 全局控制器实例
DualLoopController_t g_bldc_controller;

// 初始化 BLDC 控制
void BLDC_Init(void) {
    DualLoopController_t *ctrl = &g_bldc_controller;
    
    // 初始化 PID 参数
    PID_Init(&ctrl->speed_pid, 0.5f, 0.1f, 0.01f, MAX_SPEED_RPM);
    PID_Init(&ctrl->current_pid, 5.0f, 1.0f, 0.1f, MAX_CURRENT_A);
    
    // 初始化电机参数
    ctrl->motor_params.rs = 0.1f;      // 0.1 Ω
    ctrl->motor_params.ls = 0.001f;    // 1 mH
    ctrl->motor_params.ke = 0.05f;     // 0.05 V/(rad/s)
    ctrl->motor_params.kt = 0.05f;     // 0.05 Nm/A
    ctrl->motor_params.pole_pairs = POLE_PAIRS;
    ctrl->motor_params.max_speed = MAX_SPEED_RPM;
    ctrl->motor_params.max_current = MAX_CURRENT_A;
    ctrl->motor_params.max_voltage = 24.0f;
    
    // 初始化控制命令
    ctrl->command.target_speed = 0.0f;
    ctrl->command.target_current = 0.0f;
    ctrl->command.ramp_rate = 1000.0f;  // 1000 RPM/s
    ctrl->command.direction = 0;
    ctrl->command.brake = false;
    ctrl->command.enable = false;
    
    // 初始化电机状态
    ctrl->motor_status.speed_rpm = 0.0f;
    ctrl->motor_status.current_a = 0.0f;
    ctrl->motor_status.current_b = 0.0f;
    ctrl->motor_status.voltage_bus = 24.0f;
    ctrl->motor_status.temperature = 25.0f;
    ctrl->motor_status.torque = 0.0f;
    ctrl->motor_status.state = MOTOR_STATE_IDLE;
    ctrl->motor_status.mode = CONTROL_MODE_STOP;
    
    // 初始化 PWM
    PWM_Init();
    
    // 初始化编码器
    Encoder_Init();
    
    // 初始化电流采样
    ADC_Init_CurrentSense();
    
    // 初始化换相
    ctrl->commutation_sector = 0;
    ctrl->last_commutation_time = 0;
    
    printf("BLDC Controller Initialized\r\n");
}

// 双闭环控制循环
void BLDC_ControlLoop(void) {
    DualLoopController_t *ctrl = &g_bldc_controller;
    float dt = CONTROL_PERIOD_MS / 1000.0f;  // 转换为秒
    
    // 更新电机状态
    BLDC_UpdateMotorStatus();
    
    // 安全检查
    BLDC_SafetyCheck();
    
    if (!ctrl->command.enable || ctrl->motor_status.state == MOTOR_STATE_FAULT) {
        PWM_SetThreePhase(0, 0, 0);
        return;
    }
    
    // 根据控制模式执行
    switch (ctrl->motor_status.mode) {
        case CONTROL_MODE_SPEED:
            BLDC_SpeedControl();
            break;
            
        case CONTROL_MODE_CURRENT:
            BLDC_CurrentControl();
            break;
            
        case CONTROL_MODE_TORQUE:
            // 转矩控制(电流控制的一种)
            BLDC_CurrentControl();
            break;
            
        default:
            PWM_SetThreePhase(0, 0, 0);
            break;
    }
    
    // 执行换相
    BLDC_Commutation();
}

// 速度控制(外环)
void BLDC_SpeedControl(void) {
    DualLoopController_t *ctrl = &g_bldc_controller;
    float dt = CONTROL_PERIOD_MS / 1000.0f;
    
    // 斜坡处理
    static float ramp_target = 0.0f;
    if (fabsf(ctrl->command.target_speed - ramp_target) > ctrl->command.ramp_rate * dt) {
        if (ctrl->command.target_speed > ramp_target) {
            ramp_target += ctrl->command.ramp_rate * dt;
        } else {
            ramp_target -= ctrl->command.ramp_rate * dt;
        }
    } else {
        ramp_target = ctrl->command.target_speed;
    }
    
    // 速度 PID 计算
    float speed_error = ramp_target - ctrl->motor_status.speed_rpm;
    float current_setpoint = PID_Calculate(&ctrl->speed_pid, ramp_target, 
                                          ctrl->motor_status.speed_rpm, dt);
    
    // 限制电流设定值
    if (current_setpoint > MAX_CURRENT_A) current_setpoint = MAX_CURRENT_A;
    if (current_setpoint < -MAX_CURRENT_A) current_setpoint = -MAX_CURRENT_A;
    
    ctrl->current_setpoint = current_setpoint;
    
    // 执行电流控制
    BLDC_CurrentControl();
}

// 电流控制(内环)
void BLDC_CurrentControl(void) {
    DualLoopController_t *ctrl = &g_bldc_controller;
    float dt = CONTROL_PERIOD_MS / 1000.0f;
    
    // 获取相电流
    float current_u, current_v;
    Current_GetPhaseCurrents(&current_u, &current_v);
    ctrl->motor_status.current_a = current_u;
    ctrl->motor_status.current_b = current_v;
    
    // 计算电流幅值(矢量模)
    float current_magnitude = sqrtf(current_u * current_u + current_v * current_v);
    
    // 电流 PID 计算
    float voltage_setpoint = PID_Calculate(&ctrl->current_pid, ctrl->current_setpoint, 
                                         current_magnitude, dt);
    
    // 转换为 PWM 占空比
    float duty_cycle = voltage_setpoint / ctrl->motor_status.voltage_bus * 100.0f;
    
    // 限制占空比
    if (duty_cycle > 95.0f) duty_cycle = 95.0f;
    if (duty_cycle < -95.0f) duty_cycle = -95.0f;
    
    // 存储占空比用于换相
    ctrl->duty_cycle[0] = duty_cycle;
    ctrl->duty_cycle[1] = duty_cycle;
    ctrl->duty_cycle[2] = duty_cycle;
}

// 换相控制(六步换向)
void BLDC_Commutation(void) {
    DualLoopController_t *ctrl = &g_bldc_controller;
    
    // 根据霍尔传感器或反电动势确定换相扇区
    uint8_t hall_state = GPIO_ReadInputData(GPIOC) & 0x07;  // PC6, PC7, PC8
    
    // 霍尔状态到扇区的映射
    uint8_t sector_map[8] = {0, 0, 1, 2, 5, 4, 3, 0};  // 无效状态为0
    uint8_t sector = sector_map[hall_state];
    
    if (sector == 0) {
        return;  // 无效霍尔状态
    }
    
    ctrl->commutation_sector = sector;
    
    // 根据扇区和方向设置 PWM
    float duty_u = 0, duty_v = 0, duty_w = 0;
    bool direction = ctrl->command.direction;
    
    // 六步换向表
    if (!direction) {  // 正转
        switch(sector) {
            case 1: duty_u = ctrl->duty_cycle[0]; duty_v = 0; duty_w = -ctrl->duty_cycle[2]; break;
            case 2: duty_u = ctrl->duty_cycle[0]; duty_v = ctrl->duty_cycle[1]; duty_w = 0; break;
            case 3: duty_u = 0; duty_v = ctrl->duty_cycle[1]; duty_w = -ctrl->duty_cycle[2]; break;
            case 4: duty_u = -ctrl->duty_cycle[0]; duty_v = ctrl->duty_cycle[1]; duty_w = 0; break;
            case 5: duty_u = -ctrl->duty_cycle[0]; duty_v = 0; duty_w = -ctrl->duty_cycle[2]; break;
            case 6: duty_u = 0; duty_v = -ctrl->duty_cycle[1]; duty_w = -ctrl->duty_cycle[2]; break;
        }
    } else {  // 反转
        switch(sector) {
            case 1: duty_u = -ctrl->duty_cycle[0]; duty_v = 0; duty_w = ctrl->duty_cycle[2]; break;
            case 2: duty_u = -ctrl->duty_cycle[0]; duty_v = -ctrl->duty_cycle[1]; duty_w = 0; break;
            case 3: duty_u = 0; duty_v = -ctrl->duty_cycle[1]; duty_w = ctrl->duty_cycle[2]; break;
            case 4: duty_u = ctrl->duty_cycle[0]; duty_v = -ctrl->duty_cycle[1]; duty_w = 0; break;
            case 5: duty_u = ctrl->duty_cycle[0]; duty_v = 0; duty_w = ctrl->duty_cycle[2]; break;
            case 6: duty_u = 0; duty_v = ctrl->duty_cycle[1]; duty_w = ctrl->duty_cycle[2]; break;
        }
    }
    
    // 设置 PWM
    PWM_SetThreePhase(duty_u, duty_v, duty_w);
}

// 更新电机状态
void BLDC_UpdateMotorStatus(void) {
    DualLoopController_t *ctrl = &g_bldc_controller;
    
    // 更新转速
    static uint32_t last_time = 0;
    uint32_t current_time = Get_SystemTime();
    uint32_t dt_ms = current_time - last_time;
    
    if (dt_ms >= 10) {  // 每10ms更新一次速度
        ctrl->motor_status.speed_rpm = Encoder_GetSpeedRPM(dt_ms);
        ctrl->motor_status.speed_rad_s = ctrl->motor_status.speed_rpm * 2.0f * M_PI / 60.0f;
        last_time = current_time;
    }
    
    // 更新母线电压
    ctrl->motor_status.voltage_bus = Current_GetBusVoltage();
    
    // 计算输出转矩
    ctrl->motor_status.torque = ctrl->motor_status.current_a * ctrl->motor_params.kt;
}

// 安全检查
void BLDC_SafetyCheck(void) {
    DualLoopController_t *ctrl = &g_bldc_controller;
    
    // 过流保护
    if (fabsf(ctrl->motor_status.current_a) > MAX_CURRENT_A * 1.2f ||
        fabsf(ctrl->motor_status.current_b) > MAX_CURRENT_A * 1.2f) {
        ctrl->motor_status.state = MOTOR_STATE_FAULT;
        PWM_EmergencyStop();
        printf("Overcurrent Fault!\r\n");
        return;
    }
    
    // 过压保护
    if (ctrl->motor_status.voltage_bus > 30.0f) {
        ctrl->motor_status.state = MOTOR_STATE_FAULT;
        PWM_EmergencyStop();
        printf("Overvoltage Fault!\r\n");
        return;
    }
    
    // 欠压保护
    if (ctrl->motor_status.voltage_bus < 10.0f) {
        ctrl->motor_status.state = MOTOR_STATE_FAULT;
        PWM_EmergencyStop();
        printf("Undervoltage Fault!\r\n");
        return;
    }
    
    // 过热保护
    if (ctrl->motor_status.temperature > 80.0f) {
        ctrl->motor_status.state = MOTOR_STATE_FAULT;
        PWM_EmergencyStop();
        printf("Overtemperature Fault!\r\n");
        return;
    }
}

// 设置速度
void BLDC_SetSpeed(float speed_rpm) {
    DualLoopController_t *ctrl = &g_bldc_controller;
    
    if (speed_rpm > MAX_SPEED_RPM) speed_rpm = MAX_SPEED_RPM;
    if (speed_rpm < -MAX_SPEED_RPM) speed_rpm = -MAX_SPEED_RPM;
    
    ctrl->command.target_speed = speed_rpm;
    ctrl->motor_status.mode = CONTROL_MODE_SPEED;
    ctrl->command.enable = true;
}

// 设置电流
void BLDC_SetCurrent(float current_a) {
    DualLoopController_t *ctrl = &g_bldc_controller;
    
    if (current_a > MAX_CURRENT_A) current_a = MAX_CURRENT_A;
    if (current_a < -MAX_CURRENT_A) current_a = -MAX_CURRENT_A;
    
    ctrl->command.target_current = current_a;
    ctrl->motor_status.mode = CONTROL_MODE_CURRENT;
    ctrl->command.enable = true;
}

// 启动电机
void BLDC_Start(void) {
    DualLoopController_t *ctrl = &g_bldc_controller;
    
    ctrl->command.enable = true;
    ctrl->motor_status.state = MOTOR_STATE_RUNNING;
    
    // 对齐转子
    PWM_SetThreePhase(10, 0, 0);  // 施加10%占空比对齐
    Delay_ms(100);
    
    printf("Motor Started\r\n");
}

// 停止电机
void BLDC_Stop(void) {
    DualLoopController_t *ctrl = &g_bldc_controller;
    
    ctrl->command.enable = false;
    ctrl->command.target_speed = 0;
    ctrl->command.target_current = 0;
    ctrl->motor_status.state = MOTOR_STATE_IDLE;
    ctrl->motor_status.mode = CONTROL_MODE_STOP;
    
    PWM_SetThreePhase(0, 0, 0);
    
    printf("Motor Stopped\r\n");
}

// 刹车
void BLDC_Brake(bool enable) {
    DualLoopController_t *ctrl = &g_bldc_controller;
    
    ctrl->command.brake = enable;
    
    if (enable) {
        // 短路三相下桥臂进行能耗制动
        PWM_SetThreePhase(-100, -100, -100);
        ctrl->motor_status.state = MOTOR_STATE_BRAKE;
        printf("Motor Braking\r\n");
    } else {
        PWM_SetThreePhase(0, 0, 0);
        ctrl->motor_status.state = MOTOR_STATE_IDLE;
    }
}

// 改变方向
void BLDC_ChangeDirection(bool reverse) {
    DualLoopController_t *ctrl = &g_bldc_controller;
    
    ctrl->command.direction = reverse;
    
    if (reverse) {
        printf("Direction: Reverse\r\n");
    } else {
        printf("Direction: Forward\r\n");
    }
}

3.7 主程序 (main.c)

c 复制代码
#include "stm32f10x.h"
#include "bldc_control.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "key.h"

// 系统状态
typedef enum {
    SYS_INIT = 0,
    SYS_READY,
    SYS_RUNNING,
    SYS_FAULT,
    SYS_STOP
} SystemState_t;

static SystemState_t system_state = SYS_INIT;
static uint32_t control_counter = 0;

// 按键处理函数
void Key_Process(void) {
    if (Key_Scan(KEY_START)) {
        if (system_state == SYS_READY || system_state == SYS_STOP) {
            BLDC_Start();
            system_state = SYS_RUNNING;
        }
    }
    
    if (Key_Scan(KEY_STOP)) {
        BLDC_Stop();
        system_state = SYS_STOP;
    }
    
    if (Key_Scan(KEY_BRAKE)) {
        static bool brake_state = false;
        brake_state = !brake_state;
        BLDC_Brake(brake_state);
    }
    
    if (Key_Scan(KEY_DIR)) {
        static bool dir_state = false;
        dir_state = !dir_state;
        BLDC_ChangeDirection(dir_state);
    }
}

// 串口命令处理
void UART_CommandProcess(void) {
    if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET) {
        char cmd = USART_ReceiveData(USART1);
        
        switch(cmd) {
            case '1':  // 低速
                BLDC_SetSpeed(500);
                printf("Set Speed: 500 RPM\r\n");
                break;
            case '2':  // 中速
                BLDC_SetSpeed(1000);
                printf("Set Speed: 1000 RPM\r\n");
                break;
            case '3':  // 高速
                BLDC_SetSpeed(2000);
                printf("Set Speed: 2000 RPM\r\n");
                break;
            case 's':  // 停止
                BLDC_Stop();
                system_state = SYS_STOP;
                printf("Motor Stopped\r\n");
                break;
            case 'r':  // 反转
                BLDC_ChangeDirection(true);
                break;
            case 'f':  // 正转
                BLDC_ChangeDirection(false);
                break;
            case '?':  // 状态查询
                printf("Speed: %.1f RPM\r\n", g_bldc_controller.motor_status.speed_rpm);
                printf("Current: %.2f A\r\n", g_bldc_controller.motor_status.current_a);
                printf("Voltage: %.1f V\r\n", g_bldc_controller.motor_status.voltage_bus);
                printf("Torque: %.2f Nm\r\n", g_bldc_controller.motor_status.torque);
                break;
        }
    }
}

int main(void) {
    // 系统初始化
    SystemClock_Init();
    Delay_Init();
    USART_Init(115200);
    LED_Init();
    Key_Init();
    
    printf("STM32 BLDC Dual Loop Control System\r\n");
    printf("=====================================\r\n");
    
    // 初始化 BLDC 控制器
    BLDC_Init();
    
    system_state = SYS_READY;
    printf("System Ready. Press START button or send commands.\r\n");
    
    while(1) {
        // 按键处理
        Key_Process();
        
        // 串口命令处理
        UART_CommandProcess();
        
        // 双闭环控制循环(1ms周期)
        static uint32_t last_control_time = 0;
        uint32_t current_time = Get_SystemTime();
        
        if (current_time - last_control_time >= CONTROL_PERIOD_MS) {
            BLDC_ControlLoop();
            last_control_time = current_time;
            control_counter++;
            
            // 每秒打印一次状态
            if (control_counter % 1000 == 0) {
                printf("Speed: %.1f RPM, Current: %.2f A, Voltage: %.1f V\r\n",
                       g_bldc_controller.motor_status.speed_rpm,
                       g_bldc_controller.motor_status.current_a,
                       g_bldc_controller.motor_status.voltage_bus);
            }
        }
        
        // LED 指示系统状态
        switch(system_state) {
            case SYS_READY:
                LED_On(LED_GREEN);
                LED_Off(LED_RED);
                break;
            case SYS_RUNNING:
                LED_Toggle(LED_GREEN);
                LED_Off(LED_RED);
                break;
            case SYS_FAULT:
                LED_On(LED_RED);
                LED_Off(LED_GREEN);
                break;
            case SYS_STOP:
                LED_Off(LED_GREEN);
                LED_Off(LED_RED);
                break;
            default:
                break;
        }
        
        Delay_ms(1);
    }
}

参考代码 基于STM32的双闭控制直流无刷电机BLDC www.youwenfan.com/contentcsu/60618.html

四、工程配置与优化

4.1 编译配置

makefile 复制代码
# Makefile 配置
TARGET = bldc_dual_loop
MCU = cortex-m3
CFLAGS = -O2 -Wall -Wextra -std=c99
LDFLAGS = -Tlinker.ld

# 源文件
SOURCES = main.c \
          bldc_control.c \
          pwm_driver.c \
          encoder.c \
          current_sense.c \
          pid_controller.c \
          usart.c \
          delay.c \
          led.c \
          key.c

# 包含路径
INCLUDES = -I./Inc -I./Drivers/STM32F10x_StdPeriph_Driver/inc

# 编译规则
all: $(TARGET).bin

$(TARGET).bin: $(TARGET).elf
	arm-none-eabi-objcopy -O binary $< $@

$(TARGET).elf: $(SOURCES)
	arm-none-eabi-gcc $(CFLAGS) $(INCLUDES) $(SOURCES) $(LDFLAGS) -o $@

4.2 性能优化建议

优化项目 建议方案
控制频率 电流环 10-20kHz,速度环 1-5kHz
电流采样 使用同步采样,减少噪声
换相策略 结合霍尔传感器和反电动势
启动算法 三段式启动(对齐-加速-切换)
参数整定 先调电流环,再调速度环

4.3 常见问题解决

问题 原因 解决方案
电机抖动 PID参数不合适 减小比例系数,增加积分时间
启动困难 对齐不充分 延长对齐时间,增加对齐电流
过流保护频繁 电流采样噪声大 增加滤波,检查采样电阻
速度不稳 编码器分辨率低 使用更高分辨率编码器
效率低下 换相时机不准 优化换相逻辑,考虑超前角

这套基于STM32的双闭环BLDC控制方案提供了完整的软硬件实现,包括速度外环和电流内环控制,可直接应用于电动工具、电动车、工业伺服等领域。

相关推荐
Heartache boy1 小时前
野火STM32_HAL库版课程笔记-DWT应用与DHT11温湿度传感器
笔记·stm32·单片机·嵌入式硬件
无人装备硬件开发爱好者9 小时前
STM32G474 + 1.32 寸 OLED(128×96)俄罗斯方块游戏实现指南
stm32·嵌入式硬件·游戏
三佛科技-134163842129 小时前
SM2850P无电感离线稳压器 5V输出 典型应用电路分析(管脚、关键设计要点)
单片机·嵌入式硬件·物联网·智能家居·pcb工艺
潜创微科技10 小时前
IT6636+USB 协同芯片 3 进 1 出 HDMI2.1 KVM 切换器一体化方案
嵌入式硬件·音视频
dqsh0610 小时前
关于STM32G474芯片有规律的自动重启的问题
stm32·单片机·嵌入式硬件·系统重启·原因解析
时空自由民.11 小时前
BLDC无刷直流电机作为发电机的波形图
单片机
yong999011 小时前
基于 STM32 的 4×4 矩阵键盘源码
stm32·矩阵·计算机外设
JSMSEMI1111 小时前
JSM63006 5A 28V三相无刷电机驱动电路
单片机·嵌入式硬件
国产芯片设计11 小时前
【LCD驱动实战】单颗YL1621脚位不足?双芯片联动驱动方案详解
stm32·单片机·mcu·51单片机·硬件工程