尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

嵌入式ADC全解析:从采样原理到架构选型与工程实践

嵌入式ADC全解析:从采样原理到架构选型与工程实践 很多嵌入式初学者都有个共同的困惑学了 GPIO、学了串口、学了定时器寄存器操作都熟了可一提到 ADC总觉得它就是“读一个电压值”而已。后来又做了一些实际项目才意识到 ADC 这个外设远没有想象中那么简单——模拟信号怎么变成数字信号、采样周期和转换时间到底怎么算、为什么有人做出来的采集值稳定得像直线而有人做出来的数据漂得像心电图、为什么同一个 PCB 上 ADC 精度差了十几个 LSB……这些问题如果一开始就有人讲透能省下大量调试时间。这篇文章想做的就是把 ADC 这条链路从头到尾拆开揉碎了讲一遍从模拟信号和数字信号的本质区别到 SAR、Sigma-Delta 这些常见架构的工作原理再到外设寄存器逻辑、DMA 多通道采样、PCB 布局、软件滤波和校准这些实际工程中绕不开的细节。不管你是刚入手 STM32、GD32、S32K312 这类 MCU 的新手还是已经写了几年嵌入式代码但没深究过 ADC 细节的工程师这篇文章都适合放在手边当参考。1. 先搞清楚 ADC 到底在“数”什么一条从电压到二进制数字的完整链路ADC全称 Analog-to-Digital Converter中文叫模数转换器。它在嵌入式系统里的角色就是一个“翻译官”负责把连续的电压信号翻译成 CPU 认识的 0 和 1。但真正理解 ADC不能只停在“把电压变成数字”这句话上得把模拟信号、采样、量化和编码这条完整链路拆开看。1.1 模拟信号不是“连续的电压”那么简单模拟信号的本质特征是连续。在时间和幅值两个维度上它都是连续变化的。比如一个 NTC 热敏电阻分压后输出的电压会随着温度变化平滑地上升或下降中间任何一个时刻都有对应的电压值电压值可以是任意小数——1.234567V、1.234568V 都可以。数字信号则完全不同它在时间和幅值上都是离散的。时间上只在某些特定的采样时刻有意义幅值上只能表示有限个等级。这就是为什么我们说 ADC 是一个“离散化”的过程不顾模拟信号在采样时刻之间的变化也不理睬采样时刻那些无穷多的小数电压只认有限个离散电平。这里就引出一个很多新手忽略的点模拟信号是客观存在的物理量数字信号是我们对物理量的近似描述。你永远无法用数字系统完整保存一个模拟信号的“全部信息”ADC 能做的只是在满足一定条件下让数字表示尽可能接近原始信号或者更准确地说让你关心的信息不丢失。这个“条件”就是我们后面要讲的采样定理。1.2 从采样到编码一次 ADC 转换到底做了几件事一次完整的 ADC 转换内部经历了采样、保持、量化和编码四个阶段。采样——在某个时刻“抓住”输入的电压值。理想情况下就是瞬间完成但实际电路里采样开关有导通电阻采样电容需要充电时间所以必须保证采样时间足够长让采样电容上的电压充分逼近外部输入电压。这就是数据手册里SAMPLING TIME采样时间存在的意义。如果采样时间不足采到的电压会偏低尤其是信号源内阻大的时候误差会非常明显。保持——把采到的电压“冻结”起来在转换期间内保持不变。采样电容通常叫CSH就是干这个的。保持阶段要求电容的漏电足够小否则电荷泄漏会导致保持电压漂移。你会看到高性能 ADC 前面往往加一个运放做缓冲目的就是给采样电容提供足够低的阻抗让充电更快更准。量化——把保持的模拟电压和内部基准电压VREF进行比较看它落在哪个电压区间里。这里有个关键概念叫量化误差。对于一个 12 位 ADC输入范围 0~3.3V那么它把 3.3V 分成 4096 份每份约 0.806mV。如果真实电压是 1.0004V量化后就只能落在 1.000V 或 1.001V 的某个档位上这个“对不齐”的偏差就是量化误差理论上最大为 ±0.5 LSB。编码——把量化出来的档位编号换算成二进制数。比如 12 位 ADC 输出 0x1F4就代表电压落在第 500 个档位上对应的电压约 0.4028V。这一步在 MCU 内部由硬件自动完成你从数据寄存器里读到的就是编码后的结果。1.3 为什么分压电阻和阻抗匹配这么重要讲完四个阶段就该明白一个现实问题ADC 的“采样”环节会对你被测的电路产生影响。想象一下采样电容在采样瞬间相当于把外部信号源短路了一下如果信号源内阻很大电容充电就会很慢你可能需要分配很长的采样时间才能采准。举个例子一个 100kΩ 内阻的信号源直接接到 STM32 的 ADC 引脚上如果采样周期配置得太短采样电容还没来得及充到最终值采样就结束了读到的数值会比实际低。这在电池电量检测、电阻分压采样这类场景中特别常见——分压电阻动辄几十 kΩ不加缓冲直接进 ADC就会出现“电压读数偏低且不稳定”的怪现象。解决办法有三个方向在信号源和 ADC 之间加电压跟随器运放用低阻抗输出驱动 ADC。加一个 0.1μF 左右的电容到地利用电容的电荷储备效应减小采样瞬间的电压跌落但要注意这会形成低通滤波影响信号带宽。如果条件允许增大 ADC 的采样周期给采样电容更长的充电时间。这一节的核心就是想让你建立一个认知ADC 不是“接上去就能测准”的黑盒子它的整个工作过程牵涉到源阻抗、采样电容、充电时间和基准电压这些物理层面的东西。搞懂这条链路后面所有问题都好理解。2. SAR、积分型、Sigma-Delta 怎么选三种主流 ADC 架构的适用场景ADC 的“翻译”方法不止一种不同的内部工作机制决定了不同的性能表现和适用场景。嵌入式领域最常见的是 SAR 型高精度测量领域常见 Sigma-Delta 型积分型虽然慢但现在少见了Flash 型和流水线型更多出现在高速领域。选型之前先把它们的脾气摸清楚。2.1 SAR嵌入式 MCU 里最常见的选择也是入门第一个要搞懂的架构逐次逼近型SAR, Successive Approximation RegisterADC 的工作原理可以想象成一次“猜数字”游戏裁判心里想了一个电压值输入的模拟电压你每次报一个猜测值裁判告诉你猜大了还是猜小了你根据反馈不断调整直到猜中为止。具体过程是这样的SAR ADC 内部有一个比较器、一个逐次逼近寄存器、一个 DAC数模转换器。转换开始时寄存器先把最高位置 1DAC 把这个“猜测值”转成对应的模拟电压和输入电压比较如果输入电压比猜测值大最高位保留为 1否则清 0。接着对次高位重复同样操作。对一个 N 位 ADC这种二分法比较需要 N 次所以 SAR 转换时间正比于分辨率。12 位 ADC 一次转换大约需要 12 个比较周期加上采样时间典型转换时间在微秒量级。SAR 的优点是架构简单、功耗低、转换速度快而且没有延迟管线适合大多数 MCU 内置场景。STM32、GD32、S32K312 这类主流车规级 MCU 内部的 ADC基本都是 SAR 架构。它的缺点是精度受限于内部 DAC 和比较器的匹配程度要做到 16 位以上很难所以高精度应用一般不选 SAR。2.2 Sigma-Delta凭什么能做到高精度低成本过采样 Σ-Δ ADC 的思路和 SAR 完全不同。它跑得很快但用的是一种“噪声整形 数字滤波”的组合策略。它内部有一个积分器、一个 1 位比较器或者多位和一个 1 位 DAC。调制器以远高于奈奎斯特频率的速率对输入进行采样输出一串 0 和 1 的比特流。这串比特流里信号成分集中在低频而量化噪声被“整形”推到高频这就是噪声整形Noise Shaping。后面再跟一个数字低通滤波器把高频噪声滤掉最后输出高分辨率的结果。因为量化噪声大部分被推到高频并被滤除Σ-Δ ADC 在低频范围内能达到非常高的有效位数。工业上大量使用 24 位 Σ-Δ ADC 做称重传感器、热电偶采集、电流检测这类应用价格还不贵。它的缺点是转换速度慢而且存在明显的延迟不适合高速信号采集也不太适合做多通道高速轮询。很多 MCU 内部集成的也只是 SARSigma-Delta 通常作为外部独立芯片挂在 SPI/I2C 上。2.3 Flash、流水线和积分型知道是什么就够了Flash ADC 是速度最快的架构它用 2^N-1 个比较器并联一次比较直接输出 N 位结果。缺点是资源消耗巨大12 位 Flash ADC 需要 4095 个比较器基本不可能集成到普通 MCU 里主要用于射频基站、示波器前端这种需要 GHz 级采样率的地方。流水线型PipelineADC 则是把多个低精度级串起来每一级完成一部分位数转换整体达到高速度中等精度常用于视频采集、通信中频数字化。积分型比如双斜率 ADC如今在 MCU 里已经很少见它的核心思想是先用固定时间对输入电压积分再对基准电压反向积分通过测量反向积分时间来得到输入电压。它精度高、抗工频干扰强但转换速度极慢老式数字万用表里很常见。在实际项目里你只需要记住两句话MCU 内置就是 SAR高精度就是 Sigma-Delta其他架构了解原理即可遇到时知道怎么查手册就行。3. 数据手册背后的真实含义分辨率、采样周期、信噪比这些参数怎么用拿到一颗 ADC 芯片或 MCU打开参考手册看到一串参数12 位分辨率、最大采样率 1Msps、信噪比 71dB、采样周期可配 1.5~239.5 周期。每个字都认识但串在一起该怎么用很多人是含糊的。这一节把最重要的几个参数逐一讲清楚。3.1 分辨率决定灵敏度但精度不等于分辨率分辨率是指 ADC 输出的二进制位数。12 位 ADC 把满量程分成 4096 份16 位分成 65536 份。分辨率越高理论上对输入信号微小变化的感知就越灵敏也就是“最小可分辨电压”越小。但分辨率高不等于精度高。精度是“量得准不准”的问题分辨率是“量得细不细”的问题。一颗 16 位的 ADC如果参考电压噪声很大或者内部线性度不好实际精度可能还不如一颗精心设计的 12 位 ADC。衡量这个差距的指标叫有效位数ENOB公式是ENOB (SINAD - 1.76) / 6.02SINAD 是信纳比包含信号、噪声和失真的关系。当芯片手册标称精度时要看 ENOB 而不是看位数。有些便宜的 16 位 ADCENOB 可能只有 14 位甚至 12 位实际用起来和 12 位 ADC 没什么区别只是分辨率显得高。3.2 采样周期与转换时间一条必须自己动手算的公式这是入门最容易卡住的地方。以 STM32 为例ADC 的总转换时间公式是Tconv 采样时间 12.5 个 ADC 时钟周期其中 12.5 个周期是 SAR 比较过程固定的开销采样时间由寄存器配置。假设 ADC 时钟为 14MHz配置采样时间为 1.5 个周期总时间就是(1.5 12.5) / 14MHz ≈ 1μs这对应约 1Msps 的采样率是很多 STM32 的极限值。如果信号源内阻大需要把采样时间调长到 7.5、28.5 甚至 239.5 个周期转换速度就相应下降。注意这里采样周期说的是 ADC 时钟周期不是 CPU 主频周期。ADC 时钟往往由 PCLK2 分频得到分频系数在 RCC 配置里设置。有些人代码写完了发现 ADC 读值总是跳动排查半天发现是 ADC 时钟没配好超过了最大允许频率工作就不正常。3.3 信噪比、有效位数和最大采样率的实际意义信噪比SNR表示信号功率与噪声功率的比值单位 dB。理想 N 位 ADC 的理论 SNR 公式是 6.02N 1.76dB所以 12 位理想 SNR 是 74dB16 位是 98dB。实际器件达不到理论值芯片手册会给出典型测试条件下的实测 SNR比如 71dB说明实际有效位数大约是(71 - 1.76) / 6.02 ≈ 11.5 位最大采样率决定了你能采集的信号带宽。根据奈奎斯特采样定理采样率必须大于信号最高频率的两倍采样之后的数字序列才能无失真地还原原始信号。实际工程一般留 5~10 倍裕量。比如要采集 10kHz 的音频信号20kHz 采样率只是理论底线实际上用 100kHz 以上的采样率效果才够好。还有一点需要提醒数据手册上的最大采样率通常是“常温、理想电源、特定测试条件”下的数值产品设计时必须留足裕量。比如手册标 1Msps你要是真的按 1Msps 跑还得同时保证信号源阻抗很低、ADC 时钟完全符合要求否则精度会明显下降。工业上往往只跑 60%~80% 的标称采样率。3.4 一个容易被忽略的“采样周期”热搜误区网上有个热搜词“adc采样周期”很多新手误以为它等于 ADC 转换时间其实两者不是一回事。采样周期只是总转换时间的前半段负责给采样电容充电充电越充分后面对比结果越准确。如果你在项目里碰到“数值偏低”的问题第一反应除了检查分压电阻、电源基准还要想想是不是采样时间太短了。我遇到过一个温度采集的工程案例用一个 10kΩ NTC 和 10kΩ 电阻分压NTC 输出直接接 MCU 的 ADC采样时间配置成 1.5 个周期结果读到的温度整体偏低 3℃ 左右。原因就是 NTC 分压网络等效内阻太高采样电容充不满。后来把采样时间调到 239.5 个周期温度读数立刻正常了。这个案例让我养成了一个习惯只要信号源阻抗高于 10kΩ采样时间就不要低于 28.5 个周期。4. 作为一个外设ADC 是怎么被“用起来”的从时钟到寄存器到 DMA上面讨论的是 ADC 内部原理这一节回到嵌入式开发的日常写代码的时候ADC 这个外设到底是怎么和 MCU 的其他部分协同工作的为什么上电之后不能直接读数据为什么每个外设都要先开时钟理清楚这些你才算真正“掌握”了这个外设而不是只会照抄例程。4.1 上电后外设逻辑时钟、引脚模式、电源和参考电压缺一不可大多数 MCU 外设串口、ADC、定时器上电后不是马上就能用的。核心原因是低功耗设计如果不用的外设也一直通电工作待机电流早就超标了。所以 MCU 的电源管理架构给每个外设都设计了独立的时钟门控开关你得先在 RCC 里把 ADC 外设的时钟打开它的寄存器才能读写内部模拟电路才开始工作。以 STM32 为例ADC 的启用流程通常是这样的使能 GPIO 时钟把采样引脚配置为模拟输入模式。这一步很多人会漏直接把引脚配成浮空输入结果 ADC 读值总是在几个固定数之间跳。模拟输入模式下的施密特触发器是关闭的引脚直接连接 ADC 内部采样结构而数字输入模式的引脚结构不适合直接接模拟信号。使能 ADC 时钟设置 ADC 时钟分频系数检查 ADC 时钟频率是否在芯片允许范围内。校准。STM32 系列一般建议上电后做一次校准内部会自动计算校准因子写入 ADC 的校准寄存器。跳过校准不是不能用但初始偏移误差可能比较大。配置通道、采样时间、触发方式、对齐方式然后使能 ADC。还有电源和参考电压。ADC 的模拟部分需要独立的电源引脚如 VDDA和参考电压引脚如 VREF。在高精度场景下VDDA 和 VREF 必须经过滤波不能用数字电源直接供电。很多入门开发板直接把 VDDA 和 VCC 短接VREF 悬空低精度应用没问题但要做 16 位高精度采集就必须认真处理参考电压。4.2 多通道采样与 DMA为什么不用中断方式逐个读实际采集系统很少只采一路信号多通道轮询是常态。最容易踩坑的是“多通道时读数据乱序”问题网上经常有人搜“adc四通道使用dma”“gd32e230 adc dma数据紊乱”根源基本都在于对规则通道和注入通道的机制没有理解清楚。规则通道是 ADC 常规转换的通道序列。你可以配置一个序列比如顺序是通道 0、通道 1、通道 2、通道 3每次触发就按这个顺序依次转换。转换完成后结果放在同一个数据寄存器ADC_DR里如果不用 DMA你得在每次转换完成后立刻把数据读走否则下一次转换结果会覆盖上一次。用中断方式处理时如果中断响应不及时数据就丢了或者错位了。用 DMA 的方式一次触发后 DMA 按顺序把每次转换结果搬运到内存数组流程是配置 DMA 请求为循环模式数据宽度半字16 位匹配 12 位 ADC 输出。配置内存地址为数组首地址数组长度和转换通道数一致。使能 DMA 的循环模式这样一次 DMA 传输完成后自动重载CPU 只需要在数据处理时访问数组。多通道 DMA 出现“数据紊乱”还有一个常见原因DMA 循环模式和 ADC 的 DMA 请求信号配合不佳导致搬运顺序错位一位。解决办法之一是在 DMA 中断里判断当前缓冲区索引或者把数据长度设为通道数加 1转换完多个序列后从期望的通道开始解析。另一个有效做法是使用定时器触发 ADC 转换保证每次触发周期固定而不是用软件连续触发这样数据节奏是稳定的配合 DMA 搬运会容易得多。4.3 一个典型例程单通道电压采集加串口打印的完整思路用一个最小例程串联上面所有知识点。拿 STM32F103 为例采集 PA1 上的电压通过串口打印到终端代码如下// 假设已经初始化好串口1波特率115200 // 1. 配置ADC引脚 GPIO_InitTypeDef gpio; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE); gpio.GPIO_Pin GPIO_Pin_1; gpio.GPIO_Mode GPIO_Mode_AIN; // 模拟输入 GPIO_Init(GPIOA, gpio); // 2. 配置ADC时钟分频PCLK2 72MHz分频6 - 12MHz ADC时钟 RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 3. ADC初始化 ADC_InitTypeDef adc; adc.ADC_Mode ADC_Mode_Independent; adc.ADC_ScanConvMode DISABLE; // 单通道不使能扫描 adc.ADC_ContinuousConvMode ENABLE; // 连续转换 adc.ADC_ExternalTrigConv ADC_ExternalTrigConv_None; // 软件触发 adc.ADC_DataAlign ADC_DataAlign_Right; adc.ADC_NbrOfChannel 1; ADC_Init(ADC1, adc); // 4. 配置通道1的采样时间这里给55.5个周期适合中等阻抗信号源 ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5); // 5. 校准 ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); // 6. 使能并开始转换 ADC_Cmd(ADC1, ENABLE); ADC_SoftwareStartConvCmd(ADC1, ENABLE); while(1) { if(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)) { uint16_t val ADC_GetConversionValue(ADC1); float voltage val * 3.3f / 4096.0f; char buf[64]; sprintf(buf, ADC value: %d, voltage: %.3f V\r\n, val, voltage); uart_send_string(buf); } delay_ms(500); }这个例程里关键点都在注释里了引脚模式、ADC 时钟分频、采样时间、校准、使能顺序。很多新手把这个流程当成“八股文”背诵却不知道每一步意味着什么。等你踩过几次坑就会明白这些步骤没有一步是多余的。5. 硬件板级问题时钟抖动、电源噪声和 PCB 布局这三道坎嵌入式 ADC 项目的精度并不只由芯片参数决定。一个能跑 12 位理论精度的 ADC如果 PCB 布局不合理、电源纹波大、参考电压不干净实际做到 10 位精度都算好的。网上有一个热搜词是“adc/dac 电路设计:规避时钟抖动与电源噪声的3个pcb布局要点”这确实是很多硬件工程师反复强调的内容。这一节就讲讲板级问题。5.1 时钟抖动如何影响采样精度时钟抖动Clock Jitter指的是 ADC 采样时钟沿的微小时间波动。对于低频信号时钟抖动的影响可以忽略但采集高频信号时一个很小的时钟抖动就能导致明显的电压误差。原因很简单抖动导致采样点的时间位置不确定而在高频信号上电压变化率很大时间上差一点电压就差很多。举例来说采集一个 1MHz、幅值 3.3V 的正弦波时钟抖动 1ns信号每秒变化率最大约为 2π × 1MHz × 3.3V ≈ 20.7V/μs1ns 抖动带来的电压误差约为 20.7mV这已经超过 12 位 ADCLSB 约 0.806mV的好几个 LSB 了。因此高速 ADC 应用里采样时钟质量非常重要。MCU 内部 ADC 的时钟通常来自 PLL 分频往往会带有一定的抖动做低速采集没问题做高速高质量采集时就需要考虑外部精密时钟源。5.2 电源噪声影响参考电压等于直接污染测量结果ADC 的测量本质是把输入电压和参考电压做比例比较。如果参考电压本身不稳定测量结果必然不稳定。这也是为什么 ADC 芯片手册里 VREF 引脚周围总要求加滤波电容。电源噪声对 ADC 最直接的影响就是导致转换结果跳变。这里有个实操原则ADC 的参考电压和模拟电源要独立滤波。常见的做法是加磁珠或者小电阻10Ω 左右将模拟电源和数字电源隔离然后接 10μF 钽电容和 100nF 陶瓷电容去耦。参考电压引脚要单独用高质量电容滤波。不要图省事接个 100nF 就完事低频纹波需要大电容高频噪声需要小电容大小搭配才有效。5.3 PCB 布局的 3 个具体要点模拟地和数字地要单点连接。不要大面积铺铜后直接连成一片。如果 ADC 是 MCU 内部的就在 MCU 底部的地焊盘位置把模拟地数字地单点连起来这个连接点要靠近 ADC 电源引脚。模拟信号线要远离数字信号线尤其是 PWM、SPI、I2C 这类高频翻转的信号线。如果 PCB 空间有限无法避免交叉用平面地层做屏蔽在模拟信号线两侧加接地走线。ADC 输入滤波电容要尽量靠近 MCU 引脚。这个电容的作用是给采样电容提供瞬态电荷距离越远回路电感就越大采样瞬间的电压跌落也越严重。说到 PCB 布局我还想强调一个热词相关的问题“∑-δadc前端rc滤波设计”。Sigma-Delta ADC 前端通常需要 RC 低通滤波用来抑制带外噪声和混叠。这个 RC 的截止频率不是随便设置的太高了滤不掉噪声太低了会衰减有用信号和导致建立时间过长。一般设计时先确定信号带宽再把滤波截止频率设置为信号带宽的 5~10 倍同时考虑输入阻抗的影响必要时用运放做有源滤波。6. 软件层面的坑和经验从数据漂移到多点校准硬件做好之后ADC 读数还是会出各种问题。数据漂移、跳变、非线性、DMA 乱序……这些都是在实际项目中反复出现的问题。这一节记录一些常见问题的排查思路和解决方案都是我在实际工程中踩过又填上的坑。6.1 数据漂移最常见的三个根因数据漂移是所有做 ADC 采集的人都会遇到的问题。所谓漂移就是相同的物理量下ADC 读值随时间缓慢变化或者每次开机读值都不一样。常见原因有三个第一个是温度漂移内部参考电压或器件本身的温漂导致测量偏移随温度变化。这个没办法完全消除只能通过校准减小影响。第二个是参考电压不稳定。如果你用 MCU 的 VDDA 做参考电压而 VDDA 同时给其他电路供电一旦负载变化参考电压就会波动读值自然漂。解决办法是使用独立的参考电压芯片或者至少在 VDDA 前加 LDO 隔离。第三个是采样电容老化和污染。这是硬件层面的问题比如 PCB 清洗不彻底、潮湿环境导致漏电流增大。出现这种问题往往需要怀疑板子本身。排查漂移问题时最有效的方法是用一个高精度电压源输入固定电压然后长时间记录 ADC 读数观察漂移曲线大致判断是随机跳变噪声还是趋势性变化温漂或参考源漂移。6.2 软件滤波简单有效的滑动平均和中值滤波如果硬件已经尽量优化读数仍然有随机噪声软件滤波就是最后一道防线。常见的方法有以下几种限幅滤波相邻两次采样值之差超过阈值就认为是一次干扰丢弃或限制变化速率。适合剔除偶发毛刺。中值滤波连续采 N 个值排序去中间值。对脉冲式干扰效果好适合慢变信号但对快速变化信号会失真。N 一般取奇数如 5 或 7。滑动平均滤波维护一个长度为 N 的队列每次取平均值。能有效抑制周期性噪声但会引入滞后。N 越大越平滑响应也越慢。一阶低通滤波y[n] α * x[n] (1-α) * y[n-1]实现简单运算量小适合嵌入式。α 越大响应越快滤波效果越弱。实际项目中我经常把限幅滤波和一阶低通滤波组合使用既消除毛刺又平滑曲线计算开销很小。只看效果选一个中值或者滑动平均也够用但要知道各自的滞后特性。6.3 校准从线性校准到“adc三点校准”ADC 校准的本质是找到实际转换曲线和理想曲线之间的偏差然后补偿。最简单的是单点校准也叫零偏校准输入 0V或 GND记录读数偏差作为偏移量在软件里减去这个偏移。这个方法只能校准偏移误差不能校准增益误差。更常用的是两点校准输入两个已知且稳定的电压比如 10% 满量程和 90% 满量程记录对应的 ADC 读数得到一条直线实际电压 (ADC读数 - ADC零点) * K 实际零点电压其中 K 是斜率校正系数。两点校准同时校正了偏移误差和增益误差适合大多数线性的 SAR ADC。对于非线性较明显的器件或者需要更高精度的测量就需要做“三点校准”甚至多点校准。实现方式是把量程分成多段每一段用两点校准算一条直线查表插值。比如网上常搜到“外部adc三点校准”一般是在 0%、50%、100% 三个点各采一次参考电压把曲线分成两段做分段线性校正。分段越多精度越高但校准工作量也越大工业批量生产时通常需要为此设计专门校准工装。6.4 一个容易被忽略的坑读取 ADC 结果寄存器时可能读到尚未应用校准的值有些 MCU 的 ADC 模块会有校准补偿功能比如对结果做 offset trim。数据手册上常会出现一句很不起眼的话当你读取 ADC 结果寄存器时可能读到的是尚未应用 offset trim 的原始值或者读到已经应用 trim 的值取决于读时机或寄存器配置。这类问题的典型表现是校准之后读数还是有一个固定偏移或者每次读取偶发出现一个固定的错误值。遇到这种情况不能靠软件做二次处理应该去查数据手册里关于结果寄存器、校准寄存器和触发关系的描述。比如有的 MCU型号不能点名但 S32K3 系列就有类似情况在 DMA 读取结果时如果 DMA 请求刚好触发在校准值更新之前就会搬到旧值。解决办法一般是等待某个状态位确认或者用 MUX 选择“只读校准后结果”的寄存器。这一类问题特别容易藏在“八股文”之外平时不看手册真发现不了。我的习惯是用到新芯片的 ADC 时先把数据手册里 ADC 章节从头到尾读一遍尤其是 Result Register 和 DMA Interaction 部分能省下后面大量调试时间。7. 从入门到跑通完整链路给新手的学习路线和面试自查清单写到这里ADC 的基本原理、架构、参数、外设逻辑、硬件布局、软件处理都已经覆盖到了。最后这个章节说说如何把这些知识系统化地串起来形成一个能应对学习和面试的知识框架。7.1 结合网上常搜的“嵌入式学习路线”和“嵌入式开源项目”怎么安排自己嵌入式学习路线的话题每次讨论都很热闹。ADC 部分我建议的顺序是这样的用开发板跑一遍单通道 ADC 采集配合串口或者 OLED 显示把采样、转换、读寄存器的基本流程跑通。做多通道采集加上 DMA理解规则通道序列和缓冲区的关系。测量一个真实物理量比如 NTC 温度传感器或者光敏电阻做一个简单的环境监控或者温度采集系统这能逼你把分压电阻、参考电压、采样时间这些细节全部串起来。往高端走一点可以做基于 STM32F4 的 FFT 频谱分析仪。这个项目在开源社区很常见核心就是 ADC 高速采样加上 FFT 运算涉及采样率设置、缓冲区管理、窗口函数选择对理解 ADC 的频域行为帮助极大。还可以研究一下 BM C 通过 ADC 读取电压的做法。服务器主板上 BMC 常用 ADC 读取电压轨核心思路是电阻分压 多通道扫描 校准原理和 MCU 是一致的。7.2 嵌入式面试中 ADC 相关的高频问题面试官喜欢问的 ADC 问题其实就围绕着这节课里讲的几个点什么是分辨率、精度、采样率它们之间有什么区别简述 SAR ADC 的原理。奈奎斯特采样定理是什么如果采样率不够会发生什么为什么 ADC 读数不稳定怎么解决多通道扫描时数据为什么会乱序DMA 怎么配合如何测量一个高内阻的信号源硬件上如何提高 ADC 采样精度这些问题没有一个能靠背八股文应付过去的面试官追问几句就能看出是真懂还是背下来的。真正理解并动手做过回答起来才会有底气。最后分享一个实操小技巧如果你正在调一个 ADC 读数不准的板子手头又没有高精度电压源我推荐一个土办法用一节全新的碱性电池当参考源。碱性电池的开路电压相当稳定一般在 1.6V 左右用万用表测出精确值然后接入 ADC 引脚。由于电池内阻很低不用考虑阻抗匹配问题。对比 ADC 读数和万用表读数可以快速评估板子的整体误差水平。这个方法帮我排查过好几个项目的 ADC 问题成本几乎为零效果却非常直观。ADC 没有想象中那么神秘但它确实不是一个“接上就读”的傻瓜外设。从模拟信号的理解到内部架构的选型再到外设的启用逻辑和硬件布局每一步都有值得深挖的细节。把这篇文章里的知识吃透再去动手做一两个自己的小项目相信你会对嵌入式系统里“读一个电压值”这件小事建立起完全不一样的认知。
返回列表