4. 电流采样与重构
任务目标
在STM32 FOC控制中,电机相电流是电流环反馈的关键输入。本案例实现基于定时器触发ADC注入组采样的双电阻电流重构方案:在PWM中心对齐计数模式下,利用两个下桥臂导通时刻采样U、V相电流,并通过基尔霍夫定律重构W相电流,最终验证采样时序正确性与重构精度。
硬件与依赖
- 硬件:STM32G431(或同类带ADC注入组的FOC专用MCU)、DRV8323或类似栅极驱动器、双电阻采样板(采样电阻位于下桥臂GND侧)
- 软件:STM32CubeMX生成的HAL工程,启用TIM1高级定时器(中心对齐PWM模式)、ADC1注入组、DMA
采样原理与时序
采用七段式SVPWM,PWM周期中心处两个零矢量(000/111)作用,此时下桥臂全部导通,电流经下桥臂续流,采样电阻两端电压正比于相电流。在中心对齐计数的上溢/下溢中断点触发ADC注入组采样,可同时采集U、V两相电流。W相电流由iw = -(iu + iv)计算。采样窗口需避开PWM边沿附近的开关噪声,因此ADC触发点应设置在计数顶点或底点并插入适当死区补偿。
关键完整代码
// adc_current_sensor.h
#ifndef ADC_CURRENT_SENSOR_H
#define ADC_CURRENT_SENSOR_H
#include "main.h"
typedef struct {
float iu; // U相电流 (A)
float iv; // V相电流 (A)
float iw; // W相电流 (A)
float iu_offset; // U相零电流偏置 (ADC码)
float iv_offset; // V相零电流偏置 (ADC码)
float adc_to_amp; // ADC码转电流系数 (A/LSB)
} CurrentSensor_t;
void CurrentSensor_Init(CurrentSensor_t *sensor);
void CurrentSensor_ReadPhaseCurrents(CurrentSensor_t *sensor);
void CurrentSensor_CalibrateOffsets(CurrentSensor_t *sensor);
#endif
// adc_current_sensor.c
#include "adc_current_sensor.h"
#include "tim.h"
#include "adc.h"
extern ADC_HandleTypeDef hadc1;
extern TIM_HandleTypeDef htim1;
static volatile uint32_t adc_buffer[2]; // DMA存储注入组转换结果
void CurrentSensor_Init(CurrentSensor_t *sensor) {
// 假设供电电压3.3V,运放增益10倍,采样电阻0.01Ω
// ADC 12位分辨率,满量程4096
// 电流系数 = Vref / (4096 * Rshunt * Gain) = 3.3 / (4096 * 0.01 * 10)
sensor->adc_to_amp = 3.3f / (4096.0f * 0.01f * 10.0f);
sensor->iu_offset = 2048.0f; // 零电流时ADC中点(需校准)
sensor->iv_offset = 2048.0f;
sensor->iu = 0.0f;
sensor->iv = 0.0f;
sensor->iw = 0.0f;
}
void CurrentSensor_CalibrateOffsets(CurrentSensor_t *sensor) {
// 电机静止且下桥臂全部导通时采样,取多次平均作为零电流偏置
uint32_t sum_u = 0, sum_v = 0;
const int samples = 100;
for (int i = 0; i < samples; i++) {
HAL_ADCEx_InjectedStart(&hadc1); // 软件触发一次注入组转换
HAL_ADCEx_InjectedPollForConversion(&hadc1, 10);
sum_u += HAL_ADCEx_InjectedGetValue(&hadc1, ADC_INJECTED_RANK_1);
sum_v += HAL_ADCEx_InjectedGetValue(&hadc1, ADC_INJECTED_RANK_2);
}
sensor->iu_offset = (float)sum_u / samples;
sensor->iv_offset = (float)sum_v / samples;
}
void CurrentSensor_ReadPhaseCurrents(CurrentSensor_t *sensor) {
// 读取DMA搬运的注入组转换结果(由TIM1触发)
uint32_t adc_u = adc_buffer[0];
uint32_t adc_v = adc_buffer[1];
// 转换为实际电流值(考虑方向:下桥臂采样,电流流入为正)
sensor->iu = (adc_u - sensor->iu_offset) * sensor->adc_to_amp;
sensor->iv = (adc_v - sensor->iv_offset) * sensor->adc_to_amp;
sensor->iw = -(sensor->iu + sensor->iv); // 基尔霍夫重构
}
// 在TIM1周期中断中调用(中心对齐模式,上溢/下溢均触发)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim == &htim1) {
// 读取最新采样结果(DMA已自动更新)
// 此处可加入电流环控制代码
}
}
// main.c 中的初始化与调用示例
#include "adc_current_sensor.h"
CurrentSensor_t current_sensor;
void FOC_CurrentLoop_Init(void) {
// 1. 初始化传感器参数
CurrentSensor_Init(¤t_sensor);
// 2. 校准零电流偏置(电机上电静止时执行一次)
CurrentSensor_CalibrateOffsets(¤t_sensor);
// 3. 配置TIM1触发ADC注入组
// 在CubeMX中配置:TIM1_TRGO2事件触发ADC1注入组
// ADC1注入组使能DMA循环模式,数据宽度32位,内存地址指向adc_buffer
// 4. 启动PWM和ADC
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);
HAL_ADCEx_InjectedStart_DMA(&hadc1, (uint32_t *)adc_buffer, 2);
HAL_TIM_Base_Start_IT(&htim1); // 使能更新中断用于控制节拍
}
// 在TIM1更新中断中周期调用
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim == &htim1) {
CurrentSensor_ReadPhaseCurrents(¤t_sensor);
// 此处可读取 current_sensor.iu/iv/iw 用于电流环PI控制
}
}
CubeMX关键配置
- TIM1:PWM Generation CH1/CH2/CH3及互补输出,计数模式为Center Aligned mode 1,周期值根据PWM频率设定(如20kHz对应PSC=0, ARR=1700 @170MHz)
- ADC1:注入组2个通道(对应U、V相采样电阻经运放后的电压),采样时间设为最大(如47.5周期)以增强抗噪;触发源选择Timer 1 Trigger 2 event
- DMA:ADC1注入组请求映射到DMA1 Channel1,循环模式,数据宽度Word
- GPIO:采样电阻运放输出连接至ADC输入引脚(如PA0、PA1)
验证方法与判定标准
验证采样时序:在电机静止且下桥臂全部导通(输出零矢量000)时,用示波器测量采样电阻电压波形,同时观察ADC注入组转换完成标志。在TIM1中心计数顶点附近应能看到ADC触发脉冲,且转换结果稳定无毛刺。
验证重构精度:向电机注入已知直流电流(如通过外部电源在电机绕组中通入1A直流),读取current_sensor.iu、current_sensor.iv、current_sensor.iw值。判定标准:
- 三相电流之和
|iu + iv + iw| < 0.05A(验证基尔霍夫重构一致性) - 各相读数与外部注入电流值的误差在±5%以内(验证ADC转换精度)
- 当外部电流为0时,三相读数均接近0(验证偏置校准有效)
预期输出示例(注入1A直流时):iu=0.98A, iv=-0.51A, iw=-0.47A,三相和接近0。此结果由给定电流分配关系直接推出,实际值取决于电机绕组连接方式。
常见问题
- 采样点落在开关噪声区:调整TIM1的TRGO2触发位置(可配置为上升沿/下降沿),或增大ADC采样时间以滤除尖峰
- 重构电流在低调制比时失真:当PWM占空比接近0%或100%时,下桥臂导通时间不足以保证ADC采样窗口,此时需切换为三电阻采样或插入测量矢量
- 零电流偏置漂移:运放温漂会导致偏置变化,建议在电机每次启动前重新执行
CurrentSensor_CalibrateOffsets()