STM32 ADC 多通道采样:配置、校准与滤波的实用指南
👁 9 阅读 · 2026-08-14 · STM32 ADC
本文深入讲解STM32 ADC多通道采样的完整流程,包括扫描模式与注入模式的选择、采样时间优化、硬件过采样与软件滤波的权衡,以及ADC校准(尤其是不连续采样下的偏移误差校准)。通过一个基于HAL库的代码示例,演示如何配置多通道规则组连续采样,并给出简单有效的滑动平均滤波实现,帮助开发者解决实际项目中多通道数据采集的精度与稳定性问题。
## 一、先理解STM32 ADC多通道的几种工作模式
STM32的ADC支持**规则组**和**注入组**两类通道。规则组类似于常规轮询,最多16个通道;注入组类似中断优先,可插入到规则转换中。多通道采样最常用的是**规则组+扫描模式**,配合DMA可以无CPU干预地完成所有通道的循环采集。
关键概念:
- **扫描模式(Scan Mode)**:自动按顺序转换规则组中的所有通道。
- **不连续模式(Discontinuous Mode)**:每次触发只转换指定数量的通道,常用于节省功耗或配合定时器分批次采样。
- **采样时间**:影响ADC采样电容的充电时间,对高阻抗信号源尤其重要。
- **校准(Calibration)**:STM32片内ADC自带校准功能,用于消除电容匹配误差。
## 二、配置步骤(基于STM32CubeMX + HAL库)
1. **选择ADC实例**:在CubeMX中启用ADC1,将需要的通道(如CH0、CH1、CH2)配置为规则通道,并使能扫描模式。
2. **设置转换长度**:Number Of Conversion = 3,表示规则组中有3个通道。
3. **配置采样时间**:根据信号源内阻调整,通常设置55.5或84周期(即ADC时钟下)。若信号源高阻,建议加大到239.5周期。
4. **开启DMA**:将ADC1的DMA请求添加到循环模式,外设地址为ADC->DR,内存地址为自定义数组。
5. **ADC校准**:在初始化后调用HAL_ADCEx_Calibration_Start()。注意此函数会阻塞一段时间,建议放在启动后主循环前。
## 三、完整代码示例(STM32F1 / F4系列通用)
以下代码适用于STM32F4系列,使用ADC1的CH0~CH2采样三个模拟信号,DMA循环传输到数组,主循环中计算滑动平均滤波结果。
```c
// adc_config.h
#define ADC_CH_NUM 3
extern uint16_t adc_raw[ADC_CH_NUM];
extern float adc_filtered[ADC_CH_NUM];
void ADC_Init(void);
void ADC_Filter(void);
// adc_config.c
#include "adc_config.h"
#include "main.h"
static ADC_HandleTypeDef hadc1;
static DMA_HandleTypeDef hdma_adc1;
uint16_t adc_raw[ADC_CH_NUM];
float adc_filtered[ADC_CH_NUM];
#define FILTER_WINDOW 8
static uint16_t filter_buf[ADC_CH_NUM][FILTER_WINDOW];
static uint8_t filter_index = 0;
void ADC_Init(void)
{
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_DMA2_CLK_ENABLE();
// 配置DMA(ADC1的DMA请求映射到DMA2 Stream0)
hdma_adc1.Instance = DMA2_Stream0;
hdma_adc1.Init.Channel = DMA_CHANNEL_0;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR;
hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
HAL_DMA_Init(&hdma_adc1);
__HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);
// ADC1配置
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.ContinuousConvMode = ENABLE; // 连续采样
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = ADC_CH_NUM;
HAL_ADC_Init(&hadc1);
// 配置三个规则通道
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.SamplingTime = ADC_SAMPLETIME_84CYCLES; // 根据信号源内阻调整
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = 1;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = 2;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
sConfig.Channel = ADC_CHANNEL_2;
sConfig.Rank = 3;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
// 校准
HAL_ADCEx_Calibration_Start(&hadc1);
// 启动ADC并开启DMA
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc_raw, ADC_CH_NUM);
}
// 滑动平均滤波(每通道)
void ADC_Filter(void)
{
filter_index = (filter_index + 1) % FILTER_WINDOW;
for (int i = 0; i < ADC_CH_NUM; i++) {
filter_buf[i][filter_index] = adc_raw[i];
uint32_t sum = 0;
for (int j = 0; j < FILTER_WINDOW; j++) {
sum += filter_buf[i][j];
}
adc_filtered[i] = (float)sum / FILTER_WINDOW;
}
}
```
## 四、校准注意事项
- STM32的ADC校准适用于所有转换模式,但**在连续扫描+DMA模式下,校准不会影响实时数据流**,需在启动转换前完成。
- 有些系列(如F4)校准前需要先将ADC使能,且等待稳定时间。HAL库函数已封装,直接调用即可。
- 若使用不同参考电压或环境温度变化大,建议定期重新校准。
## 五、滤波策略:硬件过采样 vs 软件滤波
- **硬件过采样**:部分STM32支持过采样(oversampling),通过硬件累加+移位提高有效分辨率,适合低噪声信号。但每个通道会增加转换时间,且需要精确配置。
- **软件滤波**:灵活多样,滑动平均、中值滤波、IIR低通滤波等。对于工频干扰(50/60Hz),可结合定时器触发与整数周期采样。
- 推荐做法:先使用硬件过采样(如果支持)或增加采样时间降低噪声,再叠加简单的滑动平均或移动平均,计算代价小。
## 六、常见问题与注意事项
- **规则组转换序列溢出**:如果NbrOfConversion设置小于实际配置的Rank数,会漏掉通道。务必保证两者相等。
- **DMA数据错位**:当ADC通道转换顺序与DMA缓冲写入不匹配时,会让数据张冠李戴。必须保持通道顺序和数组索引一致。
- **注入组冲突**:如果同时使用注入组且优先级高于规则组,会导致规则组转换被中断,时间轴抖动。若非必要,建议关闭注入组。
- **高阻抗信号**:采样时间过短会导致充电不足,产生非线性误差。可使用运放跟随器或延长采样周期。
- **参考电压噪声**:VREF+引脚上必须接高质量去耦电容,否则会影响所有通道的转换精度。
- **多ADC同步**:如果需要同时采样多个通道,可考虑多ADC同步模式(如使用ADC1和ADC2),但要注意外设映射冲突。
## 七、总结
STM32 ADC多通道采样的核心在于正确配置扫描模式、通道顺序和采样时间,并利用DMA卸载CPU。校准能消除固定偏移误差,而滤波则是抑制噪声的有效手段。实际项目中应根据信号特性和实时性要求,灵活组合硬件过采样、软件滤波和触发方式。希望本文的示例与经验能帮助你在开发中少走弯路。