STM32F4 供电模式切换下的 ADC 采样稳定性:LDO/DCDC 切换与内部参考电压漂移的实战对策
👁 1 阅读 · 2026-08-27 · 嵌入式
在 STM32F4 系列中,LDO 与 DCDC 供电模式切换虽能优化功耗,却常引发内部参考电压(VREFINT)漂移,导致 ADC 采样值跳变。本文深入剖析漂移机理,结合硬件去耦、软件校准与切换时序控制,提供一套完整的工程解决方案,并给出可直接落地的代码示例,帮助开发者彻底解决切换瞬间的采样异常。
# 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 库)
```c
// 供电模式切换与 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 通道实时补偿。实际项目中,建议结合具体电源设计进行验证,必要时引入自适应滤波算法,确保系统长期稳定。