4. STM32 ADC多通道采集配置与校准
工业数据采集终端往往需要同时监测多路模拟量,例如 4~20 mA 变送器、热电阻调理输出、电池电压和基准源。STM32 的 ADC 若只按单通道轮询方式使用,CPU 会被采样等待占满,通道间还会互相干扰。本节围绕“多通道如何组织、数据如何搬运、精度如何校准、时间如何分配”四个问题展开,把 ADC 配置成一条稳定的采集流水线。
规则组与注入组:两类通道的分工
STM32 ADC 的通道被划分为规则组(Regular)和注入组(Injected)。规则组是主采集序列,可配置最多 16 个通道,按顺序自动转换,转换结果写入同一个数据寄存器;注入组最多 4 个通道,拥有独立的数据寄存器,可被外部触发打断规则组,常用于需要更高优先级、更快响应的信号,例如过流保护采样或同步采样点。
规则组的关键限制是“结果共用一个寄存器”。如果不用 DMA,每转换完一个通道就必须及时读走,否则会被下一通道覆盖。因此多通道规则采集几乎必然配合 DMA。注入组则相反,4 个通道各有独立结果寄存器(JDR1~JDR4),可在转换结束后一次性读取,适合少量高优先级通道。
一个典型分工示例:规则组顺序采集 6 路慢变信号(温度、压力、液位等),注入组采集 2 路快变保护信号(母线电流、阀位反馈)。规则组由定时器触发,注入组由比较器或外部事件触发,两者互不阻塞。
DMA 循环搬运:让数据自动落位
规则组多通道采集的标准做法是开启 DMA 循环模式(Circular)。ADC 每完成一次转换就发出 DMA 请求,DMA 把 ADC_DR 中的结果搬到内存数组,地址自增,搬完一轮后自动回到数组首地址继续。CPU 完全不参与搬运,只在半满或全满中断里处理数据。
配置要点如下:
- DMA 方向为外设到存储器,外设地址固定为 ADC 数据寄存器,存储器地址自增。
- 数据宽度按分辨率选择:12 位结果用半字(16 位)即可,避免字节对齐问题。
- 循环模式使能,否则一轮结束后 DMA 停止,后续转换结果无处存放。
- DMA 缓冲区长度等于规则组通道数,保证“通道—数组下标”一一对应。
下面是一段基于 HAL 库的规则组 + DMA 循环采集配置示例,采集 6 个通道,缓冲区 6 个半字:
#define ADC_CH_NUM 6
static uint16_t adc_buf[ADC_CH_NUM];
// ADC 规则组通道顺序:IN0, IN1, IN4, IN5, IN6, IN7
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
uint32_t ch_list[ADC_CH_NUM] = {
ADC_CHANNEL_0, ADC_CHANNEL_1, ADC_CHANNEL_4,
ADC_CHANNEL_5, ADC_CHANNEL_6, ADC_CHANNEL_7
};
for (int i = 0; i < ADC_CH_NUM; i++) {
sConfig.Channel = ch_list[i];
sConfig.Rank = i + 1; // 规则组顺序
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}
// 启动 DMA 循环搬运
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc_buf, ADC_CH_NUM);
启动后 adc_buf[0] 对应 IN0,adc_buf[1] 对应 IN1,依此类推。若发现通道错位,优先检查 Rank 顺序与数组下标是否一致,而不是怀疑硬件。
过采样:用时间换有效位数
STM32 部分系列内置硬件过采样单元,可对同一通道连续采样 N 次并累加/平均,把结果右移后输出。过采样能抑制随机噪声,提高有效分辨率。例如 12 位 ADC 做 16 倍过采样并右移 2 位,理论上可得到约 14 位有效分辨率,但代价是转换时间变为原来的 16 倍。
过采样配置需关注三个参数:过采样倍数(2~256)、右移位数、触发模式。倍数与右移要匹配:16 倍过采样通常右移 2 位,256 倍右移 4 位。若右移过多会丢失有效位,右移过少则结果溢出。过采样适合低频信号,如温度、称重;对高频动态信号会引入额外延迟,需谨慎使用。
内部参考电压校准:消除供电漂移
工业现场 VDDA 常由 LDO 提供,存在温漂和负载波动。若直接用 VDDA 作为参考计算电压,误差会直接进入结果。STM32 内部有一个出厂校准的参考电压通道 VREFINT,其典型值约 1.21 V,且在芯片出厂时把该通道在 3.3 V 下的 12 位校准值写入系统存储区。
校准思路是:先采集 VREFINT 通道的原始码值,再读取出厂校准值,反推出当前实际 VDDA:
// VREFINT_CAL 为出厂校准值,典型地址 0x1FFF75AA
#define VREFINT_CAL_ADDR 0x1FFF75AAUL
#define VREFINT_CAL_VOLT 1210UL // 单位 mV,示例值
uint16_t vref_raw = adc_buf_vref[0]; // VREFINT 通道原始码
uint16_t vref_cal = *(uint16_t *)VREFINT_CAL_ADDR;
// 当前 VDDA(mV)= 校准电压 × 校准码 / 实测码
uint32_t vdda_mv = (VREFINT_CAL_VOLT * vref_cal) / vref_raw;
// 用实际 VDDA 换算任意通道电压
uint32_t ch_mv = (uint32_t)adc_buf[i] * vdda_mv / 4095UL;
这样即使 VDDA 从 3.30 V 漂到 3.24 V,换算结果仍能保持稳定。注意 VREFINT 通道也要纳入规则组或单独采集,且采样时间要足够长(建议 ≥ 71.5 周期),否则内部参考尚未建立稳定。
采样时间优化:在精度与速度之间取舍
采样时间决定采样保持电容的充电时长。信号源内阻越大,所需采样时间越长。经验公式为:采样时间 ≥ (R_source + R_ADC) × C_ADC × ln(2^N),其中 N 为目标精度位数。工程上常用做法是:低阻信号(运放直驱)用 7.5~15 周期,中阻信号用 41.5~71.5 周期,高阻或内部通道用 247.5 周期以上。
采样时间过短会导致读数偏低且通道间串扰明显,表现为“后一个通道受前一个通道影响”。若发现相邻通道读数相关性强,应优先增大采样时间,而不是改滤波算法。
配置检查与结果判读
完成上述配置后,可用以下顺序快速验证:先单独采集 VREFINT,确认反推的 VDDA 在 3.2~3.4 V 之间;再给已知通道加固定电压,检查换算值与万用表读数偏差是否在 ±1% 以内;最后观察多通道连续采集时相邻通道是否串扰。若偏差偏大,按“采样时间 → 参考电压校准 → 过采样设置”的顺序排查,而不是先改软件滤波。