嵌入式ADC高精度采集实战指南:从硬件到软件的踩坑记录

做了6年工业数据采集,从12位到24位ADC,把硬件设计、软件滤波、误差校准的经验全倒出来

2026-09-14
ADC采集高精度参考电压源软件滤波16位ADC工业采集

先说结论:做高精度采集,硬件是决定上限的,软件是拉高下限的。参考源选不好、PCB布错了,再牛的软件算法也救不了。一般工业采集,12位ADC(STM32自带的)够用了;要求高一点上16位(ADS1115、AD7606之类);再高精度就上24位Σ-Δ型(ADS1256、ADS1299),但主要用在称重、温度等低速高精度场景。别盲目追求高分辨率,先搞清楚你需要多少精度。

ADC采集是嵌入式开发里最常见的功能之一,也是坑最多的功能之一。很多人觉得"不就是读个ADC值嘛,有什么难的",结果做出来的数据跳得一塌糊涂,最后不知道问题出在哪。

我们团队做工业数据采集做了6年,从单通道到32通道,从12位到24位,从毫伏级信号到毫安级信号,各种采集场景都做过。踩过的坑能列一长串——参考源温漂大、PCB地线没布好、电源纹波大、前端运放自激、软件滤波过度……

今天这篇文章,从ADC选型到硬件设计,从PCB布局到软件滤波,从误差校准到常见坑,给你讲透。

一、先搞清楚:分辨率、精度、采样率不是一回事

很多人一上来就说"我要16位精度的ADC",这是典型的概念混淆。三个概念先分清楚:

大白话解释:分辨率就像尺子上的刻度——12位是4096个小格,16位是65536个小格。但尺子本身不准(参考源有误差),刻度再细也没用。精度就是这把尺子准不准。采样率就是你多久读一次数——信号变化快的话,你得频繁读才能看清变化过程。

那怎么选ADC?看你的需求:

ADC类型 典型分辨率 典型精度 采样率 适用场景
MCU内置ADC 10~12位 ±1%~±3%FS 几十kHz~几MHz 电池电压、按键检测、一般测量
SAR型外置ADC 12~16位 ±0.1%~±0.5%FS 几百kHz~几MHz 工业采集、多通道、中速高精度
Σ-Δ型ADC 18~24位 ±0.01%~±0.1%FS 几Hz~几十kHz 称重、温度、压力等低速高精度
项目经验:我们做智慧供暖项目的时候,最开始用STM32自带的12位ADC采集温度和压力,总感觉数据跳得厉害,误差有2%~3%。后来客户要求精度到0.5%以内,我们就换了外置的16位ADC(ADS1115),精度一下就上去了,做到了0.2%左右。不是说内置ADC不好,而是内置ADC受MCU内部干扰大,参考源也一般,对精度要求高的场合还是得用外置的。

二、硬件设计:精度的上限是硬件决定的

做高精度采集,硬件设计是基础。硬件没设计好,软件再怎么滤波、再怎么校准,也达不到理想的精度。

1. 参考电压源——最关键的元件

ADC的测量基准是参考电压(Vref)。参考源不准,ADC再准也白搭。举个例子:你的参考源标称2.5V,实际只有2.45V,差了2%,那所有测量结果都会差2%。

常见的参考源方案:

参考源方案 初始精度 温漂 价格(约) 适用场景
MCU内部参考 ±3%~±5% 几十~上百 ppm/℃ 0元 粗略测量、对精度要求不高
TL431并联基准 ±0.5%~±1% ~50 ppm/℃ 0.2元 一般应用,性价比高
REF3030/REF3325 ±0.1%~±0.2% 10~20 ppm/℃ 3~5元 高精度工业级,常用
REF5025/ADR431 ±0.05%以内 3~5 ppm/℃ 15~30元 高精度仪器、仪表
LTZ1000 ±0.005%以内 0.05 ppm/℃ 上百元 基准源、计量级
真实踩坑:我们早期做的一块采集板,用了TL431做参考源,常温下测着还行。到了冬天,客户反映数据不准了。我们拿到现场一看,车间里白天20多度,晚上可能零下几度,温度变化二三十度。TL431的温漂是50ppm/℃,20度就是0.1%,看起来不多,但加上其他误差累积,最后整体误差就超了。后来换成REF3030(15ppm/℃),温漂的影响就小多了。做工业产品,温漂这个参数千万别忽略。

2. 电源设计——纹波和噪声是杀手

ADC对电源噪声很敏感。电源上的纹波会直接耦合到ADC的采样结果里,表现为数据跳变。

电源设计要点:

3. 前端信号调理——让信号匹配ADC

很多传感器输出的信号很弱(比如毫伏级),直接给ADC的话,分辨率不够用。这时候就需要前端放大——用运放把信号放大到ADC满量程附近。

前端调理的常见需求:

运放选型要点:

经验之谈:选运放别只看增益带宽积,失调电压和温漂更重要。我们做称重传感器采集的时候,最开始选了个普通运放(LM358),结果零点漂移特别厉害,温度一变,零点能飘几十毫伏。换成了高精度运放(OP07级别以上),漂移一下就小了。做高精度采集,运放别省钱,一块钱的差价,效果差很多。

4. PCB布局——很多问题都是布出来的

ADC电路的PCB布局特别讲究,布不好,硬件再完美也白搭。几个关键原则:

经典坑:我们有一块8通道采集板,刚做出来的时候,数据总是有50Hz的工频干扰,跳来跳去的。查了很久,最后发现问题出在PCB上——模拟输入线从一个LED旁边走过去了,LED的电源线是50Hz整流后的,工频干扰直接耦合到了模拟线上。把那条线改了个方向,干扰就小多了。别小看PCB布局,一条线走对走错,效果天差地别。

三、软件滤波:拉高下限的利器

硬件做好了,数据还是会有噪声——这很正常,世界上没有绝对干净的信号。这时候就要靠软件滤波了。

常用的几种滤波算法,各有优缺点:

滤波算法 原理 优点 缺点 适用场景
限幅滤波 两次采样差值超过阈值就丢弃 简单、高效、防脉冲干扰 不能滤除平滑噪声 变化缓慢的信号,去掉跳点
算术平均滤波 N次采样取平均值 简单、对随机噪声效果好 有延迟、浪费资源 对实时性要求不高的信号
滑动平均滤波 用队列存N个数据,每次更新一个 实时性好、平滑 RAM占用多、有延迟 大多数采集场景,最常用
中值滤波 N次采样取中间值 对脉冲干扰效果极好 计算量大、对平滑噪声效果一般 有尖峰干扰的信号
一阶低通滤波 本次结果 = α×本次采样 + (1-α)×上次结果 超简单、省RAM、平滑 有相位滞后 慢速变化的信号,简单有效
卡尔曼滤波 基于状态方程的最优估计 效果好、动态响应快 复杂、需要调参数 对动态响应和精度都有要求

我们团队最常用的组合是:限幅 + 滑动平均。先去掉明显的跳点,再做平均,效果不错,计算量也不大,一般的MCU都能跑。

// 限幅 + 滑动平均 组合滤波 —— 我们项目里用得最多的组合
// 原理:先限幅去掉尖脉冲,再滑动平均平滑噪声

#define FILTER_N 10      // 滑动平均窗口大小,越大越平滑但延迟越大
#define MAX_DIFF  50      // 限幅阈值,单位是ADC的LSB,根据实际情况调

static int filter_buf[FILTER_N];  // 滤波缓冲区
static int buf_index = 0;
static int last_val = 0;
static int sum = 0;

int adc_filter(int new_val)
{
    // 第一步:限幅滤波 —— 变化太大的数据直接扔掉
    if (last_val != 0) {
        int diff = new_val - last_val;
        if (diff > MAX_DIFF || diff < -MAX_DIFF) {
            return last_val;  // 跳变太大,不用这个值,返回上次的
        }
    }

    // 第二步:滑动平均 —— 用新数据替换最老的数据
    sum -= filter_buf[buf_index];     // 减去最老的数据
    filter_buf[buf_index] = new_val;  // 存入新数据
    sum += new_val;                   // 加上新数据

    buf_index++;
    if (buf_index >= FILTER_N) {
        buf_index = 0;
    }

    last_val = sum / FILTER_N;  // 取平均值
    return last_val;
}

// 团队经验:窗口大小别太大,10~20次足够了
// 太大了延迟严重,传感器数据都变了,滤波结果还没跟上
// 实测发现:10次滑动平均,随机噪声能降70%左右,延迟也不大
实测对比:我们在一个16位ADC采集项目里测过,输入一个稳定的直流信号,原始数据的峰峰值波动约30个LSB。用10次滑动平均后,波动降到约8个LSB;用中值+平均(取10个值,去掉最大最小,剩下8个取平均),波动约5个LSB;用一阶低通(α=0.1),波动约3个LSB,但响应慢了很多。怎么选,看你的应用——对实时性要求高就用小窗口平均,对平滑度要求高就用大窗口或者低通。

四、校准:消除系统误差的必杀技

硬件做得再好,也会有系统误差——参考源有误差、运放有失调、电阻有公差。这些误差靠滤波是滤不掉的,必须校准。

常用的校准方法:

1. 两点校准(增益和失调校准)

最常用的校准方法。输入两个已知的标准值(比如0V和满量程),测出ADC的读数,算出增益系数和偏移量,以后每次采样都用这个系数修正。

公式:实际值 = (ADC读数 - 偏移量) × 增益系数

// 两点校准 —— 工业采集最常用的校准方法
typedef struct {
    float gain;     // 增益系数
    float offset;   // 偏移量
} adc_calib_t;

adc_calib_t calib;

// 校准函数:输入两个标准值和对应的ADC读数
void adc_calibrate(float std1, int adc1, float std2, int adc2)
{
    // 算增益:(标准值差) / (ADC读数差)
    calib.gain = (std2 - std1) / (float)(adc2 - adc1);
    // 算偏移:标准值1 - ADC读数1 × 增益
    calib.offset = std1 - calib.gain * (float)adc1;
}

// 校准后的实际值计算
float adc_get_real_value(int adc_val)
{
    return calib.gain * (float)adc_val + calib.offset;
}

// 这里容易踩坑:校准参数要存在Flash里,不能每次上电重新算
// 而且要加校验,防止Flash数据坏了导致结果完全不对
// 我们一般存两份参数,各加CRC校验,互为备份

2. 多点校准

如果系统的非线性比较严重,两点校准不够用,就用多点校准——测N个点,存一张校准表,实际使用的时候插值计算。精度更高,但也更麻烦。

一般来说,12位ADC两点校准就够了;16位以上的可以考虑多点校准。

五、工业数据采集项目:8通道16位ADC设计实录

我们给一家化工厂做的8通道数据采集模块,要求采集4~20mA电流信号,精度±0.2%FS,工作温度-20~60℃。

大概的设计思路:

最后实测的精度数据:

测试条件 原始误差(未校准) 校准后误差 加滤波后波动
常温(25℃) ±0.8% FS ±0.15% FS ±0.02% FS(峰峰值)
低温(-20℃) ±1.5% FS ±0.3% FS ±0.03% FS
高温(60℃) ±1.2% FS ±0.25% FS ±0.025% FS

客户要求±0.5%FS,我们做到了±0.3%FS(全温范围),余量还挺大的。

经验总结:做高精度采集,一定要留余量。客户要求0.5%,你不能刚好做到0.5%,得做到0.2%~0.3%,这样量产的时候才不会因为元器件公差、焊接差异等原因导致产品不合格。我们一般的原则是:设计指标要是客户要求的2倍以上。

六、7个ADC采集常见大坑

坑1:参考源用系统电源代替

现象:ADC读数随供电电压变化,电源波动的时候数据也跟着跳。

原因:很多图省事的做法——ADC的参考源直接接VCC。VCC是给系统供电的,上面有纹波,而且电压也不一定稳定,当然不准。

解决:高精度采集一定要用专用的参考电压源。哪怕是TL431,也比直接用VCC强。

坑2:模拟地和数字地乱接

现象:数据噪声大,有规则的干扰(比如50Hz工频、开关电源频率)。

原因:数字电路的开关噪声通过地回路耦合到模拟部分。

解决:模拟地和数字地分开布局,单点连接。如果是多层板,模拟层下面铺模拟地,数字层下面铺数字地。

坑3:输入阻抗不够,信号被拉低了

现象:测出来的值比实际值小,而且换个传感器误差就不一样。

原因:ADC的输入阻抗不够高,或者前端分压电阻太小,把传感器的信号拉低了。高输出阻抗的传感器(比如某些温度传感器、pH电极)特别容易出这个问题。

解决:前端加高输入阻抗的运放做电压跟随,或者选输入阻抗更高的ADC。

坑4:采样率太高,混叠了

现象:采到的信号里有奇怪的频率成分,跟实际信号对不上。

原因:采样率低于信号最高频率的2倍(奈奎斯特采样定理),发生了混叠。

解决:提高采样率,或者在ADC前面加抗混叠低通滤波,把采样率一半以上的频率滤掉。

坑5:多通道采集串扰

现象:多通道ADC,一个通道有信号,其他通道也跟着有,而且值跟那个通道有关。

原因:多通道ADC内部的模拟开关切换太快,前一个通道的电荷还没放掉,就切到了下一个通道,导致串扰。特别是高阻抗输入的时候更明显。

解决:切换通道后加个小延时再采样,或者每个通道采样多次,第一次的结果扔掉。也可以降低采样率,给模拟开关留出稳定时间。

坑6:运放自激振荡

现象:前端加了运放之后,噪声反而更大了,数据有高频抖动。

原因:运放电路自激了——可能是负载电容太大、反馈参数不对、或者电源退耦不好。

解决:在运放输出端加个小电阻(比如100Ω)驱动容性负载,或者在反馈电阻上并联一个小电容做相位补偿。用示波器看运放输出波形,有自激的话能看到高频振荡。

坑7:只校准常温,不考虑温漂

现象:常温下很准,到了现场(夏天热/冬天冷)就不准了。

原因:参考源、运放、电阻都有温漂,温度变了误差就大了。

解决:选低温漂的元器件(参考源、运放、电阻)。如果要求特别高,可以做温度补偿——测个温度传感器的值,根据温度修正校准系数。但这比较麻烦,能选好元器件就尽量选好的。

七、常见问题FAQ

Q1:STM32自带的ADC能做到多高精度?够用吗?

答:STM32的12位ADC,如果用内部参考源,不校准的话,大概±2%~±3%的精度。如果用外部参考源+校准+滤波,能做到±0.5%左右,一般应用够了。但要求更高(比如±0.1%以内),还是建议用外置ADC。内置ADC受MCU内部数字电路干扰大,而且参考源一般,极限精度有限。

Q2:16位ADC真的能用到16位吗?有效位数是多少?

答:一般用不到满16位。16位是分辨率,有效位数(ENOB)一般在12~14位左右,具体看你的设计水平。噪声大的话,可能有效位数还不到10位。衡量ADC实际效果,看有效位数比看分辨率更有意义。数据手册上一般会标ENOB参数,那个是理想条件下的,实际打个折。

Q3:4~20mA信号怎么采集?为什么用250Ω电阻?

答:4~20mA是工业上最常用的信号标准。采集的话,串一个精密电阻把电流转成电压,然后ADC采电压。250Ω电阻的话,4mA对应1V,20mA对应5V,刚好是很多ADC的输入范围(0~5V)。注意电阻要选精密的(0.1%精度以上),温漂也要小,不然电阻本身的误差就把精度吃掉了。

Q4:软件滤波是不是滤得越狠越好?

答:不是。滤波越狠,数据越平滑,但延迟也越大。比如你用100次平均,数据是平滑了,但信号变了之后要等很久滤波结果才跟上。对于需要快速响应的场合(比如报警、控制),延迟大了会出问题。选什么滤波、参数设多少,要根据实际需求来——平衡好平滑度和响应速度。

Q5:差分ADC和单端ADC有什么区别?什么时候用差分?

答:单端ADC是测信号对地的电压,差分ADC是测两个输入端之间的电压差。差分输入的好处是可以抑制共模干扰——比如两根线上都感应到了50Hz干扰,差分之后就抵消了。工业现场干扰大、或者信号是差分输出的(比如称重传感器、热电偶),就用差分输入。干扰小、信号是单端输出的,用单端就行,省通道。


总结

高精度ADC采集,是个系统工程——不是选个高分辨率ADC就完事了,参考源、前端运放、电源、PCB布局、软件滤波、校准,每个环节都影响最终精度。

我们做了这么多年采集,最深的体会是:硬件决定上限,软件决定下限。硬件设计好了,软件稍微处理一下就能达到不错的精度;硬件没设计好,再复杂的软件算法也救不了你。

所以做采集项目,先把硬件做扎实,再考虑软件优化。顺序别搞反了。

希望这篇文章对你有帮助。如果你的采集项目遇到了精度问题、干扰问题,也可以找我们聊聊——从毫伏到伏、从12位到24位,各种坑我们都踩过。

还想接着看

采集精度做不上去?

沧州艾诺威 — 6年工业数据采集经验,从12位到24位
硬件设计 · 软件滤波 · 系统校准,帮你把精度做上去

立即微信咨询

电话:13930711029 | 邮箱:tech@czinv.com | 24小时内响应