STM32F4 供电模式切换下的 ADC 采样稳定性:LDO/DCDC 切换与内部参考电压漂移的实战对策

一、问题现象与根源

在低功耗物联网设备中,STM32F4 常通过切换 LDO(低压差线性稳压器)与 DCDC(直流-直流转换器)模式来平衡功耗与性能。然而,切换瞬间 ADC 采样值常出现 ±10~30 LSB 的跳变,尤其在采集高精度传感器信号时不可接受。

根本原因

  • 内部参考电压 VREFINT(约 1.21V)由主电源 VDD 经内部 LDO 稳压产生,其稳定性依赖供电路径的阻抗与噪声。
  • 切换时,电源路径从 LDO 变为 DCDC(或反之),内部 LDO 的输入电压和负载瞬态响应发生变化,导致 VREFINT 出现毫秒级漂移(典型 5~20 mV)。
  • ADC 以 VREFINT 为基准(或用于校准),基准漂移直接转化为采样误差。

二、硬件设计关键点

1. 去耦电容布局

  • 在 VREF+ 引脚(若使用外部参考)或 VDD 引脚放置 1µF + 100nF 陶瓷电容,且尽量靠近 MCU,减少寄生电感。
  • 若使用内部参考,确保 VDD 去耦充分,建议在 VDD 与 VSS 之间并联 10µF 钽电容 + 100nF 瓷片电容。

2. 电源切换电路

  • 避免直接硬切,采用 MOSFET 或负载开关,并增加 RC 缓启动(时间常数 1~10ms),减缓电压突变。
  • 在 DCDC 输出端增加 LC 滤波器(如 2.2µH + 10µF),抑制开关纹波。

三、软件策略:三重防护

1. 切换时序控制

在切换前后,暂停 ADC 转换,等待 VREFINT 稳定。根据数据手册,稳定时间典型为 10µs,但建议预留 100µs 安全裕量。

2. 软件校准补偿

利用 VREFINT 校准通道(ADC_IN17)实时测量内部参考电压,动态修正采样值。原理:

  • 已知 VREFINT 标称值(如 1.21V),实际测量值反映当前基准漂移。
  • 修正公式:实际电压 = ADC_测量值 × (VREFINT_标称 / ADC_VREFINT_实测值)

3. 数字滤波

对采样结果应用中值滤波或移动平均,消除残余毛刺。

四、完整代码示例(基于 STM32F407,HAL 库)

// 供电模式切换与 ADC 校准示例
#include "stm32f4xx_hal.h"

ADC_HandleTypeDef hadc1;
static uint16_t vrefint_raw;
static float vrefint_voltage;

// 初始化 ADC1,使能内部 VREFINT 通道
void ADC_Init(void) {
    __HAL_RCC_ADC1_CLK_ENABLE();
    hadc1.Instance = ADC1;
    hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
    hadc1.Init.Resolution = ADC_RESOLUTION_12B;
    hadc1.Init.ScanConvMode = DISABLE;
    hadc1.Init.ContinuousConvMode = DISABLE;
    hadc1.Init.DiscontinuousConvMode = DISABLE;
    hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    hadc1.Init.NbrOfConversion = 1;
    HAL_ADC_Init(&hadc1);

    // 配置 VREFINT 通道(ADC_IN17)
    ADC_ChannelConfTypeDef sConfig = {0};
    sConfig.Channel = ADC_CHANNEL_VREFINT;
    sConfig.Rank = 1;
    sConfig.SamplingTime = ADC_SAMPLETIME_84CYCLES;
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}

// 读取 VREFINT 原始值
uint16_t Read_VREFINT(void) {
    HAL_ADC_Start(&hadc1);
    HAL_ADC_PollForConversion(&hadc1, 10);
    return HAL_ADC_GetValue(&hadc1);
}

// 切换供电模式(示例:LDO->DCDC)
void Switch_Power_Mode(PowerMode mode) {
    // 1. 停止 ADC 转换
    HAL_ADC_Stop(&hadc1);

    // 2. 执行切换(硬件操作,如 GPIO 控制)
    // HAL_GPIO_WritePin(PWR_EN_GPIO_Port, PWR_EN_Pin, (mode == DCDC) ? GPIO_PIN_SET : GPIO_PIN_RESET);

    // 3. 等待稳定(100µs,可调用 HAL_Delay(1) 或微秒延时)
    delay_us(100);

    // 4. 重新读取 VREFINT 并更新校准系数
    vrefint_raw = Read_VREFINT();
    vrefint_voltage = 1.21f * 4095.0f / vrefint_raw; // 实际 VDD 电压(假设 VREFINT 标称 1.21V)
}

// 修正 ADC 采样值(输入原始值,输出修正后的电压)
float Get_Compensated_Voltage(uint16_t raw_adc) {
    return (raw_adc * vrefint_voltage) / 4095.0f;
}

// 主函数示例
int main(void) {
    HAL_Init();
    ADC_Init();

    // 初始读取 VREFINT
    vrefint_raw = Read_VREFINT();
    vrefint_voltage = 1.21f * 4095.0f / vrefint_raw;

    while (1) {
        // 假设需要切换模式
        Switch_Power_Mode(DCDC);

        // 读取外部通道(如 ADC_IN0)并修正
        ADC_ChannelConfTypeDef sConfig = {0};
        sConfig.Channel = ADC_CHANNEL_0;
        sConfig.Rank = 1;
        sConfig.SamplingTime = ADC_SAMPLETIME_84CYCLES;
        HAL_ADC_ConfigChannel(&hadc1, &sConfig);
        HAL_ADC_Start(&hadc1);
        HAL_ADC_PollForConversion(&hadc1, 10);
        uint16_t raw = HAL_ADC_GetValue(&hadc1);
        HAL_ADC_Stop(&hadc1);

        float voltage = Get_Compensated_Voltage(raw);
        // 使用 voltage 进行后续处理
    }
}

五、注意事项与进阶优化

  • 切换频率:频繁切换会加剧 VREFINT 漂移,建议切换间隔 > 1ms,且切换后至少等待 100µs 再采样。
  • 温度影响:VREFINT 随温度漂移(典型 10ppm/°C),若环境温度变化大,需周期性校准(如每 10 秒一次)。
  • 多通道采样:若同时使用多个 ADC 通道,确保每个通道的采样时间足够(> 10µs),避免串扰。
  • 使用外部参考:若对精度要求极高(>12bit),建议使用外部精密参考(如 REF3030),并配置 VREF+ 引脚,此时内部 VREFINT 漂移影响可忽略。
  • 调试技巧:在切换瞬间用示波器观察 VDD 波形,若尖峰过大,可增加 RC 吸收电路。

六、总结

通过硬件去耦、切换时序控制、软件校准三重手段,可有效抑制 STM32F4 在 LDO/DCDC 切换时的 ADC 采样跳变。核心思路是“先稳定基准,再采样”,并利用 VREFINT 通道实时补偿。实际项目中,建议结合具体电源设计进行验证,必要时引入自适应滤波算法,确保系统长期稳定。