
1. 先搞明白ADC到底是什么为什么嵌入式工程师天天跟它打交道做嵌入式或者硬件开发的朋友肯定绕不过 ADC 这三个字母。ADC 全称 Analog-to-Digital Converter中文叫模数转换器作用就是把连续变化的模拟电压信号转换成单片机或者处理器能直接处理的数字量。温度传感器输出的是一个随温度变化的电压、电位器转动改变分压值、电流采样电阻两端产生压降、麦克风捕捉到的声波振动……这些真实的物理量最终都要经 ADC 变成一串数字才能被程序逻辑判断、被算法计算、被屏幕显示或者被上传到云端。老实说ADC 是模拟世界和数字世界之间唯一的桥梁。没有 ADC单片机再聪明也感知不到外部环境没有 ADC你写的 PID 控制、FFT 频谱分析、电池电量监测全都是空谈。所以不管是刚入门玩 STM32 的新手还是做工业采集、电源控制的老手把 ADC 的定义、工作原理、工作模式和基本参数吃透都是值得的。这篇文章我就按“定义→原理→模式→参数→实战坑点”这条线把 ADC 从头到尾拆开讲一遍尽量用大白话加实际工程经验让你看完就能上手用用完还能跟别人讲明白。这篇文章适合谁看呢第一类是刚接触单片机的学生或转行者第二类是做传感器采集、电源管理、电机控制、音频处理的嵌入式工程师第三类是偶尔要选型 ADC 芯片的硬件工程师。哪怕你现在只用过 Arduino 的 analogRead也能在这篇文章里补上很多之前没搞清楚的底层细节。2. ADC 的核心工作原理采样、保持、量化、编码四步走2.1 采样和保持为什么不能直接“读”电压要理解 ADC 的工作原理别一上来就背那些转换架构的名字先搞清楚 ADC 在时间轴上做了什么。ADC 不可能像电压表那样持续盯着输入电压看它只能在一个瞬间“抓拍”电压值然后再花时间去把这个值转换成数字。所以第一步是采样也就是在某个时刻把输入电压的瞬时值取进来。但问题来了——ADC 内部的比较器或者电容阵列需要一个稳定电压来完成转换如果输入信号一直在变转换结果就会不准。所以 ADC 前端通常会有一个采样保持电路 S/H核心就是一组开关加一个电容。开关闭合时电容快速充电到当前输入电压开关断开后电容把电压“保持”住给后级转换电路足够的时间慢慢处理。这个过程你可以理解成拍照快门一按画面就定格在那一瞬间之后的事情跟原场景无关了。这里有个很关键的概念叫采样时间。采样时间太短电容还没充到输入电压的实际值转换结果就会偏小采样时间太长在低频信号上问题不大但采集高频信号时可能会丢失快速变化的细节。所以你会发现 STM32 的 ADC 配置里有个 SMP 位就是用来调节采样时间的你没调过的话默认值往往不一定适合你的源阻抗场景。源阻抗大的时候比如高阻传感器直接接 ADC 引脚必须把采样时间调长否则误差会让你怀疑人生。2.2 量化与编码从连续电压到有限数字的精度代价采样保持之后ADC 拿到的是一个“定格”的模拟电压接下来要把它变成数字。这个环节叫量化。量化是什么意思呢一个 12 位 ADC 能表达的数字范围是 0~4095它要把参考电压比如 0~3.3V切分成 4096 个等份每份大小为 3.3V / 4096 ≈ 0.806mV。输入电压落在哪个区间就输出对应的数字量。听起来很简单但量化天生就会引入误差叫作量化误差。比如你测到的电压是 1.0004V但 12 位 ADC 在这个参考电压下能表示的最小单位是 0.806mV那 1.0004V 落到 1241 个 LSB 和 1242 个 LSB 之间的某个位置最终会被四舍五入到其中一个值。误差最大就是 ±0.5 LSB这是原理上不可避免的再高级的 ADC 也逃不掉。实际工程项目中你得知道这个误差是地板任何宣称“零误差”的 ADC 都是在耍流氓。然后就是编码。绝大多数 ADC 输出的是二进制补码或者二进制原码直接映射到 0 到 2^N-1 的整数。STM32 的常规 ADC 就是 0~409512 位超过参考电压就钳位低于 0 就输出 0。编码这一步不需要你关心底层逻辑但你得知道单片机寄存器里读出来的原始值只是一个“映射”要换算成真实电压公式是电压 原始值 × 参考电压 / 4096。很多新手拿到原始值直接就当电压用数据全是错的还没意识到问题出在换算上。2.3 主流 ADC 架构对比SAR 是主角Σ-Δ 是高精度王者ADC 的内部实现方式有很多种工程中最常见的三种逐次逼近型SAR ADC、Δ-Σ 型Sigma-Delta ADC、以及流水线型Pipeline ADC。这里篇幅有限我重点讲前两种因为单片机和工业采集场景里 90% 都在用它们。逐次逼近型 ADC 的原理可以类比“猜数字”游戏先用最高位试猜比较器判断输入电压比猜测值大还是小根据结果锁定最高位再接着猜下一位。猜完 12 位就用 12 次比较把输入电压逼近到足够精确的程度。SAR ADC 的优点是转换速度非常快、功耗低、不需要外部保持电路内部自带所以 STM32、GD32 这类 MCU 内部集成的基本都是 SAR ADC。缺点是高分辨率下比如 16 位以上内部电容阵列匹配精度做不高且对输入信号噪声敏感。Δ-Σ ADC 的思路完全不同它不追求每次转换“一步到位”而是用极低的精度、极高的采样率对输入信号反复采样再用数字滤波把噪声整形出去最终换取超高的有效位数。打个比方SAR 是拿一把普通尺子量一次误差就定了Δ-Σ 是拿同一把尺子量一千次取平均值把随机误差削掉一大截。所以 24 位高精度 ADC 芯片比如 ADS1256、HX711基本都是 Δ-Σ 架构。代价是转换速度慢、延迟高适合称重、温度、压力等慢变信号不适合音频或高频振动采集。选型的时候一定要想清楚你的信号变化有多快。要是拿 Δ-Σ 去做电机相电流高频采集结果就是带宽不够相位延迟大到控制环根本稳不住。流水线型 ADC 主要出现在高速数据采集、射频直采、示波器前端这些场景比如几十 MSPS 甚至 GSPS 级别的采样率多级级联把速度拉满。普通 MCU 开发者基本不太接触知道它“快且贵”就够了。2.4 参考电压 Vref 为什么决定了你的测量精度很多人调 ADC 只盯着分辨率看把参考电压当成一个“随便配个 3.3V 就行”的角色。实际上参考电压是整个 ADC 转换精度的“标尺”。ADC 输出的数字量本质上是输入电压与参考电压的比值。Vref 抖动 10mV你的测量结果就跟着漂 10mV不管你用的是 12 位还是 24 位 ADC都救不回来。所以外部 Vref 引脚最好接一个低噪声、低温漂的基准源芯片比如 REF3030而不是直接把 MCU 的 VDD 拉过去。尤其是在电池供电的设备里电池电压从 4.2V 掉到 3.4V你要是把电池电压当 Vref那你采出来的数据全程都在“移动标尺”后期数据处理再花哨也没用。另外要注意 Vref 的输入阻抗不是无穷大ADC 内部的采样电容充电瞬间会从 Vref 抽取电流。如果 Vref 由高阻分压电阻提供动态响应跟不上就会出现“重负载时 ADC 读数偏低”的怪现象这在工业采集板上很常见。要嘛加个运放缓冲要嘛在 Vref 引脚旁边放一个 1μF 到 10μF 的储能电容就近放电。3. ADC 的几种工作模式单次、连续、扫描、注入各有各的用途3.1 单次转换模式和连续转换模式别用错场合ADC 的工作模式是很多人一开始看参考手册就懵的地方。先说最简单的两种——单次转换模式和连续转换模式。单次转换模式触发一次转换完成一次转换结果存到数据寄存器然后停在那里。适合低频轮询的场合比如你每秒读一次温度读完成就休眠省电又省事。连续转换模式就是 ADC 启动之后自己不停地采、不停地把数据寄存器刷新适合需要实时监测的信号比如直流母线电压、电机电流环反馈。注意了连续模式下 CPU 如果没及时读走数据寄存器数据就会被下一次转换结果覆盖你读到的可能是“最新但不完整”的数据。所以连续模式也不是随便开的要配合 DMA 中断来搬运。我见过不少新手直接在 while 主循环里调用一次 ADC 转换函数然后写了个延时接着再读一次这样其实是在“单次触发”里模拟连续采样CPU 被白白占了。更好的做法是配置成定时器触发DMA 自动搬运数据攒一批再处理既省 CPU 又能保证等间隔采样。3.2 扫描模式、注入模式多通道采集的两种思路如果你要采集多个通道扫描模式就派上用场了。扫描模式可以按照配置好的通道顺序依次完成所有通道的转换。配合连续模式它就是“不停地从第一通道扫到最后一通道再回到第一通道”。扫描模式最大的价值是能保证多通道数据在时间上尽量连续适合传感器阵列轮询。注入模式就比较特殊了它能“插队”。想象一下你正在用扫描模式按顺序采集八个通道突发事件要求立刻采集通道 3 的信号如果等扫描结束再处理可能就错过瞬间尖峰了。注入模式就是专门干这个的——它可以抢占当前转换优先完成注入通道组的转换完事之后再回到原来的扫描流程。这在故障保护、快速过流检测场景非常有用比如用 ADC 监测电机电流一旦发现过流必须马上锁定电流值做保护动作普通扫描模式是来不及的。3.3 定时器触发与 DMA高性能采样的黄金组合说 ADC 采样不能绕开两个高频搭档定时器触发和 DMA。定时器触发就是 ADC 的“节拍器”——由定时器产生一个固定频率的触发信号ADC 严格跟随这个频率启动转换。这样做的好处太明显了采样间隔是硬件级的精确不像“whileC 代码延时”那样受中断和编译器优化干扰。需要等间隔采样做 FFT 的时候一定要用定时器触发。DMA 的作用就更不用吹了。ADC 每次转换完触发 DMA把结果自动搬运到内存缓冲区CPU 全程不需要参与。只要缓冲区够大你可以攒满 1024 个点之后再一次性处理CPU 开销几乎为零。STM32G474 这类带高精度 ADC 的 MCU配 DMA 就能轻松跑几十 KHz 的连续采样还留出充足算力跑算法。这里分享一个我自己的配置习惯先用定时器触发 ADC 单次转换DMA 传输完成中断里置标志位主循环只在标志位置位后才去处理新数据。这样不会在中断里做耗时操作也不会因为频繁进出中断而丢数据。如果你用的是 CubeIDE 的图形化配置界面记得把 DMA 模式设成 Circular否则缓冲区满了之后 DMA 会停止搬运数据就断了。4. 基本参数逐个说透分辨率、采样率、信噪比、INL/DNL4.1 分辨率与 LSB分辨率高不等于精度高分辨率就是 ADC 输出的位数常见的有 8 位、10 位、12 位、16 位、24 位。它决定了 ADC 能区分的最小电压变化也就是 1 LSB 对应的电压值。计算公式很直白LSB Vref / 2^N。比如 Vref 3.3V12 位 ADC 的 LSB 就是 3.3 / 4096 ≈ 0.806mV。但千万记住分辨率是理论上的最小步进不代表实际精度。一个 16 位 ADC 如果参考电压噪声是 10mV那低几位其实全是噪声在跳动有效位数可能连 12 位都不到。工程上衡量“实际有多准”要看有效位数ENOB而不是位数。选 ADC 的时候优先看 ENOB尤其是对弱信号采集场景来说出厂标称 24 位实际有效位数做到 20 位已经算很优秀了。4.2 采样率与奈奎斯特定理别让信号混叠骗了你采样率或叫采样速率指 ADC 每秒能完成的转换次数单位是 SPS 或 Hz。最低采样率的底线是由奈奎斯特定理决定的采样率必须大于信号最高频率的两倍否则会发生混叠也就是说高频信号会伪装成低频信号进入你的数据里而且一旦混叠发生后期怎么滤波都滤不掉。实际项目里建议采样率至少是信号最高频率的 5 到 10 倍。比如你要采集 1kHz 的音频信号采样率设成 8kHz 都偏紧张设成 16kHz 或 32kHz 才能留出足够的抗混叠滤波余量。很多初学者只看“最高频率的两倍”这个下限结果采出来的波形形态怪怪的其实是混叠在捣鬼。除了提高采样率硬件上还应该在 ADC 输入端加一个抗混叠低通滤波器把高于 0.5 倍采样率的成分提前干掉。4.3 信噪比 SNR 与 ENOB评估 ADC 实际性能的硬指标SNR 是信号功率与噪声功率之比单位是 dB。理论上一只理想的 N 位 ADCSNR 约为 6.02N 1.76dB。这个公式可以带你快速反推如果一个 ADC 标称 16 位但实际测出来的 SNR 只有 80dB那它的有效位数 ENOB (80 - 1.76) / 6.02 ≈ 13 位。差距就是内部噪声、失真、时钟抖动等因素吃掉的。评估 ADC 真实水平一定得看 ENOB 和 SINAD信号与噪声失真比类似“满桶水晃荡”的道理——纸面精度再高桶沿是歪的也装不满。别只看宣传页上“24-bit ADC”几个大字得看它在你的采样率下还能剩多少有效位。4.4 INL 和 DNL线性度才是保证精度的隐形功臣INL积分非线性度和 DNL微分非线性度是两个容易被忽略、但在精密测量场景中极其重要的参数。INL 表示 ADC 实际传输特性曲线偏离理想直线的最大误差单位是 LSB。如果 INL 差你测出来的电压在高段和低段会出现系统性偏差而且不是简单的比例关系后期校准很难覆盖。DNL 表示相邻两个数字码对应的实际电压间隔与理想 LSB 的偏差。如果 DNL 小于 -1 LSB就意味着有的码会“缺失”也就是某些数字值永远不会出现这在闭环控制里会导致输出跳动或者失控。虽然 MCU 内置 ADC 的 DNL 通常没有外部独立 ADC 那么漂亮但对于一般的电压监测、温度采集已经够用了。只有在做高精度称重、精密电源、医疗仪表时你才需要认真比较候选芯片的 INL/DNL 数据手册曲线。4.5 转换时间与采样周期被忽略的实时性瓶颈转换时间和采样周期经常被混在一起说。转换时间是采样保持完成之后、真正把模拟值变成数字值的时间而一个完整的采样周期 采样时间 转换时间。STM32 的 ADC 允许你配置不同的采样时间比如 1.5、7.5、28.5、71.5……个 ADC 时钟周期。有些人为了追求高采样率把采样时间调到最短结果源阻抗一大了读数就偏低。这是因为采样电容没有足够时间充满电。我在做工业变送器的时候吃过这个亏传感器输出阻抗有十几 KΩ我把 STM32 的 ADC 采样时间设成 1.5 周期读出来的电压比万用表低了差不多 30mV。后来把采样时间调到 71.5 周期数据马上正常。所以如果你的信号源是高阻输出优先保采样时间不要盲目追求时钟频率。5. 实操中的坑与排查技巧从采样电路设计到软件滤波5.1 输入阻抗匹配为什么示波器测得好好的ADC 一接就飘ADC 输入端不是理想的高阻原因就是前面讲的采样电容。采样开关打开瞬间电容要从信号源“偷”走一部分电荷如果信号源阻抗高电容充不满电压就会被拉低。你在示波器上量信号源两端是准的但接到 ADC 引脚后读数就偏了大概率就是这个原因。解决办法很直接在 ADC 输入端加一级运放跟随器做缓冲。运放输入阻抗是兆欧级别输出阻抗几乎为零无论后面 ADC 怎么“抽取”电流信号源都感知不到。另一种办法是把采样时间调长给电容更充裕的充电时间但治标不治本。还有一种情况是信号源本身带宽很低比如热电偶你可以在 ADC 引脚和地之间加一个 100nF 电容既能滤掉高频噪声又能为采样电容提供瞬态电荷实测改善非常明显。5.2 抗混叠滤波器与 RC 参数选择前面已经提到混叠问题这里说说具体怎么选 RC 低通滤波器的参数。假设你的信号最高频率是 1kHz采样率是 10kHz那抗混叠滤波器的截止频率可以设在 1kHz 到 2kHz 之间。一阶 RC 低通滤波的截止频率公式是 f 1 / (2πRC)。比如选 R 1kΩ、C 100nF算出来约 1.59kHz够用。但这里有个容易忽略的点RC 滤波器本身也会增加信号源阻抗如果它后面直接接 ADC采样电容的充电时间会变慢这时候就需要把采样时间相应调大。很多人的做法是 RC 后面再加一级运放缓冲采样精度和滤波效果两手都硬。如果你不想加运放那就把 C 选大一点或者 ADC 的采样时间调长。这些小细节往往决定了你的采样数据是好是坏而不是靠代码里那个中位值平均滤波函数来补救。5.3 软件滤波策略滑动平均、中位值、一阶低通怎么选软件滤波是后处理手段不能替代硬件设计但确实能挽回不少随机噪声问题。我常用的三种滑动平均滤波适合缓慢变化的信号比如温度、压力中位值滤波适合有脉冲干扰的场景比如工业现场的静电放电一阶低通滤波y[n] α·x[n] (1-α)·y[n-1]适合实时性要求高、信号相对平滑的场合α 越小滤波越强但延迟越大。在 C 语言里实现一阶低通滤波非常简洁。α 的选择要看采样频率和想要的截止频率大概关系是 α ≈ 截止频率 / 采样频率 × 6.28简化估算然后你还要处理浮点运算或者定点数。MCU 资源紧张的时候我会用定点实现把 α 转成整数再右移缩放运算开销小很多。说句大实话再好的软件滤波也不如把 ADC 采样电路硬件设计得当你调软件滤波参数调两小时可能根源就是采样电路里少了一个滤波电容。5.4 ADC 接口的雷电防护与 ESD 处理工业现场用的设备ADC 接口很容易因为雷击感应的浪涌或者静电放电被打坏。普通 MCU 内部的 ADC 引脚虽然有一点 ESD 保护但面对工业现场的强干扰根本不够看。外部防护思路一般是串联限流电阻→TVS 管钳位→RC 滤波→运放限幅。TVS 管选工作电压略高于信号最大值、钳位电压低于 ADC 引脚绝对最大额定值的型号来阻挡浪涌电压串联电阻限制浪涌电流RC 再做高频滤波。有些设备还会在信号线上加正温度系数热敏电阻做二次过流保护跟电源输入级的处理思路类似。一个很核心的提醒即使你的信号只在室内使用也照样建议加低成本的 TVS 管和串联电阻。因为插拔探头、人体接触、附近电机启停都可能让 ADC 引脚瞬间承受超额电压而 ADC 引脚一旦烧毁整个芯片基本就废了修起来远比你加两个被动元件费事得多。6. 常用 MCU 内置 ADC 与外部 ADC 芯片的选型思路6.1 内置 ADC 够用吗从需求反推方案选内置还是外置 ADC首先别盲目跟风。如果你只需要监测电压、电流、温度精度要求 12 位以内采样率几十 KHz 就够那 STM32 内置的 ADC 完全够用。现在 STM32G4 系列甚至内置了硬件过采样和偏移校准在电机控制和数字电源里性能相当能打。内置 ADC 最大的优势是零额外 BOM 成本、布局简单、跟 MCU 通信零延迟还有 DMA 直接帮你送数据到内存性能往往被低估了。反过来说如果你要做高精度的称重、电化学检测、温度变送器这类信号幅度小、动态范围宽的场景内置 ADC 的 ENOB 和噪声指标大概率不够用。这时候外置的 24 位 Δ-Σ ADC比如 ADS1256、HX711、AD7190加独立基准源才是靠谱方案。外置 ADC 通常会带 SPI 或 I2C 接口虽然多了一点通信开销但换来的是更高的测量精度和更稳定的温漂表现。6.2 选型检查清单除了位数还要看什么我给自己总结了一套 ADC 选型检查清单每次选型都过一遍1有效位数 ENOB 而不是标称位数2参考电压支持范围以及独立参考输入3采样率余量是否满足 5 倍法则4输入阻抗和源阻抗的匹配5INL/DNL 是否满足系统误差分配6工作温度范围内的增益漂移和偏移漂移7数字接口是并行、SPI 还是 I2C与主控的配合难度8供货稳定性与价格。这些条件过完基本就锁定两三款候选再看具体的手册细节和典型应用电路去验证。有个小技巧很多独立 ADC 的数据手册会给出典型应用电路包含基准源型号、输入滤波器参数、数字隔离方案等这是最可靠的参考模板。不完全等同于“照抄就完事”但至少在原理层面帮你避开了大部分坑。7. 结尾一点实在的心得最后聊点个人体会。ADC 这个东西看起来是你往寄存器里写几个参数、等着读数据就行但实际项目里 90% 的“读数不准”问题都不是代码错了而是采样电路设计、参考电压质量、输入阻抗匹配这些底层工程细节出了岔子。我后来养成了一个习惯每次遇到 ADC 数据漂、毛刺多先拿示波器看引脚波形再量参考电压纹波最后才去查软件和寄存器配置。排查顺序对了很多问题的原因一眼就能看穿。还有一个建议在做多通道采集的初期尽量先只调试一个通道把单通道采样、换算、滤波整顺畅了再扩展到多通道和 DMA。一次把所有通道都配好再调出了问题你很难判断是通道串扰、参考电压抽载还是 DMA 配置的问题。ADC 这条路慢就是快。如果你也在调 ADC建议把这篇文章里的参数挨个对着你的芯片数据手册捋一遍然后动手配一个定时器触发DMA 的采样工程实测一下不同采样时间对高阻信号源的影响。折腾完这一轮你对 ADC 的理解会远超那些只会调用库函数的同行。