STM32 ADC多通道采样:采样电容保持时间与通道串扰的边界测试方法
👁 2 阅读 · 2026-08-27 · 嵌入式
在STM32多通道ADC采集中,采样电容的保持时间直接影响通道间串扰水平。本文深入剖析采样电容的工作原理,提出一套可量化的边界测试方法,通过调整采样周期与通道切换顺序,定位串扰临界点,并给出完整代码示例与工程注意事项,帮助开发者优化多通道采集精度。
# 基于 STM32 的 ADC 多通道采样时采样电容保持时间与通道串扰的边界测试方法
## 一、问题背景
在嵌入式系统中,STM32 的 ADC 常被用于多通道模拟信号采集。当通道切换频繁时,采样电容(Sample-and-Hold Capacitor)的充电时间不足,会导致前一个通道的残余电荷影响当前通道的采样值,即产生**通道串扰**。这种串扰在高速采集或高阻抗信号源时尤为明显,严重时会造成数据失真。
## 二、原理剖析
### 2.1 采样电容的工作机制
STM32 的 ADC 采用逐次逼近型(SAR)架构,内部有一个采样电容。采样阶段,开关闭合,电容充电至输入电压;保持阶段,开关断开,电容电压被比较器逐次比较。采样时间(Sampling Time)必须足够长,使电容电压稳定到输入电压的精度范围内(通常为 1/2 LSB)。
### 2.2 通道串扰的根源
多通道采集时,ADC 在通道间切换。若采样时间过短,电容未完全放电或充电,残留电荷会叠加到下一次采样值上。串扰大小取决于:
- 采样时间(可配置的采样周期数)
- 通道切换顺序(相邻通道的电压差)
- 信号源阻抗(影响充电时间常数)
### 2.3 边界测试的必要性
不同 STM32 型号、不同时钟频率、不同供电电压下,最优采样时间不同。通过边界测试,可以找到“串扰可接受”的最小采样周期,从而在保证精度的前提下提高采样速率。
## 三、测试方法设计
### 3.1 测试原理
构造两个通道:CH0 接高电平(如 3.3V),CH1 接低电平(如 0V)。交替采样,并改变采样周期。当采样周期较短时,CH1 的采样值会因 CH0 的残留而偏高,串扰率 = (V_CH1_实际 - V_CH1_理想) / (V_CH0 - V_CH1)。记录不同采样周期下的串扰率,找到串扰率 < 1 LSB 的最小采样周期。
### 3.2 硬件准备
- STM32 开发板(以 STM32F103 为例)
- 两个稳定的直流电源(或分压电阻)
- 示波器(可选,用于验证)
### 3.3 软件配置步骤
1. **初始化 ADC**:配置为扫描模式,通道序列为 CH0, CH1。
2. **设置采样时间**:通过寄存器调整采样周期数(如 1.5、7.5、13.5、28.5、41.5、55.5、71.5、239.5 周期)。
3. **循环采集**:每次切换采样时间,采集多组数据,计算平均值和串扰率。
4. **记录结果**:输出串扰率与采样周期的关系。
## 四、完整代码示例
以下代码基于 STM32 HAL 库,演示了自动扫描不同采样时间并输出串扰率。
```c
#include "stm32f1xx_hal.h"
ADC_HandleTypeDef hadc1;
static void ADC_Init(void)
{
__HAL_RCC_ADC1_CLK_ENABLE();
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ENABLE; // 扫描模式
hadc1.Init.ContinuousConvMode = DISABLE; // 单次转换
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 2; // 两个通道
HAL_ADC_Init(&hadc1);
// 配置通道0和通道1,采样时间在循环中修改
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5; // 初始值
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = 2;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}
// 设置采样时间(通过修改通道配置)
static void SetSamplingTime(uint32_t samplingTime)
{
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = 1;
sConfig.SamplingTime = samplingTime;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = 2;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}
// 读取两个通道的转换值
static void ReadADC(uint16_t *ch0, uint16_t *ch1)
{
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 10);
*ch0 = HAL_ADC_GetValue(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 10);
*ch1 = HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);
}
int main(void)
{
HAL_Init();
ADC_Init();
// 假设 CH0 接 3.3V,CH1 接 0V,参考电压 3.3V,12位分辨率
uint32_t samplingTimes[] = {
ADC_SAMPLETIME_1CYCLE_5,
ADC_SAMPLETIME_7CYCLES_5,
ADC_SAMPLETIME_13CYCLES_5,
ADC_SAMPLETIME_28CYCLES_5,
ADC_SAMPLETIME_41CYCLES_5,
ADC_SAMPLETIME_55CYCLES_5,
ADC_SAMPLETIME_71CYCLES_5,
ADC_SAMPLETIME_239CYCLES_5
};
const char *timeNames[] = {"1.5", "7.5", "13.5", "28.5", "41.5", "55.5", "71.5", "239.5"};
for (int i = 0; i < 8; i++) {
SetSamplingTime(samplingTimes[i]);
uint32_t sum0 = 0, sum1 = 0;
const int samples = 100;
for (int j = 0; j < samples; j++) {
uint16_t ch0, ch1;
ReadADC(&ch0, &ch1);
sum0 += ch0;
sum1 += ch1;
}
float avg0 = (float)sum0 / samples;
float avg1 = (float)sum1 / samples;
// 理想情况下 ch1 应为 0,串扰率 = avg1 / avg0 * 100%
float crosstalk = (avg1 / avg0) * 100.0f;
printf("Sampling time: %s cycles, CH0=%.2f, CH1=%.2f, Crosstalk=%.3f%%\n",
timeNames[i], avg0, avg1, crosstalk);
}
while (1) {}
}
```
## 五、测试结果分析
- 当采样周期从 1.5 增加到 239.5 时,串扰率应逐渐下降。
- 通常,当采样周期 ≥ 13.5 时,串扰率可降至 0.1% 以下(对应 12 位 ADC 的 1 LSB 约为 0.024%)。
- 若串扰率始终较高,需检查信号源阻抗,必要时增加外部电容或使用缓冲器。
## 六、注意事项
- **信号源阻抗**:高阻抗源会增大充电时间常数,需更长采样时间。建议信号源阻抗 < 10kΩ。
- **通道顺序**:将电压接近的通道相邻排列,可减小串扰影响。
- **参考电压稳定性**:测试时务必使用稳定的参考电压,否则结果失真。
- **多次采样取平均**:为消除噪声,每次测试应采集多次取平均值。
- **不同型号差异**:STM32F1 与 F4 系列采样电容值不同,需重新测试。
- **使用 DMA**:实际项目中建议使用 DMA 连续采集,减少 CPU 干预,但测试时需注意时序一致性。
## 七、总结
通过上述边界测试方法,开发者可以量化采样电容保持时间与通道串扰的关系,为多通道 ADC 应用选择最优采样周期。该方法简单实用,可移植到其他 STM32 系列,是嵌入式系统设计中的重要调试手段。