ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

ADC技术详解:从采样原理到嵌入式工程实践

ADC技术详解:从采样原理到嵌入式工程实践 拿一块真实的硬件来说很多做嵌入式的人第一次接触“数字化仪”这个词是在示波器或者数据采集卡的说明书上。其实拆开来看数字化仪干的事情就一件把连续变化的模拟电压按固定节奏“拍照”转成一串计算机能处理的数字。这个“拍照”的核心器件就是ADC模数转换器Analog-to-Digital Converter。这篇文章我想从ADC的技术原理讲到工程落地覆盖采样定理、量化噪声、时钟抖动、电源噪声、PCB布局、嵌入式驱动、校准方法、滤波处理这些实操中躲不开的点。内容适合正在做传感器采集、电源监测、电机控制、音频处理、仪器仪表开发的工程师也适合刚入门想系统了解ADC的同学。我会用实际开发中的视角来讲尽量把每个“为什么这么做”都说透而不是单纯堆概念。1. 数字化仪的完整链路ADC只是其中一环1.1 一条典型的模拟信号数字化链路很多人以为数字化仪就是一颗ADC芯片这个理解其实窄了。真实系统里从物理世界的模拟信号到CPU能读的数字量中间至少经过五个环节传感器/信号源把物理量变成电压或电流比如热电阻、压力桥、光电二极管。信号调理包括放大、衰减、电平移位、滤波目的是把信号幅度和阻抗调整到ADC的输入范围内。抗混叠滤波通常是低通滤波器滤掉高于采样率一半的频率成分防止混叠。ADC转换核心的模拟到数字转换过程。数据接口与处理SPI/I2C/并行接口把数据送进MCU/DSP/FPGA再做校准、滤波、换算。我在实际项目里踩过最深的一个坑就是只盯着ADC芯片参数挑型号却忽略了信号调理链路。ADC的输入等效阻抗不是无限大尤其是SAR型ADC采样瞬间会从信号源抽取一个电流脉冲。如果前级用的是高阻输出比如有些运放直接驱动或者分压电阻值偏大建立时间不够采出来的值就会偏低且不稳定。这个问题后面细讲。1.2 选对ADC架构才能不翻车ADC架构选择直接决定系统能不能满足性能要求。市面上常见的架构大概有这几种架构分辨率范围采样率范围典型应用SAR逐次逼近型8~18位几kSPS到几MSPSMCU内置ADC、工业采集、电机控制Σ-Δ过采样型16~24位几SPS到几MSPS高精度称重、音频、温度测量流水线型8~16位几十MSPS到几百MSPS示波器、通信中频、视频采集折叠内插型6~8位上GSPS超高速雷达、宽带示波器前端双积分型12~20位极低采样率万用表、精密计量SAR架构是MCU系统里最常碰到的原理可以类比成“用天平称重量”从最高位开始拿一个已知的电压和输入电压比大小大了就放弃这一位小了就保留逐位逼近。N位ADC需要N个比较周期所以转换时间和时钟频率强相关。这类ADC的优势是功耗低、采集速度快、延迟小适合中等精度场合但通常需要前端驱动电路有足够带宽和驱动能力。Σ-Δ架构则是另一种思路。它用极高的采样率对输入信号反复采样再通过数字滤波把带外噪声滤掉利用噪声整形把量化噪声推到高频段换取样较低的实际输出速率下非常高的有效分辨率。这颗器件适合做高精度但低速的测量比如称重传感器、热电偶冷端补偿、电池电量监测。如果你在低速高精度场景用了SAR可能测得抖成狗反过来在高速场合用了Σ-Δ又会发现输出数据率跟不上控制环路节奏。选型时我一般先明确三个指标信号最高频率、需要的有效位数、系统能接受的转换延迟。把这三个定下来架构基本就锁定了。再去看具体芯片的INL/DNL、温漂、输入阻抗这些细节才不会在选型阶段就被参数表带偏。2. ADC采样原理拆解采样定理与量化噪声2.1 采样周期怎么定奈奎斯特只是底线ADC采样周期这个概念直接决定了你能看到多快的信号。奈奎斯特采样定理说的是为了避免混叠采样率至少要是信号最高频率的两倍。工程上没人卡这个底线一般取5~10倍甚至更高。原因很简单理论上的“两倍”要求信号严格带限而且需要理想滤波器现实世界做不到。以音频为例人耳能听到20kHzCD标准用44.1kHz采样留了大约10%的过渡带余量再配合陡峭的抗混叠滤波器。而在电机电流采样这类场合如果你关心的是几十kHz的开关纹波那采样率至少得放到200kSPS以上否则你看到的“纹波”其实是混叠出来的假频率完全不可信。采样周期的另一个众生平等问题是ADC建立时间acquisition time。SAR ADC内部有一个采样保持电容采样开关闭合后外部信号源要通过源阻抗给这个电容充电。如果充电时间不够电容上的电压还没稳定到输入电压的精度范围内就断开了转换结果自然有误差。计算时可以参考RC充电模型建立时间 t k × (R_source R_switch) × C_samplek取决于你要达到的精度。12位精度下误差要小于1/4096 LSBk大约取8~916位精度则要到11以上。如果信号源阻抗很高比如100kΩ分压后的信号直接进ADC而内部采样电容是10pF、开关电阻是2kΩ时间常数为(100k2k)×10pF ≈ 1.02μs。12位精度需要的建立时间约为9×1.02μs ≈ 9.2μs。如果MCU的ADC采样时间寄存器配成1.5个周期在36MHz时钟下单周期约27.8ns1.5周期才41.7ns远远不够读数自然偏低。解决办法要么把ADC采样时间配成最大要么在ADC输入端加一个运放做低阻抗驱动或者至少加一个电容做电荷池让采样开关从电容上而不是直接从高阻信号源取电。2.2 量化噪声、信噪比与有效位数的本质ADC的量化过程其实是个取整操作。模拟电压落在两个相邻量化电平之间ADC只能输出其中最近的那个数字码。这个误差就是量化噪声它在±0.5LSB之间均匀分布。理想N位ADC的量化噪声功率为q²/12其中q 满量程电压 / 2^N由此可以推导出理想信噪比公式SNR 6.02 × N 1.76 dB这个公式做ADC的人应该都眼熟。12位ADC理想SNR是74dB16位是98dB。但注意这是“理想”值实际芯片往往只能做到接近这个数值因为还存在热噪声、时钟抖动、参考电压噪声、INL/DNL非线性误差。实际系统中我们更关心ENOB有效位数也就是考虑所有噪声和非线性后ADC实际能提供的位数。计算方式是把实测SNR或者SINAD含失真代入反推ENOB (SINAD - 1.76) / 6.02如果一颗16位ADC实测SINAD只有80dB那ENOB大约就是(80-1.76)/6.02 ≈ 13位。也就是说你花钱买了16位芯片但因为系统设计不给力实际只得到了13位的有效精度。这种情况下与其纠结是不是换了24位芯片就能提升不如先查查电源纹波、参考噪声和PCB布局往往改善更大。2.3 时钟抖动与电源噪声两个容易埋雷的地方时钟抖动对ADC的影响经常被低估。理论上ADC在每个采样时钟边沿采集输入如果时钟沿出现随机时间偏移那么采到的电压就与理想时刻有偏差。输入信号变化越快同样时钟抖动造成的电压误差越大。高频信号搭配大抖动是采样系统的隐形杀手。量化的影响可以通过下面公式估算时钟抖动引入的SNR上限SNR_jitter -20 × log10(2 × π × f_in × t_jitter)假设输入信号频率为10MHz时钟随机抖动为10ps这个指标已经算不错了那么算出来的SNR上限大约为-20 × log10(2 × 3.1416 × 10e6 × 10e-12) -20 × log10(6.28e-4) ≈ 64dB也就是说即使ADC本身是14位、16位只要前端时钟抖成这样系统有效精度就卡在64dB这个水平约合10.4位。所以做高速采集系统时时钟源的抖动往往比ADC分辨率更先成为瓶颈。低速MCU内置ADC一般对时钟抖动没那么敏感但如果你用PLL倍频出来的高频时钟驱动SAR ADC做精密采样也要留意抖动指标。电源噪声同样是ADC性能杀手。ADC内部有比较器和采样开关电源上的毛刺会通过寄生电容耦合到信号路径直接影响转换结果。参考电压VREF更是直接参与转换比例参考上的纹波会原样出现在输出码里。实际操作中我习惯在模拟电源和参考电压引脚前加一级RC滤波比如10Ω串联加1μF/0.1μF并联电容把高频分量压下去。数字电源和模拟电源尽量分开走数字地和模拟地在ADC处单点汇合避免数字开关噪声串到模拟区域。2.4 ADC/DAC电路设计规避时钟抖动与电源噪声的3个PCB布局要点PCB布局这块我总结了自己常用的三条硬规则。第一模拟信号路径要短而直。ADC输入引脚到前级运放输出之间的距离尽量控制在10mm以内中间不要打过孔跳来跳去。信号路径越长寄生电感和天线效应越明显越容易吸收环境噪声。第二采样时钟和数字信号远离模拟信号。时钟线、SPI数据线、PWM输出线这种快速翻转的信号不要和模拟输入走线平行甚至扎堆贴着走。我在一个项目里就遇到过SPI时钟线从ADC输入下方穿过结果每次SPI通信时采集值都有规律性跳变。后来把时钟线改到另一层并用地线隔离问题立刻消失。第三电源和参考引脚必须有完备的去耦网络。每个模拟电源引脚放一个0.1μF高频去耦电容紧贴引脚放置再接一个1μF~10μF的体电容。参考电压引脚至少并联一个10μF钽电容和一个0.1μF陶瓷电容电容与参考引脚之间的回路越小越好。如果用了外部基准芯片基准输出到ADC参考引脚这段走线要粗且短最好加RC滤波。注意去耦电容不是随便焊上去就完事。电容的谐振频率要和目标滤除的噪声频率匹配。0.1μF陶瓷电容的谐振频率大约在几十MHz到上百MHz适合滤数字开关噪声大容量电解或钽电容滤低频纹波更有效。所以大小电容搭配使用不是玄学是物理规律。3. 嵌入式实战从ADC配置到稳定出数的完整路径3.1 MCU内置ADC的基本驱动流程以STM32系列为例用CubeMX配置ADC看起来简单打开ADC1、选通道、设采样时间、开中断或者DMA生成代码。但很多问题恰恰出在“简单”二字上。配置ADC前有几个容易被忽略的环节GPIO要设置成模拟输入模式。很多人习惯用默认的输入模式结果引脚内部的上拉或者斯密特触发器把信号拉偏了采样值不准。改成模拟输入后GPIO内部的上拉、下拉和斯密特触发器才会被禁用引脚呈高阻状态。采样时间宁可长不要短。如果信号源阻抗不低或者你对采样精度没有绝对把握直接把采样时间配置到最大。牺牲一点采样率换稳定可靠的数据完全值得。时钟源选择和分频系数要算清楚。ADC时钟太高会影响线性度STM32F1系列一般建议ADC时钟不超过14MHzF4系列可以到36MHz但不建议顶格跑留点余量给性能和功耗的平衡。DMA传输是批量采集的神器。多通道、连续采样场景下用DMA把ADC数据搬进内存CPU就可以去干别的事。配置时要注意两点数据数位宽度要和ADC分辨率匹配比如12位ADC数据寄存器是16位DMA的每个数据单元宽度要设成HalfWordDMA缓冲区的长度要和通道数/采样次数对应否则会出现数据错位。3.2 四通道DMA采集中容易踩的坑与配置要点多通道采集最典型的场景是同时采集多路电压。我推荐的做法是扫描模式连续转换DMA循环模式。原理上ADC按照规则序列依次转换通道0、1、2、3每次转换完触发一次DMA请求DMA把结果按顺序搬到数组里buff[0]CH0, buff[1]CH1...一轮结束再来一轮。这里有个极其隐蔽的坑如果你同时开启了连续转换和DMA循环模式而且DMA中断里做数据处理时没注意同步很容易读到“新旧混搭”的数据。比如通道0已经进入第二轮转换通道3还是上一轮的数据刚好你又在这时刻处理完一轮数据那整帧数据其实是错位的。解决办法是使用DMA传输完成中断在每轮数据传输完成后统一处理整批数组而不是随时取数组里的值。同时如果各通道数据间存在因果关系比如三相电流采样更稳妥的做法是用定时器触发ADC转换保证所有通道的采样时刻相对确定。3.3 校准处理ADC数据漂移的关键一步ADC数据漂移是很多人头痛的问题。表现为同一电压早上测和下午测差几个LSB或者温度一变化读数就飘。这个现象主要来源有两个ADC本身的增益误差和偏移误差以及参考电压随温度漂移。内部校准不少品牌的MCU内部自带校准功能。比如STM32的ADC有自动校准CAL流程上电后执行一次校准ADC会自动把内部偏移消除掉。GD32、NXP的S32K系列也有类似机制。但这里有个细节值得注意有些芯片的校准值比如offset trim在默认状态下并未自动应用到结果寄存器需要软件读取校准值后写入指定寄存器才生效。网上有人问“CLA读取ADC结果寄存器时读到的是尚未应用offset trim的原始值”这个就是典型的没有做校准值应用的操作。外部校准更通用、更可控的方法是做外部电压三点校准。思路是给ADC输入三个已知的精确电压记下对应的原始码值然后用最小二乘法拟合出线性关系Y a × X b其中Y是真实电压X是ADC原始码。高精度场景下单点或两点校准无法处理的非线性问题三点校准可以覆盖更多信息。分段线性校准则更进一步把量程分成若干段每段单独做两点或三点拟合适合INL较大的ADC。移位寄存器的处理同样值得留意校准参数要保存在非易失存储中因为每次上电后ADC的偏移误差可能略有不同。最好在设备出厂时做一次标定把校准系数烧录进去产品运行时再加载使用。3.4 C语言ADC值滤波函数从滑动平均到一阶低通ADC采回来的原始数据几乎不会像想象的那么干净。即使电路设计再到位传感器本身的噪声、工频干扰、微小振动都会叠加在信号上。下面分享几个我常用且好写的滤波算法。滑动平均滤波适用于削除随机噪声。窗口大小N取4、8、16等2的幂次方便用移位替代除法#define FILTER_N 16 static uint16_t buf[FILTER_N]; static uint8_t idx 0; static uint32_t sum 0; uint16_t slide_filter(uint16_t new_val) { sum - buf[idx]; sum new_val; buf[idx] new_val; idx (idx 1) % FILTER_N; return sum / FILTER_N; }这个实现把旧值减掉、新值加上再除以窗口长度。寄存器存储时注意buf数组要是static保证数据持续累积。N取16时除法可以写成sum 4省掉浮点和除法指令在资源紧张的MCU上很实用。一阶低通滤波也叫指数加权平均适合有真实变化趋势的信号比如NTC温度、电池电压缓慢变化uint16_t lowpass_filter(uint16_t new_val, uint16_t last_val, uint8_t alpha) { return (uint16_t)((alpha * new_val (256 - alpha) * last_val) 8); }alpha取值在0~256之间alpha越大对新值的权重越大响应越快但噪声抑制变差。alpha 16时滤波后信号对应的时间常数大约是 1/(2×π×fc)你可以按实际信号频率调。中位值平均滤波是滑动平均的升级版适合有明显脉冲干扰的场景。做法是先取N个值排序去掉最大最小剩下的做平均。缺点是需要额外内存和时间但剔除尖峰的能力确实好。我在电机电流采样里试过配合DMA批量采集后效果很明显。提醒一句滤波永远是“最后的补丁”而不是“设计的第一选择”。如果滤波窗口大到系统响应跟不上的程度优先回头检查硬件设计和PCB布局而不是继续加大滤波强度。4. 进阶玩法一路ADC识别多按键与电压监测电路4.1 ADC按键一个引脚搞定一排按键MCU的引脚资源紧张时ADC按键方案很常见。原理很简单每个按键串联不同的分压电阻按下不同按键时ADC引脚上得到的电压不一样。MCU通过判断电压落在哪个区间来识别按键。电路上一个上拉/下拉电阻接到VCC或GND每个按键串联一个独立电阻到ADC引脚。例如用1kΩ、3kΩ、7kΩ做分压对应三个键按下时得到不同的电压。设计时注意两点一是每个按键的电压区间要分开足够大不能靠得太近否则电阻误差和电源波动一叠加就分不清了二是要防抖动机械按键按下瞬间有抖动电压会跳变几次软件上需要做20ms~50ms的去抖窗口。ADC键盘的另一个好处是省IO适合矩阵键盘排不下的面板精简设计。缺点是一旦某一个分压电阻阻值偏移超过设计裕量按键识别的可靠性就会下降所以电阻精度建议用1%并且预留校准程序。4.2 BMC通过ADC读取电压的过程服务器主板上BMC带外管理控制器读取各种电源电压用的就是ADC只是链路比想象的稍长。典型框图是被监测电源 → 分压电阻 → 运放跟随/放大 → 多通道ADC → I2C/SMBus接口 → BMC寄存器 → 上层管理软件。分压电阻的作用是把高电压比如12V、5V降到ADC量程内比如3.3V。BMC的ADC输入量程通常在0~1.8V或0~3.3V所以分压比要算准。例如12V想要降到1V可以选择1kΩ和11kΩ分压12×(1/(111)) 1V。但这里有个坑分压电阻的阻抗如果太高ADC采样瞬间的电流抽取会导致电压跌落读数偏低。做法是分压后加一级跟随器比如LM358、OP07这类通用运放用运放的输出去驱动ADC输入隔离信号源阻抗和采样电容之间的抽载问题。软件读取方面BMC通过SMBus/I2C访问ADC芯片的寄存器读取当前通道的转换结果。ADC芯片地址、寄存器地址、数据格式都带在数据手册里。如果从寄存器读出来的原始值和万用表实测电压对不上先查数据手册里的LSB含义。很多ADC芯片的换算公式是例程里写好的比如12位ADC、参考电压2.5V那么LSB 2.5/4096 ≈ 0.610mV实际电压 ADC码 × 0.610mV再乘回分压比还原到原始电压。5. 常见问题与排查技巧实录5.1 几个高频故障的真实排查过程采样值明显偏低且不稳定。这种情况十有八九是信号源阻抗太高、ADC采样时间不够导致的建立时间不足。我用过的最有效排查方法是把一个已知低阻信号源比如直接短接VCC或GND输入ADC如果读数正常再换上高阻信号源问题就暴露出来了。实际项目里最终方案是在信号源和ADC之间加一级运放跟随并同时延长ADC采样时间问题彻底解决。ADC数据和DMA错位。GD32E230上遇到过一次四个通道的数据轮流乱跳查了一圈发现DMA缓冲长度配成了字节数而不是半字数。ADC的结果寄存器是16位的DMA搬运时数据宽度必须配成HalfWord而缓冲区长度是2×通道数。这种“数据紊乱”基本都是配置不一致不是硬件问题。ADC读数随系统负载漂移。一个电源管理项目的现象是电机转起来后ADC读数就飘。查示波器发现模拟电源和数字电源没有完全隔离电机驱动器的大电流开关噪声通过公共地阻抗耦合到了模拟部位。解决方式是把模拟地单独走线并在电源入口处加磁珠和电容隔离数字和模拟部分只在主电源入口处单点相连接地问题解决。参考电压波动导致测量比例失调。有个做称重方案的朋友用MCU内部参考电压结果发现温度一变测量值就变。根源是内部参考电压温漂系数较大。后来换了外部精密基准比如2.5V基准芯片温漂从几十ppm降到几个ppm问题解决。这个案例说明高精度场景内部参考要谨慎使用。5.2 常见问题速查表现象可能原因检查方向读数明显偏低采样时间不够、输入阻抗过高加大采样时间、加运放跟随读数无规律跳变数字信号干扰、电源噪声检查PCB布局、走线分隔、去耦多通道数据错位DMA宽度/长度配置错误、触发时机不对确认数据单元宽度、帧同步温漂严重参考电压温漂、ADC偏移未校准换外部基准、做温度补偿校准快速信号失真采样率不足、抗混叠滤波缺失提高采样率、增加前级低通滤波注入通道读取时机不对注入通道转换的触发条件没配好查看ADC状态寄存器、准备就绪再读时钟抖动导致高频段SNR差采样时钟抖动过大换低抖动晶振/时钟源ADC的采样时刻点设置也有一些讲究。如果用了PWM中心对齐模式配合定时器触发ADC采样的时间点最好落在PWM波形的中间平顶区域避开开关边沿附近的毛刺期。否则PWM开关管的瞬间电压尖峰会直接影响采样结果读回来的电流/电压都带着刺。配合注入通道做同步采样时触发条件和读取时机要在代码里加状态判断防止读到尚未刷新完成的旧数据。另外一个容易被忽略的点单片机ADC输入口悬空时读取到的值是不确定的通常会飘到中间某个值什么都有可能。所以如果某个通道没用到要么初始化成模拟输入后接地要么软件上把它屏蔽掉否则会影响DMA缓冲区中其他通道的数据分析。写到这里我想起自己刚入行时为了把一颗12位ADC调出稳定数据熬了整整两个通宵。后来发现是PCB布局里一根走线绕在电感下方惹的祸。做ADC应用开发原理是基础但对具体现象的敏感度才是核心竞争力。每个“突然跳变的读数”背后都有一个可以被解释的物理过程。把原理吃透加上在示波器前多看多测很多疑难问题自然就有了答案。
返回列表