☰
ADC三架构全解析:Flash、流水线、SAR与STM32/ESP32采样实战
2026/9/29 12:32:44 网站建设 项目流程

做过物联网项目的朋友大概都有这种体会:传感器那一头送过来的,永远是一个连续变化的电压,可能是热敏电阻分压后的零点几伏,也可能是电流采样电阻上几毫伏的压差;而单片机那一头能处理的,只有0和1。ADC(模拟转数字转换器)就是横在中间的那道关口,它决定了你的设备到底是"感知准确"还是"数据全靠抖"。这几年物联网从智能家居铺到智慧零售、智慧物流,环境监测、电池管理、电机控制里到处都是ADC采样,但是真正把Flash ADC、流水线ADC和逐次逼近型SAR ADC这三种架构掰开揉碎讲清楚的材料并不多,很多刚入门的朋友只知道"调个库函数读值",出了问题就抓瞎。这篇内容我想从原理层往下钻,把三种架构的工作机制、速度精度取舍、采样电路设计、VREF选择、滤波写法一直到实际排查的坑,全部串一遍,适合做嵌入式、物联网终端开发,以及正在准备毕业设计、需要把采样精度做扎实的朋友参考。

1. 先搞清楚物联网为什么绕不开ADC这件事

1.1 模拟量与数字量之间那道必过的坎

物理世界里的温度、压力、光照、电流、加速度,本质上都是连续变化的模拟量,它们在时间轴和幅值上都没有"台阶"。而MCU、SoC、DSP内部的所有运算都是基于离散的数字编码,这两套语言体系之间必须有一个翻译官,这个翻译官就是ADC。翻译的过程分成四步:采样、保持、量化、编码。采样是在时间轴上打点,把连续信号切成一个个瞬间值;保持是把这一瞬间的电压"冻住",让后面的电路有时间慢慢处理;量化是把连续幅值映射到有限个刻度上;编码则是把刻度号转成二进制。

这里有个很多人一上来就忽略的点:量化一定带来误差,而且是不可逆的。一个N位ADC,把参考电压VREF均分成2^N份,每一份就是一个LSB,LSB = VREF / 2^N。你拿一个12位、VREF为3.3V的ADC去测一个1.000V的电压,理论上读到的码值是1.000 / (3.3/4096) ≈ 1241,但真实电压可能是1240.5对应的那个值,误差最大±0.5LSB,这就是量化误差,任何架构都逃不掉,只能靠提高位数或者降低VREF来减小。

所以当你抱怨"ADC读出来老是跳"的时候,先别急着怀疑电路,先算一下你的量化台阶有多大。3.3V参考、12位,一个LSB就是0.8mV左右,如果你的信号本身只有几十毫伏,那跳动的幅度完全在正常量化误差范围内,这不是bug,这是物理规律。

1.2 三种主流架构各自守着的阵地

市面上ADC架构很多,但落到实际项目里,出镜率最高的就是三种:Flash ADC、流水线ADC、SAR ADC。它们的关系有点像交通工具:Flash是赛车,起步就冲,但费油、占地、座位少;流水线是高铁,分段接力,速度快还能拉人;SAR是家用轿车,省油、便宜、够用,绝大多数通勤场景都是它。

  • Flash ADC:全并行结构,一次比较直接出结果,速度最快,但功耗和面积随位数指数爆炸,通常用在对速度极度敏感、位数要求不高的地方。
  • 流水线ADC(Pipeline ADC):把一次转换拆成多级,每级只负责几位,级间接力,兼顾速度与分辨率,常见于通信、视频、医疗成像前端。
  • SAR ADC(逐次逼近型):用二分查找的思路逐步逼近,N位大约需要N个时钟周期,功耗低、面积小、分辨率适中,是MCU内置ADC的绝对主力,也是物联网终端最常打交道的类型。

把这三者的边界划清楚,后面选型和排查就不会乱。接下来我逐个拆。

2. Flash ADC:拿面积和功耗硬换速度的暴力打法

2.1 一次比较直接出码值的工作机制

Flash ADC又叫全并行ADC,它的思路非常直接,甚至有点"莽"。一个N位的Flash ADC,内部有2^N - 1个比较器和一串等值电阻组成的分压网络。假设做3位,那就是7个比较器、8个等值电阻。参考电压VREF加在电阻串两端,每个电阻节点上的电压依次是VREF/8、2VREF/8、3VREF/8……一直排到7VREF/8,这7个节点分别接到7个比较器的负端,输入模拟信号同时送到所有比较器的正端。

输入电压一进来,凡是分压节点电压低于输入电压的比较器,输出全部为1;低于输入电压的那些,输出全部为0。于是7个比较器的输出就形成了一串"温度计码",比如输入是3.5VREF/8,那前3个比较器输出1,后面4个输出0。温度计码再经过编码器转换成二进制,就得到最终的数字输出。

这个结构最迷人的地方是:整个转换只经历一次比较器的传播延迟,加上编码器的组合逻辑延迟,没有循环、没有时钟逐位逼近,所以速度可以做到GSPS级别。高端示波器的前端ADC就是这么来的。

2.2 气泡错误和编码器这道坎

温度计码看起来很美好,实际上有个很讨厌的问题叫"气泡错误"。理论上温度计码应该是"1连续、0连续"的规整形态,但比较器之间存在失调、亚稳态、时钟偏斜,可能导致中间某个比较器输出反了,变成"1 1 0 1 0"这种夹心状态,这就是气泡。气泡一旦出现,编码器直接把它转成一个完全离谱的码值,比如本该是4,结果跳成7。

工程上的解法通常有两手:一是用格雷码编码器代替普通二进制编码器,降低相邻码值跳变时的误码风险;二是加冗余比较器,用校准逻辑纠正。即便如此,Flash ADC的分辨率还是上不去,因为位数每加1,比较器数量翻倍,8位要255个比较器,10位要1023个,功耗、面积、输入电容全都失控。

注意:Flash ADC的高输入电容是个隐形坑,它会和前一端信号源的输出阻抗形成RC低通,直接吃掉带宽。设计驱动电路时必须核算源阻抗。

它的典型应用场景很明确:高速示波器、雷达接收前端、光通信、高速串行链路的模拟前端。功耗动辄几百毫瓦到几瓦,明显不是物联网终端能承受的,但它代表的速度极限,是理解另外两种架构的基准线。

3. 流水线ADC:把一次大转换拆成多级接力赛

3.1 分级量化加余差放大的核心思路

流水线ADC的思路很聪明:既然一次性做到高位数太难,那就把任务拆开。一个12位的流水线ADC,可以做成6级,每级2位,或者更多级、每级1.5位。每一级内部其实就是一个低分辨率的Flash ADC加一个DAC加一个减法器加一个放大器。

具体过程是这样的:第一级先粗粗量化输入信号,得到一个高2位的猜测值,然后把这个猜测值送进一个2位DAC还原成模拟电压,用原始输入减去这个还原值,得到"余差";余差再乘以放大倍数(通常是2^2=4倍),送到第二级继续量化。第二级再猜两位,再算余差放大传给第三级,如此接力。最后把所有级的输出拼起来,经过数字校正,得到完整的12位结果。

这个"余差放大"是整个架构的灵魂。它保证了下一级只需要处理幅度更小的信号,但相对精度要求不变,于是每一级都可以用简单的低分辨率结构实现,整体堆出高分辨率。

3.2 流水线延迟和数字校正

流水线ADC有个特有的概念叫"延迟"(latency),不是吞吐率的延迟,而是单次转换从输入到输出的固有延迟。因为它是一级一级串下去的,第一个采样点必须等所有级都处理完才能输出,延迟等于级数乘以各级的时钟周期。但好消息是,它同时又是流水作业的,第一级处理完第一个点后马上可以开始处理第二个点,所以吞吐率可以做到每个时钟周期出一个结果,速度和延迟是两码事。

另一个关键是数字校正。实际电路里比较器有失调,增益也不精确,光靠模拟电路做到12位以上几乎不可能。所以现代流水线ADC普遍采用冗余位设计,比如每级做1.5位,多出来的那0.5位用来纠错,最后在数字域把多余的位通过加法、移位消掉。这就是为什么很多流水线ADC的每级结构看起来"多几个比较器",不是设计失误,是故意留的纠错余量。

3.3 速度、功耗、精度三者的平衡点

流水线ADC的定位在Flash和SAR之间。速度上,它可以做到几十到几百MSPS,比SAR快一到两个数量级;分辨率上,12到16位很常见,比Flash高;功耗和面积介于两者之间,但模拟部分的运放、电容匹配、基准稳定性要求都很高。

代价在于:它需要高精度运放做余差放大,需要良好的时钟抖动控制,采样保持电路的孔径抖动直接影响高频信噪比。另外它的输入电容和开关噪声也比SAR大。所以它多见于基站接收机、超声成像、专业视频采集这类对速度有硬需求、对成本和功耗不那么敏感的场合。物联网终端里基本见不到独立的流水线ADC,但很多通信模组的模拟前端内部,你拆开看就是它。

4. SAR ADC:物联网终端里真正的主角

4.1 二分查找式的逐次逼近逻辑

SAR ADC的工作方式特别像我们小时候玩"猜数字"游戏:主持人心里想一个0到1023之间的数,你每次猜中间值,对方告诉你"大了"或"小了",你据此缩小一半范围,最多猜10次就能锁定答案。SAR ADC就是这个逻辑的硬件实现。

一个N位SAR ADC内部有三个核心部件:采样保持电路、比较器、SAR逻辑寄存器(含DAC)。转换开始时,采样开关把输入电压存到采样电容上;然后SAR逻辑从最高位(MSB)开始,先把这一位设成1,DAC输出一个VREF/2,比较器判断输入电压比它大还是小;如果输入更大,这一位保持1,否则清0;接着处理次高位,DAC输出相应调整,比较,再决定该位。一轮下来,N个时钟周期就得到N位结果。

举个例子,12位、VREF为3.3V、输入是2.0V。第一步比较2.0V和1.65V(3.3/2),输入大,MSB=1;第二步比较2.0V和2.475V(3.3的3/4),输入小,次高位=0;第三步比较2.0V和2.0625V(3.3的5/8),还是小,该位=0……这样一位一位逼近,最终落在2048这个码值附近,对应2.0/3.3*4096 ≈ 2482,实际会因为前面推演简化略有出入,但逻辑就是这样。你可以自己拿纸笔推一遍12位,会非常直观。

4.2 电容DAC阵列与采样保持电路

早期SAR ADC用电阻串或者电流源做DAC,现在主流是电荷再分配型电容DAC(CDAC)。原理是一组二进制加权的电容阵列,最高位电容容量是C,次高位是C/2,依次减半,最低位是C/2^(N-1)。通过控制每个电容是接VREF还是接地,就能在比较器输入端合成出不同的电压。

这个设计的好处非常明显:电容的相对匹配精度在CMOS工艺里天然就比电阻好,做12位甚至16位都不吃力;而且采样保持和DAC可以复用同一组电容,省面积省功耗。缺点也有,电容阵列的开关切换会产生开关噪声和电荷注入,高速时比较器的失调和噪声直接影响有效位数。

采样保持电路是另一个关键。采样开关通常是MOS管,采样瞬间它的导通电阻和采样电容构成RC网络,如果采样时间不够,电容充不到最终值,就会产生增益误差。所以采样时间(sampling time)必须留足,一般要求大于5到10倍的时间常数。这也解释了为什么很多MCU的ADC提供可配置的采样周期,采样时间设得太短,读出来的值就偏小。

4.3 采样时间、采样周期、信噪比这几个参数怎么算

这是实际项目里最常混淆的地方。采样周期(sampling period)是从一次采样开始到下一次采样开始的总时间,等于采样时间(sampling time)+ 转换时间(conversion time)。ADC的有效转换一次所需的总时间决定了最大采样率,比如STM32的12位SAR,采样时间可设为1.5到239.5个ADC时钟周期,转换时间固定约12.5个周期,如果你的ADC时钟是12MHz,采样时间设15个周期,那总周期约27.5个周期,最大采样率约436kSPS。

信噪比(SNR)的理想公式是 SNR = 6.02N + 1.76 dB,纯理论下12位ADC的SNR约74dB,有效位数ENOB = (SNR - 1.76) / 6.02。但实际会因为抖动、非线性、基准噪声打折扣,能到10.5到11位有效就很不错了。你在选型时,别被"12位"这个标称值骗了,要看数据手册里的ENOB或者SINAD。

还有个必须记住的规则:采样率必须满足奈奎斯特,fs ≥ 2倍信号最高频率,否则会发生频谱混叠,高频信号折叠到低频区,你根本无法从数据里分辨它是真信号还是假信号。实际工程中通常取5到10倍以上,给抗混叠滤波器留余量。

5. 三种架构横向对比与选型决策

5.1 关键参数对照表

把三种架构放在一张表里对比,选型的时候一眼就能定位。

对比维度Flash ADC流水线ADCSAR ADC
转换机制全并行一次比较多级余差接力逐次二分逼近
典型分辨率3~8位10~16位8~18位
典型速度数百MSPS~GSPS数十~数百MSPS数十kSPS~数MSPS
转换延迟极低,一个周期中等,等于级数×周期N个时钟周期
功耗水平高中到高低
芯片面积大(指数增长)中小
主要成本点比较器数量、编码器高精度运放、匹配电容匹配、比较器失调
典型应用示波器、光通信通信接收、超声、视频MCU内置、传感器采样

5.2 物联网项目的实际选型逻辑

在物联网终端里,选型逻辑其实很朴素:绝大多数场景直接用MCU内置的SAR ADC就够了,因为你的传感器带宽本来就不高。温度采集、电池电压监测、光照强度、电位器位置,这些信号变化速度可能只有几赫兹到几kHz,12位SAR完全覆盖。

少数场景会考虑外置ADC。比如做振动监测、音频采集、电力谐波分析,需要几十到几百kSPS以上并且对一致性有要求,这时可以选外置的高性能SAR或者Σ-Δ型。做无线通信模组的基带前端,才可能碰到流水线架构。至于Flash,在终端侧基本没有直接使用场景,它的知识更多是帮你理解速度和面积的权衡本质。

我个人的经验是:先看信号带宽,再定采样率,再反推架构,最后才看分辨率。很多人顺序反了,一上来就追求"16位ADC",结果前端电路噪声比量化台阶还大,16位读出来只有10位有效,纯属浪费。

6. 实战:基于STM32和ESP32的SAR ADC采样落地

6.1 采样电路设计和VREF选择的门道

先说VREF。很多新手直接用MCU的VDDA当参考,或者干脆用内部参考,结果发现温漂大、精度差。内置参考或者电源参考的缺点是它本身会随负载和温度波动。如果项目对精度有要求,建议外接一个专用的基准芯片,比如2.5V或3.0V的低温漂基准,接到VREF+引脚上,再配上0.1μF和1μF的去耦电容靠近引脚放置。

VREF选多大也有讲究。VREF越小,一个LSB对应的电压越小,小信号分辨率越高,但可测的输入范围也越窄,且对噪声越敏感。我一般的原则是:让被测信号的最大值占VREF的70%到90%,既充分利用量程,又给过冲留余量。比如测0到2.4V的信号,选2.5V或3.0V基准都合适。

采样前端电路的典型结构是:传感器信号先经过一个电压跟随器(运放缓冲)降低源阻抗,再串联一个小电阻(10到100欧)限流,接着一个RC低通滤波(比如1k欧+100nF,截止频率约1.6kHz),最后进ADC引脚。这个RC既抗混叠又抑制高频干扰,一举两得。但RC的时间常数必须远小于采样时间,否则会出现采样不充分导致的读数偏低。

提示:ADC输入引脚绝对不要悬空,悬空引脚会拾取环境噪声,读出来的值随机跳,而且会在通道间串扰。不用的通道要么接地,要么在配置里禁用。

6.2 DMA加定时器触发的采样配置

用软件循环读ADC是最容易踩坑的方式,因为读的时刻不固定,采样间隔抖动大,做频谱分析时完全没法用。正确做法是用定时器触发ADC,再用DMA搬运数据。

配置思路是:把定时器设置成PWM输出模式但不使能输出引脚,通过TRGO事件触发ADC启动;ADC配置成外部触发、连续转换关闭、DMA循环模式;DMA配置成从ADC数据寄存器搬到内存数组,传输长度设成缓冲大小。这样定时器每次溢出,ADC自动采一个点,DMA自动搬走,CPU完全不参与,采样间隔由定时器时钟精确决定。

采样率的计算就变成了:fs = 定时器时钟 / (预分频+1) / (自动重载值+1)。比如72MHz时钟,预分频设为0,自动重载设为999,那fs = 72MHz / 1000 = 72kSPS。这个精度比软件延时靠谱得多。

配置完成后一定要用示波器或者逻辑分析仪看一眼采样触发信号和ADC转换信号,确认没有丢点或者重复触发。我见过有人DMA缓冲区大小和ADC数据宽度没对齐(16位缓冲配12位右对齐数据),结果数据全错位,排查了半天。

6.3 几种实用的ADC滤波函数写法

原始采样值必然带噪声,滤波是必须的。下面几个C函数都是我在实际项目里反复用的,直接抄就行。

中值滤波适合去掉脉冲干扰,比如电机换向、继电器动作时产生的尖峰:

#define MED_WIN 5 uint16_t median_filter(uint16_t new_val) { static uint16_t buf[MED_WIN] = {0}; static uint8_t idx = 0; uint16_t tmp[MED_WIN]; uint8_t i, j; buf[idx] = new_val; idx = (idx + 1) % MED_WIN; for (i = 0; i < MED_WIN; i++) tmp[i] = buf[i]; // 简单冒泡排序,窗口小,开销可接受 for (i = 0; i < MED_WIN - 1; i++) for (j = 0; j < MED_WIN - 1 - i; j++) if (tmp[j] > tmp[j + 1]) { uint16_t t = tmp[j]; tmp[j] = tmp[j + 1]; tmp[j + 1] = t; } return tmp[MED_WIN / 2]; }

滑动平均适合平滑随机噪声,对周期性干扰效果一般,但计算量小:

#define AVG_N 16 uint16_t moving_average(uint16_t new_val) { static uint32_t sum = 0; static uint16_t buf[AVG_N] = {0}; static uint8_t idx = 0; sum -= buf[idx]; buf[idx] = new_val; sum += new_val; idx = (idx + 1) % AVG_N; return (uint16_t)(sum / AVG_N); }

一阶低通(指数加权)适合信号缓变、又要保留一定响应速度的场合,比如温度、电池电压:

// alpha越小越平滑,但响应越慢,一般取0.05~0.3 float low_pass(float new_val, float alpha) { static float y = 0.0f; y = alpha * new_val + (1.0f - alpha) * y; return y; }

实际工程里我通常把三者串起来用:先中值去尖峰,再滑动平均压随机噪声,最后一阶低通做最终平滑。注意不要为了追求"数字好看"把滤波做得太重,否则真实信号的快速变化会被吃掉,比如你做的是过流保护,滤波太狠可能导致保护动作延迟,得不偿失。

6.4 硬件滤波和端口保护不能省

软件滤波只能处理已经进到ADC的数据,如果干扰在采样瞬间就耦合进来,软件也无能为力。硬件上要做三件事:

第一,串联限流电阻加钳位。ADC输入引脚前串一个100欧到1k欧的电阻,再并在引脚处接两个肖特基二极管,一个到电源一个到地,做钳位保护。这样即使输入端意外接了高压,也不会直接烧掉引脚。

第二,RC低通滤波要靠近引脚。电阻和电容的物理位置越靠近ADC引脚,滤波效果越好,因为走线本身就是天线。电容选C0G或X7R材质,容值100nF配合电阻形成合适截止频率。

第三,去耦和地平面。模拟电源和数字电源分开走线,VDDA和VSSA单独去耦,模拟地单点接到数字地。这一点在多层板上比较容易做到,两层板要格外小心,模拟走线尽量短、远离时钟线和PWM线。

我在一个带Wi-Fi的ESP32项目里踩过一次坑:Wi-Fi一开启,ADC读数就跳十几个码值,加滤波也没用。后来发现是射频部分的电源和模拟电源共用了一段走线,改成独立LDO供电加星形接地后,跳动降到两三个码值以内。所以很多所谓的"ADC噪声大",本质是电源和布线问题,不是ADC本身不行。

7. 常见问题与排查技巧实录

7.1 采样值跳动、偏移、非线性的排查思路

读数不稳定是最高频的抱怨,排查要分层次。先看跳动幅度是否在±0.5到1个LSB以内,如果是,那是正常的量化噪声和热噪声,不用管。如果跳动几十个LSB,那就往下查。

现象可能原因排查方法
读数整体偏大或偏小VREF不准、采样时间不足万用表实测VREF,加长采样时间
读数随机跳动大电源噪声、地线干扰、输入悬空示波器看电源纹波,检查接地
高通道串扰到低通道采样电容切换残留、走线耦合增加通道间采样间隔,拉开走线
满量程附近非线性输入超出VREF范围、钳位导通确认输入不超过VREF+0.3V
数据周期性错位DMA宽度与对齐方式不匹配检查DMA数据宽度和ADC对齐配置
温漂明显内部参考温漂大换外置低温漂基准

7.2 采样周期和转换时钟的匹配问题

前面说过,ADC时钟太快会导致采样不充分。很多MCU的ADC时钟是独立分频的,默认可能偏高,需要手动降下来。STM32F1系列的ADC时钟不能超过14MHz,F4系列不能超过36MHz,不同系列差别很大,一定要查手册。我见过有人把ADC时钟配到60MHz,结果读数整体偏低且不线性,就是因为采样电容根本充不满。

采样时间的设置也有个经验公式:采样时间要大于等于(源阻抗+开关导通电阻)×采样电容×ln(2^(N+1))除以ADC时钟周期。这个数值算起来麻烦,实操上用一半的量程点做验证就行:输入一个已知的中间电压,逐步增大采样时间,看读数何时稳定,稳定后再留2倍余量。

7.3 几个只有踩过才知道的实操教训

第一个教训:不要用杜邦线做模拟信号输入。杜邦线的接触电阻不稳定,而且线长容易拾取干扰,短时间测试可能没问题,一做成产品就翻车。模拟信号尽量用短而粗的走线或者屏蔽线。

第二个教训:内部参考和VDDA的关系要理清。很多MCU内部参考其实就是VDDA经内部缓冲得到,VDDA不稳,参考就不稳。如果你用USB供电,USB电压波动加上纹波,采出来必然跳。

第三个教训:校准不能只在开机做一次。有些MCU支持ADC自校准,但如果温度变化大,漂移会累积。我的做法是先做一次上电自校准,再在软件里配合长周期的零点校准(比如每次开机或者每隔一小时,采一次已知的接地通道做偏置修正)。

第四个教训:测电流时要注意共模。低压侧电流采样的运放共模范围要包含地,高压侧采样的共模要覆盖母线电压,选型错误会导致输出直接饱和到轨,读出来永远是满量程。

第五个教训:ESP32这类集成了射频的芯片,ADC在Wi-Fi或蓝牙工作时的噪声明显增大。如果项目同时需要无线通信和高精度采样,要么在通信间隙采样并加滤波,要么直接外挂一颗独立ADC,用I2C或SPI读,把模拟部分和射频部分在物理上隔开。

我个人在这些年的项目里慢慢形成一个习惯:任何用到ADC的地方,先在纸面上把量化台阶、信号幅值、采样率需求、滤波截止频率这四个数算清楚,再去画电路、写代码。别看这一步只花十分钟,它能帮你省掉后面几天的排查时间。尤其是做毕业设计或者小批量产品的时候,模拟这块地基没打好,后面堆多少软件算法都是在补救,补不回来的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询