3. 电流采样与重构
任务目标
在无刷电机FOC控制中,电流环需要精确的相电流反馈。本案例设计基于单电阻的母线电流采样方案,利用PWM中心对齐模式下各相占空比的时间关系,在一个PWM周期内通过两次ADC采样重构出两相电流,并推导第三相电流,同时完成采样时刻的自动校准。
硬件与采样原理
单电阻采样将采样电阻串联在逆变器直流母线负端,通过检测不同开关状态下流过母线的电流来重构相电流。在中心对齐PWM中,当某一相上桥臂导通、其余两相下桥臂导通时,母线电流等于该相电流;当两相上桥臂导通时,母线电流等于第三相(未导通相)电流的负值。
采样窗口的有效性取决于各相占空比之间的差值。若两相占空比过于接近,对应的开关状态持续时间过短,无法完成ADC采样。因此需要根据当前占空比矢量选择最优的两次采样点,并确保采样时刻避开开关噪声。
核心代码实现
// 单电阻电流采样与重构 - 基于STM32 HAL库
// 依赖:TIM1中心对齐PWM,ADC1注入组采样,DMA传输
#define PWM_PERIOD 2400 // 定时器周期(中心对齐模式下为半周期值)
#define ADC_SAMPLE_TIME_NS 500 // ADC采样时间约500ns
#define DEAD_TIME_NS 200 // 死区时间
#define MIN_SAMPLE_WINDOW 1200 // 最小可靠采样窗口(ns),需大于ADC采样+死区
typedef struct {
uint16_t duty_a; // A相占空比(0~PWM_PERIOD)
uint16_t duty_b;
uint16_t duty_c;
float ia, ib, ic; // 重构后的三相电流(A)
uint8_t sample_valid;
} CurrentSensor_t;
CurrentSensor_t motor_current;
// 根据三相占空比选择采样扇区,返回两次采样的定时器比较值
void SelectSamplePoint(uint16_t *ccr_sample1, uint16_t *ccr_sample2) {
uint16_t d[3] = {motor_current.duty_a, motor_current.duty_b, motor_current.duty_c};
uint8_t idx[3] = {0, 1, 2};
// 冒泡排序:d[0]最小,d[2]最大
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2 - i; j++) {
if (d[j] > d[j+1]) {
uint16_t tmp = d[j]; d[j] = d[j+1]; d[j+1] = tmp;
uint8_t tmpi = idx[j]; idx[j] = idx[j+1]; idx[j+1] = tmpi;
}
}
}
uint16_t mid = d[1];
uint16_t min_val = d[0];
uint16_t max_val = d[2];
// 采样窗口检查:中间相与最小/最大相的差值需足够大
uint16_t window1 = mid - min_val; // 对应开关状态:中间相上桥导通
uint16_t window2 = max_val - mid; // 对应开关状态:最大相上桥导通
// 将占空比差值转换为时间(ns)
float clk_ns = 1.0f / 72e6 * 1e9; // 72MHz定时器时钟
float t_window1 = window1 * clk_ns;
float t_window2 = window2 * clk_ns;
if (t_window1 < MIN_SAMPLE_WINDOW || t_window2 < MIN_SAMPLE_WINDOW) {
motor_current.sample_valid = 0; // 扇区过小,无法可靠采样
return;
}
// 采样点设置在窗口中间,避开死区和开关噪声
// 第一次采样:中间相上桥导通期间(对应电流为中间相电流)
*ccr_sample1 = min_val + window1 / 2;
// 第二次采样:最大相上桥导通期间(对应电流为最大相电流的负值)
*ccr_sample2 = mid + window2 / 2;
motor_current.sample_valid = 1;
}
// ADC注入组转换完成回调(由DMA在两次采样完成后触发)
void HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef *hadc) {
if (hadc->Instance != ADC1) return;
uint32_t raw1 = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_1);
uint32_t raw2 = HAL_ADCEx_InjectedGetValue(hadc, ADC_INJECTED_RANK_2);
// 转换为电流值(假设采样电阻0.01Ω,运放增益50倍,ADC参考3.3V,12位)
float v1 = (float)raw1 / 4095.0f * 3.3f;
float v2 = (float)raw2 / 4095.0f * 3.3f;
float i1 = v1 / (0.01f * 50.0f); // 第一次采样电流
float i2 = v2 / (0.01f * 50.0f); // 第二次采样电流
// 根据排序索引映射到实际相电流
// 第一次采样:中间相上桥导通 → 母线电流 = 中间相电流
// 第二次采样:最大相上桥导通 → 母线电流 = -最大相电流
uint16_t d[3] = {motor_current.duty_a, motor_current.duty_b, motor_current.duty_c};
uint8_t idx[3] = {0, 1, 2};
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2 - i; j++) {
if (d[j] > d[j+1]) {
uint16_t tmp = d[j]; d[j] = d[j+1]; d[j+1] = tmp;
uint8_t tmpi = idx[j]; idx[j] = idx[j+1]; idx[j+1] = tmpi;
}
}
}
float i_mid = i1; // 中间相电流
float i_max = -i2; // 最大相电流(负号因为母线电流方向)
// 写入对应相
float *phase_currents[3] = {&motor_current.ia, &motor_current.ib, &motor_current.ic};
*phase_currents[idx[1]] = i_mid;
*phase_currents[idx[2]] = i_max;
// 第三相电流 = -(ia + ib)
*phase_currents[idx[0]] = -(i_mid + i_max);
}
// 在主循环中调用:更新占空比并触发采样
void CurrentSample_Update(uint16_t duty_a, uint16_t duty_b, uint16_t duty_c) {
motor_current.duty_a = duty_a;
motor_current.duty_b = duty_b;
motor_current.duty_c = duty_c;
uint16_t ccr1, ccr2;
SelectSamplePoint(&ccr1, &ccr2);
if (motor_current.sample_valid) {
// 配置ADC注入触发源为TIM1的CC1和CC2事件
TIM1->CCR1 = ccr1; // 第一次采样时刻
TIM1->CCR2 = ccr2; // 第二次采样时刻
// 使能ADC注入组转换
HAL_ADCEx_InjectedStart_IT(&hadc1);
}
}
采样时序校准
实际电路中,开关管驱动延迟、ADC采样保持电容充电时间会导致采样电流与理论值存在偏差。校准方法:在电机静止且无电流时,注入一个已知占空比(如50%),测量ADC读数作为零偏;然后逐步调整采样点位置(在窗口内前后移动),观察重构电流的纹波,选择纹波最小时的采样点作为最佳时刻。
运行与验证
- 硬件连接:将采样电阻(0.01Ω)接入逆变器负端与地之间,信号经差分运放(增益50倍)后连接ADC1的注入通道。
- 软件配置:TIM1配置为中央对齐模式(PWM模式1),更新事件在计数器上溢/下溢时产生;ADC1注入组配置为2个采样序列,触发源分别设为TIM1的CC1和CC2事件。
- 验证步骤:
- 电机开环运行(给定固定占空比),用示波器测量采样电阻两端电压,确认波形为阶梯状母线电流。
- 通过调试器读取
motor_current.ia/ib/ic,验证三相电流之和近似为零(误差<5%)。 - 在低速大电流工况下,检查
sample_valid标志:若频繁为0,说明采样窗口不足,需提高PWM载波频率或增加最小采样窗口阈值。
通过条件:当电机以恒定负载运行时,重构的三相电流波形平滑、无畸变,且与相电流探头实测值偏差小于10%。
常见问题
- 采样点靠近PWM边沿导致噪声:将采样点向窗口中心移动,并增加硬件RC滤波(截止频率约1MHz)。
- 低调制比时窗口过小:当某两相占空比接近时,可改用移相PWM或增加最小脉宽限制。
- ADC采样保持时间不足:确保ADC采样时间设置大于500ns,或降低定时器时钟频率。