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);

运行与验证

  1. 编译烧录后,保持电机静止(无电流),调用CurrentSensor_OffsetCalib()完成偏移校准。
  2. 通过外部电源向电机U相注入5A直流电流(V相不注入),调用CurrentSensor_GainCalib()完成增益校准。
  3. 验证零电流:断开外部电源,读取CurrentSensor_GetCurrent_U()和CurrentSensor_GetCurrent_V(),观察串口输出。
  4. 验证精度:分别注入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或添加硬件低通滤波。