3. 电流采样校准
任务目标
编写STM32程序读取电机相电流ADC值,通过偏移校准与增益校准,使零电流时读数输出为零,并验证校准后电流精度满足±0.1A要求。
硬件与依赖
- STM32F405(或其他带ADC的STM32),使用ADC1注入组采样两路相电流(如U相、V相)
- 电流传感器:采样电阻+运放,输出0~3.3V至ADC引脚,零点为1.65V(对应ADC值约2048,12位)
- 依赖HAL库:
stm32f4xx_hal_adc.h、stm32f4xx_hal_gpio.h
校准原理
偏移校准:电机静止且无电流时,采集N次ADC值取平均,得到偏移量offset。增益校准:施加已知直流电流(如5A),采集ADC值,计算增益系数k = I_ref / (ADC_ref - offset)。实际电流计算公式:I = (ADC_raw - offset) * k。零电流时,ADC_raw ≈ offset,输出接近0。
关键完整代码
// current_calib.h
#ifndef CURRENT_CALIB_H
#define CURRENT_CALIB_H
#include "stm32f4xx_hal.h"
#define ADC_BITS 12
#define ADC_MAX 4095
#define SAMPLE_COUNT 100 // 校准采样次数
#define I_REF 5.0f // 增益校准参考电流(A)
typedef struct {
ADC_HandleTypeDef* hadc;
uint32_t channel_u; // U相ADC通道
uint32_t channel_v; // V相ADC通道
float offset_u; // U相偏移量(ADC值)
float offset_v; // V相偏移量
float gain_u; // U相增益(A/LSB)
float gain_v; // V相增益
} CurrentSensor;
void CurrentSensor_Init(CurrentSensor* sens, ADC_HandleTypeDef* hadc,
uint32_t ch_u, uint32_t ch_v);
void CurrentSensor_OffsetCalib(CurrentSensor* sens);
void CurrentSensor_GainCalib(CurrentSensor* sens);
float CurrentSensor_GetCurrent_U(CurrentSensor* sens);
float CurrentSensor_GetCurrent_V(CurrentSensor* sens);
#endif
// current_calib.c
#include "current_calib.h"
static uint32_t ADC_ReadChannel(ADC_HandleTypeDef* hadc, uint32_t channel) {
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = channel;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_84CYCLES;
HAL_ADC_ConfigChannel(hadc, &sConfig);
HAL_ADC_Start(hadc);
HAL_ADC_PollForConversion(hadc, 10);
uint32_t val = HAL_ADC_GetValue(hadc);
HAL_ADC_Stop(hadc);
return val;
}
void CurrentSensor_Init(CurrentSensor* sens, ADC_HandleTypeDef* hadc,
uint32_t ch_u, uint32_t ch_v) {
sens->hadc = hadc;
sens->channel_u = ch_u;
sens->channel_v = ch_v;
sens->offset_u = 0;
sens->offset_v = 0;
sens->gain_u = 1.0f;
sens->gain_v = 1.0f;
}
void CurrentSensor_OffsetCalib(CurrentSensor* sens) {
// 电机静止、无电流时执行
uint32_t sum_u = 0, sum_v = 0;
for (int i = 0; i < SAMPLE_COUNT; i++) {
sum_u += ADC_ReadChannel(sens->hadc, sens->channel_u);
sum_v += ADC_ReadChannel(sens->hadc, sens->channel_v);
}
sens->offset_u = (float)sum_u / SAMPLE_COUNT;
sens->offset_v = (float)sum_v / SAMPLE_COUNT;
}
void CurrentSensor_GainCalib(CurrentSensor* sens) {
// 施加已知直流电流 I_REF 后执行
uint32_t sum_u = 0, sum_v = 0;
for (int i = 0; i < SAMPLE_COUNT; i++) {
sum_u += ADC_ReadChannel(sens->hadc, sens->channel_u);
sum_v += ADC_ReadChannel(sens->hadc, sens->channel_v);
}
float adc_u = (float)sum_u / SAMPLE_COUNT;
float adc_v = (float)sum_v / SAMPLE_COUNT;
sens->gain_u = I_REF / (adc_u - sens->offset_u);
sens->gain_v = I_REF / (adc_v - sens->offset_v);
}
float CurrentSensor_GetCurrent_U(CurrentSensor* sens) {
uint32_t adc = ADC_ReadChannel(sens->hadc, sens->channel_u);
return (float)(adc - sens->offset_u) * sens->gain_u;
}
float CurrentSensor_GetCurrent_V(CurrentSensor* sens) {
uint32_t adc = ADC_ReadChannel(sens->hadc, sens->channel_v);
return (float)(adc - sens->offset_v) * sens->gain_v;
}
// main.c 调用示例
CurrentSensor sensor;
CurrentSensor_Init(&sensor, &hadc1, ADC_CHANNEL_0, ADC_CHANNEL_1);
// 1. 偏移校准(电机静止无电流)
CurrentSensor_OffsetCalib(&sensor);
// 2. 增益校准(施加5A直流电流)
CurrentSensor_GainCalib(&sensor);
// 3. 运行中读取电流
float iu = CurrentSensor_GetCurrent_U(&sensor);
float iv = CurrentSensor_GetCurrent_V(&sensor);
运行与验证
- 编译烧录后,保持电机静止(无电流),调用
CurrentSensor_OffsetCalib()完成偏移校准。 - 通过外部电源向电机U相注入5A直流电流(V相不注入),调用
CurrentSensor_GainCalib()完成增益校准。 - 验证零电流:断开外部电源,读取
CurrentSensor_GetCurrent_U()和CurrentSensor_GetCurrent_V(),观察串口输出。 - 验证精度:分别注入1A、3A、5A已知电流,读取计算值,与真实值比较。
通过标准:零电流时读数在±0.05A以内;1A、3A、5A时误差均不超过±0.1A。
预期输出(示例)
零电流: U=0.02A, V=-0.01A
1A测试: U=1.03A
3A测试: U=2.98A
5A测试: U=5.01A
常见问题
- 偏移校准必须在电机完全静止时进行,否则偏移量包含反电动势误差。
- 增益校准电流方向需与传感器正方向一致,否则增益为负值。
- 若ADC采样噪声较大,可增加
SAMPLE_COUNT或添加硬件低通滤波。