STM32三相永磁同步电机驱动方案设计
一、系统总体设计
三相电机驱动系统通常由微控制器、功率驱动电路和电流检测电路三部分组成。微控制器负责FOC算法的执行和PWM波形的生成,功率驱动电路将控制信号放大为能够驱动功率器件的开关信号,电流检测电路则实时采集电机相电流用于闭环控制。
1.1 主控芯片选型
STM32系列微控制器凭借其强大的实时性能和丰富的外设资源,成为电机控制领域的首选方案。针对不同应用场景,推荐以下芯片方案:
- STM32G431CB:基于Cortex-M4F内核,运行频率170MHz,内置数学运算加速器和三路运放,支持三电阻电流采样,适合高性能需求场景。
- STM32G474RE:配备高速双ADC(采样率3.6Msps),支持ST的专利电流重构算法,内置比较器可用于过流保护,适用于工业高精度控制。
- STM32F303K8:经济型方案,需外接运放实现电流采样,适合成本敏感的消费电子应用。
1.2 功率驱动拓扑
三相逆变器采用六开关拓扑结构,由三个半桥电路组成。每个半桥包含一个高端MOSFET和一个低端MOSFET,通过互补PWM信号驱动实现电机相电压的连续调节。
典型驱动方案采用L6387E半桥驱动芯片或DRV8301三相全桥驱动芯片。驱动芯片需要提供足够的驱动电流(通常为1A以上)和适当的隔离功能。
二、电流采样方案
2.1 三电阻采样
三电阻采样方案在每相下桥臂串联一个采样电阻,通过运放放大后送入ADC转换。该方案可在任意时刻获取三相电流值,采样精度高,但硬件成本也相应较高。
采样电阻选型需考虑以下因素:额定功率(建议选择1W以上)、温漂系数(1%精度要求下应选择50ppm/℃以下)、电阻值(通常为0.001-0.01Ω)。
采样电路采用差分放大配置,运放增益设置为10-20倍,以匹配ADC的输入范围。偏置电压通常设置为1.65V(3.3V供电时),使采样信号在ADC量程中点附近波动。
2.2 单电阻采样
单电阻采样方案仅在下桥臂公共点串联一个采样电阻,通过时序控制在不同时刻采样各相电流。该方案硬件简单,但算法复杂度较高,需要精确控制采样时机。
采样时机通常选择在PWM周期的特定位置,确保在对应相的下桥臂导通时进行采样。有效采样窗口宽度需根据占空比动态调整,一般设置为1-2μs。
| 方案 | 精度 | 成本 | 复杂度 | 适用功率 |
|---|---|---|---|---|
| 三电阻 | ±0.5% | 较高 | 高 | 5A-50A |
| 单电阻 | ±1.5% | 中等 | 中 | 1A-20A |
| 霍尔传感器 | ±0.1% | 最高 | 低 | 50A+ |
三、FOC控制算法实现
3.1 坐标变换原理
磁场定向控制(FOC)通过坐标变换将三相电流解耦为励磁分量和转矩分量,分别进行独立控制。坐标变换包括Clark变换、Park变换及其逆变换。
// Clark变换:三相静止坐标系 → 两相静止坐标系
ia = adc_a;
ib = (2 * adc_b + adc_a) / sqrt(3); // 基于基尔霍夫定律 ia+ib+ic=0
// Park变换:两相静止坐标系 → 两相旋转坐标系
id = ia * cos电角 + ib * sin电角;
iq = -ia * sin电角 + ib * cos电角;
// 电流环PI调节
vd = kp_d * (id_ref - id) + ki_d * 积分_d;
vq = kp_q * (iq_ref - iq) + ki_q * 积分_q;
// 逆Park变换
valpha = vd * cos电角 - vq * sin电角;
vbeta = vd * sin电角 + vq * cos电角;
// SVPWM调制
svpwm_compute(valpha, vbeta);
3.2 关键时序参数
// PWM开关频率 20kHz
const float PWM_PERIOD = 1.0f / 20000.0f;
// 死区时间防止上下桥臂直通
const float DEAD_TIME_NS = 250;
// 电流环执行周期
const uint32_t CURRENT_LOOP_HZ = 1000;
// 速度环执行周期
const uint32_t SPEED_LOOP_HZ = 100;
// ADC触发采样间隔
const float SAMPLE_PERIOD = 10e-6f; // 100kHz
3.3 STM32硬件配置
// 开启FPU和DSP指令集
SCB->CPACR |= (0xF << 20);
SCB->CCR |= SCB_CCR_DC_Msk | SCB_CCR_IC_Msk;
// 配置ADC为DMA循环模式
hdma_adc.Instance = DMA2_Channel0;
hdma_adc.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc.Init.Mode = DMA_CIRCULAR;
hdma_adc.Init.MemInc = DMA_MINC_ENABLE;
// 定时器触发ADC采样
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_TRGO;
四、采样时序控制
4.1 三电阻采样时序
三电阻采样的时序相对简单,可在PWM周期的任意时刻采样。建议在PWM周期的中点进行采样,此时开关噪声最小。
// PWM更新中断中触发ADC采样
void TIM1_UP_IRQHandler(void) {
if (采样标志 == 采样窗口) {
// 启动三通道ADC DMA传输
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)电流缓冲区, 3);
}
__HAL_TIM_CLEAR_IT(&htim1, TIM_IT_UPDATE);
}
4.2 单电阻采样时序
单电阻采样需要在PWM周期的特定位置进行多次采样才能重构三相电流。采样点通常设置在每个上桥臂导通周期的末尾。
// 单电阻电流重构
void 电流重构计算(void) {
// 第一个采样点:T1时刻(A相下桥臂导通)
float ia = (Vshunt[0] - Vshunt[3]) / (2.0f * Rshunt);
// 第二个采样点:T4时刻(B相下桥臂导通)
float ib = (Vshunt[1] - Vshunt[4]) / (2.0f * Rshunt);
// 第三个采样点:T6时刻(C相下桥臂导通)
float ic = (Vshunt[2] - Vshunt[5]) / (2.0f * Rshunt);
// 基尔霍夫校验
电流和 = ia + ib + ic; // 应接近零
}
五、系统资源优化
5.1 外设复用策略
STM32的外设复用功能可以显著减少GPIO使用数量。例如,TIM1的通道可同时配置为PWM输出和编码器接口,节省独立编码器引脚。
// 编码器模式配置(TIM1_CH1/CH2)
HAL_TIM_Encoder_Init(&htim1, TIM_ENCODERMODE_TI12);
// PWM输出模式配置(TIM1_CH3/CH4)
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
5.2 数值运算优化
FOC算法涉及大量三角函数和浮点运算,使用定点数运算可显著提升执行效率。Q格式定点数是电机控制领域的常用方案。
// Q15格式电流数据结构
typedef struct {
q15_t iq; // 转矩电流分量
q15_t id; // 励磁电流分量
} 电流坐标;
// 快速三角函数查表
static const q15_t sin_table[256] = { /* 正弦表 */ };
#define FAST_SIN(x) sin_table[(x) & 0xFF]
六、高级功能实现
6.1 无传感器控制
无传感器FOC通过观测反电动势来估算转子位置,省去位置传感器并降低成本。滑模观测器和龙贝格观测器是常用的两种方案。
// 反电动势位置估算
float 估算转子位置(float iq参考, float id参考, float 角速度) {
// 基于电压方程的位置估算
float 估算电角 = 当前电角 + (iq参考 * Lq * 角速度) / (3.0f * 磁链);
return 规范化角度(估算电角);
}
6.2 远程固件更新
OTA(Over-The-Air)升级功能使设备能够通过无线网络接收固件更新,适用于IoT设备和远程部署场景。
// OTA升级流程
void 系统升级(void) {
// 接收新固件数据
HAL_UART_Receive_DMA(&huart1, 升级缓冲区, 1024);
// 等待传输完成
while (升级进度 < 100);
// 写入Flash备份区
Flash_Write(备份区地址, 升级缓冲区, 固件大小);
// 跳转执行新固件
NVIC_SystemReset();
}
6.3 保护机制
完善的保护机制是工业电机驱动系统的必要组成部分。过流保护、过压保护和过温保护通常采用硬件比较器和软件监控双重保障。
// 过流故障处理
void 故障中断处理(void) {
if (过流标志) {
// 立即关闭PWM输出
HAL_TIM_PWM_Stop(&htim1);
// 触发报警输出
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
// 记录故障类型
故障日志[故障计数++] = FAULT_OVERCURRENT;
}
}