资讯动态

搞懂模拟信号、数字信号与ADC:从原理到STM32工程实践

发布时间:2026/9/8 6:45:49 来源:尧图企业网站定制
搞懂模拟信号、数字信号和ADC外设其实就是搞懂一个“翻译”的过程。单片机只能处理0和1但现实世界的电压是连续变化的比如电池电压从4.2V慢慢跌到3.7V这个变化过程没有“中间档位”是连续的。ADCAnalog-to-Digital Converter模数转换器就是负责把这种连续变化的电压翻译成单片机能够理解的一组二进制数。初学嵌入式时很多人会在这一步卡住为什么ADC读出来的数字不对为什么一会儿跳一会儿稳为什么同一个引脚接到不同模块上读数差异巨大这些问题背后涉及的其实是模拟信号特性、数字信号表达、外设内部工作机制三件事的交叉。这篇内容就是把这条线捋清楚给正在学STM32、ESP32或任何带ADC的单片机的人一份可以直接上手、也能帮你定位问题的指南。这篇内容适合这几类人看刚入手嵌入式开发、想搞明白“单片机怎么感知外部电压”的初学者已经在用ADC但精度始终调不上去、数据波动严重的实践者以及准备面试嵌入式岗位、需要系统梳理ADC原理和关键参数的人。我会从信号本身讲起一路拆到ADC外设是怎么通过“逐次逼近”把电压变成数字的最后给出基于STM32 HAL库的完整实操流程和滤波、校准方案尽量让你看完就能在自己板子上复现。1. 先搞明白一件事为什么单片机非要有ADC一直有个比喻我挺喜欢模拟信号像“水龙头出水”你可以开到任意角度水流可以处于任何大小数字信号像“开关”只有开和关两种状态要么全通要么全断。现实世界的温度、光照、压力、电池电量全是“水龙头”那类连续变化的量而单片机内部是一个纯粹的数字逻辑世界它只能理解“有电压”和“没电压”——也就是逻辑1和逻辑0。这两个世界之间不能直接通信必须由一个“翻译官”在中间搭桥ADC就是这个翻译官。1.1 模拟信号不是“玄学”是物理量的电压映射模拟信号的本质是一个随时间连续变化的电压或电流信号。举个例子你用热敏电阻测温度温度升高时电阻阻值下降配合一个分压电阻温度变化就转化成了引脚上电压的连续变化。25℃时电压可能是1.20V26℃时是1.17V27.5℃时是1.13V——每一个温度点都对应一个唯一的电压值而且温度变化的过程中电压不会跳变它是平滑过渡的。这就是模拟信号。但这里有个关键点容易被新手忽略模拟信号本身不带任何“刻度”信息。你只知道引脚上有一个介于0V到3.3V之间的电压但你不知道这个电压对应多少度、多少公斤、多少毫升。刻度信息是人定标出来的ADC只是忠实地告诉你“这个电压大概是多高”至于它代表什么物理意义需要你在代码里做两层计算第一层是拿ADC原始读数换算出电压值第二层是拿电压值按传感器的标定关系换算出实际物理量。很多初学者拿着ADC读数直接当物理量用然后觉得数值“不对”其实不是ADC不对是换算这一步漏了。1.2 数字信号表达的边界精度和量程从何而来数字信号在单片机里最终表现为寄存器的位bit而ADC把模拟电压转换成的是一个有限位数的二进制整数。这个“有限位数”是整个ADC系统的核心约束。常见的ADC有8位、10位、12位、16位、24位位数决定了能把量程切成多少份。以12位ADC配合3.3V参考电压为例。12位意味着最大输出值是40952^12 - 1那最小分辨率就是 3.3V除以4096约等于0.8mV。也就是说这个ADC能区分的最小电压变化量是0.8mV低于这个差异的电压在它眼里可能是同一个值。这个最小变化量在ADC领域中叫LSBLeast Significant Bit最低有效位。这里引申出一个很多新手搞混的概念分辨率不等于精度。分辨率描述的是“ADC能分辨到多细”精度描述的是“ADC测得准不准”。一辆能称到0.1g的电子秤如果传感器漂了或者没校准可能每次称出来都比真实值偏0.5g这时它分辨率高但精度差。ADC同理位数是硬件的分辨能力精度受参考电压稳定性、布局布线、外部干扰、校准情况等综合影响。你在产品中真正关心的是精度而分辨率只是精度的基础条件之一。2. ADC外设内部到底在做什么逐次逼近型ADC的工作机制拆解市面上的单片机内置ADC绝大多数是逐次逼近型SARSuccessive Approximation Register架构少数高速场合会用流水线型低功耗高精度场合可能用Σ-Δ型。STM32内部集成的就是SAR ADC搞清楚它的工作过程基本就掌握了绝大多数MCU内置ADC的逻辑。2.1 用“猜数字游戏”理解逐次逼近理解SAR ADC最好的方式是把一次转换想象成一个“猜数字游戏”我心里想了一个0到100之间的数你来猜我只回答“大了”或“小了”。最高效的猜法不是在0到100之间逐个试而是先猜50如果大了就把范围缩到0到49再猜25……每一次都把范围缩小一半这就是二分查找。SAR ADC做的事完全一样单片机内部内置了一个DAC数字模拟转换器它可以把一个数字量转换成对应的模拟电压。转换一开始外部模拟电压先被采样保持电路“冻结”然后SAR逻辑先从最高位开始猜——先假设结果是1000 0000 000012位ADC的一半把这个值送入内部DACDAC输出一个模拟电压进入比较器与冻结的输入电压比较。如果输入电压比DAC输出的电压高说明猜小了这一位保留为1继续猜下一位如果输入电压低说明猜大了这一位翻回0。以此类推从最高位到最低位各比较一次12位就猜12次最终组合出一个最接近输入电压的数字量。整个过程像不像天平称重一边放未知物品另一边从小到大按二进制砝码尝试从最重的砝码开始放上去发现太重就拿掉不够就保留一级一级往下试直到天平平衡。这样就能用有限的砝码组合称出任意重量的近似值。2.2 采样保持、比较器、DAC的角色分工只看“猜数字”模型可能还觉得抽象我们把SAR ADC的每个功能模块拆开看采样保持电路Sample and Hold这是很多人忽略但极其关键的一环。ADC转换需要时间而外部模拟电压在转换期间可能持续变化如果在转换过程中电压变了那这次转换到底在测什么时候的电压说不清楚。采样保持电路在收到触发信号的瞬间闭合一个模拟开关让外部电压给内部的采样电容充电短暂充电后开关断开电容上的电压就被保持住了在之后整个逐次逼近过程中比较器看到的一直是这同一个“冻结瞬间”的电压值。这个“冻结”动作叫采样保持的时间要足够完成一次完整转换。内部DAC电容阵列DAC当代SAR ADC内部大多使用二进制加权的电容阵列来充当DAC。这些电容的容值按照1、2、4、8……的二进制比例排列SAR逻辑控制何时把哪一组电容接参考电压或者接地最终在DAC输出端叠加出与猜测数字对应的模拟电压。电容阵列本身同时兼做采样电容这个设计非常巧妙但也会带来一个问题外部信号源的驱动能力会影响采样精度这点我们在第5节会展开说。比较器Comparator它就是一个高增益的差分放大器比较两个输入电压的大小输出一个数字电平输入电压大于DAC输出电压则输出1否则输出0。比较器的性能直接影响ADC的精度如果它有失调电压那每次比较都可能带一个固定偏差最终转换结果会系统性偏离真实值。外部ADC的校准一部分就是在校准这类偏移。逐次逼近寄存器SAR Logic它负责控制“先猜哪位、保留还是撤销”的流程。通俗讲它就是个二分查找状态的机。每来一个时钟周期它就把当前这一位置为1等比较器回一个结果再决定保留或者清0然后移到下一位。2.3 两个极其容易翻车的时序指标讲完工作机制必须要提两个新手极易忽略的参数采样周期和建立时间。采样周期决定了“采样开关闭合多久、电容被充到多满”。如果采样时间不足采样电容上的电压还没来得及充到接近外部输入电压开关就断开了那后面比较器比较的是一个“没充满”的电压转换结果会比实际值偏低。采样时间需要多长跟外部信号源的阻抗直接相关信号源输出阻抗越大充电就越慢需要的采样时间越长。STM32的ADC外设允许配置采样时间常见选项有1.5个ADC时钟周期到239.5个周期不等。实际经验是如果信号来自一个高阻抗源比如电阻分压网络分压电阻总阻值几十千欧甚至更高建议把采样时间配置到最大档否则转换结果会明显偏小。下面是一个参考原则信号源阻抗范围建议采样时间档位小于1kΩ如运放输出中档即可如13.5周期1kΩ到10kΩ如传感器直接输出较长档如28.5到71.5周期大于10kΩ如高阻分压网络最大档如239.5周期另外还有一个“最少两次采样间隔”的讲究。在一次转换完成后采样电容上的电荷还残留着上次转换的“记忆”如果紧接着立刻做下一次采样新电压和残留电荷之间会发生电荷共享导致第二次转换结果有偏差。所以ADC外设在连续转换模式下会自动留出足夠的采样间隔但手动切换通道、频繁改变触发源时要特别留意必要时可以通过降低转换频率来规避这个坑。3. 从寄存器到工程分辨率、参考电压与外设配置逻辑前面把原理层面的东西聊透了现在落地到实际配置。任何一个带ADC的单片机配置外设时都绕不开三件事选多大分辨率、参考电压从哪里来、转换一次要花多长时间。这三个参数决定了你的测量系统能做到什么水平。3.1 关于分辨率位置“高”未必里子“好”STM32的大多数型号支持6位、8位、10位、12位四档分辨率可调。高分辨率意味着更细的刻度但也意味着更长的转换时间和更大的存储开销。更低的分辨率并不总是坏事如果你只是检测“电池电压有没有低于3.0V”这种阈值判断场景12位纯属浪费反之如果你在做一个精密电池电量计需要捕捉几十毫伏级别的变化那12位也未必够用可能得上外部24位Σ-Δ型ADC。实际工程中分辨率还受噪声地板限制。一个12位ADC的LSB约是0.8mV但如果你的电路板电源噪声就有2mV那低位的那一两位实际上是在量化噪声不是量化信号。这时候强行追求高分辨率没有意义优先处理噪声源才是关键。我用过很多次的反直觉经验是输出结果跳动时第一反应不应该是降分辨率而是看电源纹波和参考电压纹波。3.2 参考电压是整把“尺子”的基准参考电压Vref就是ADC这把标尺的刻度基准。12位ADC能输出0到4095对应的电压范围就是0到Vref。当Vref是3.3V时一个读数2048对应的实际电压是1.65V当Vref是2.5V时同样的读数2048对应的是1.25V。同一个数字码在不同的参考电压下代表完全不同的实际电压这个基本关系如果没建立起来后面所有换算都是错的。工程上参考电压有几个来源一是直接用MCU的模拟电源引脚电压二是芯片内部集成的参考电压三是外部高精度基准源芯片。如果是一般学习或低速测量场景直接用供电电压即可如果是做有精度要求的产品强烈建议用外部基准源。你需要核实一下手头MCU的参考电压引脚很多芯片的Vref引出来是直连供电的外部电压不稳时ADC结果会跟着剧烈跳。这里有个很多人踩过的坑同一个供电网络既给MCU又给电机、继电器之类的负载时负载一启动供电电压往下掉ADC满量程也跟着掉原本1.0V的某个被测量可能读出来还是1.0V的对应码但换回实际电压后发现测量值随负载变化而浮动。这类问题两码事一是外部噪声干扰二是参考电压自身漂移。3.3 转换时间的工程取舍与HAL库配置位ADC转换时间大约是采样阶段加逐次逼近阶段之和。逐次逼近阶段固定约等于分辨率位数加一些固定周期比如12位模式通常12到15个ADC时钟周期采样阶段则可以配置。所以总转换时间大致是总转换时间 采样时间 12至15个周期12位模式如果ADC时钟配置为12MHz、采样时间配239.5个周期那单次转换时间大约是239.5 12.5÷ 12MHz ≈ 21μs对应的最大采样率只有约4.7万次每秒。注意这已经是STM32F1系列不带过采样情况下的实际水平了比很多人想象的慢得多。如果你要采样音频48kHz或振动信号可能要求每通道10kHz以上就一定要提前算清楚这个账不然一个通道的配置都不够用。在STM32的HAL库中ADC采样时间、分辨率、时钟分频等参数集中在一个结构体里。下面是一份我常用的基础配置代码框架基于STM32F1/HAL库型号不同寄存器名略有差异但逻辑通用ADC_HandleTypeDef hadc1; void MX_ADC1_Init(void) { hadc1.Instance ADC1; hadc1.Init.ScanConvMode DISABLE; // 单通道模式 hadc1.Init.ContinuousConvMode DISABLE; // 单次转换不连续扫描 hadc1.Init.DiscontinuousConvMode DISABLE; hadc1.Init.ExternalTrigConv ADC_SOFTWARE_START; // 软件触发 hadc1.Init.DataAlign ADC_DATAALIGN_RIGHT; // 数据右对齐 hadc1.Init.NbrOfConversion 1; // 转换通道数量 if (HAL_ADC_Init(hadc1) ! HAL_OK) { Error_Handler(); } } void ADC1_Select_Channel(uint32_t channel, uint32_t sample_time) { ADC_ChannelConfTypeDef sConfig {0}; sConfig.Channel channel; sConfig.Rank 1; sConfig.SamplingTime sample_time; // 如 ADC_SAMPLETIME_239CYCLES_5 if (HAL_ADC_ConfigChannel(hadc1, sConfig) ! HAL_OK) { Error_Handler(); } }这里有个HAL库使用的细节HAL_ADC_Init里配置的NbrOfConversion是这次转换序列的通道数如果你要单通道采样就写1。每次切换通道时不需要重新HAL_ADC_Init只要重新调用HAL_ADC_ConfigChannel改通道号和采样时间即可。很多初学者一换通道就重新初始化整个ADC这是完全没必要的白白增加了切换开销。4. 上手实操STM32 HAL库ADC加DMA单通道多次采样光讲原理不跑代码等于没学。这一节我给出一套我实测过的完整流程STM32单片机的ADC单通道采集用DMA把多次转换结果搬进内存CPU不参与搬运数据到位后做平均值处理。这套方案是嵌入式处理ADC最通用的骨架不管是做传感器采集还是做数据记录直接套用都能跑。4.1 为什么“读一次寄存器”的方案不那么好用很多入门教程教的是循环里直接读ADC数据寄存器。一个while循环里启动转换、等待完成标志位、读数据看似无害但这个模式在高频采样时存在致命缺陷 **ADC数据寄存器在任何时刻只能保存最近一次转换的结果CPU如果不及时读走下一次转换完成时新数据会覆盖旧数据。**你读出来的可能是上一次、上上一次的结果也可能是新旧混合的中间值简称“丢帧”。DMA模式的思路是ADC每转换完一次硬件直接把数据寄存器里的值搬到内存数组里不经过CPU干预。转换1000次DMA就把1000个数据搬到数组里搬完了再给你一个中断信号你再去集中处理这批数据。这种架构既不会丢帧又省CPU时间是工程项目的标准做法。4.2 配置DMA的完整代码骨架在STM32CubeMX里配置时给ADC1添加DMA请求选择循环模式Circular数据宽度按Half Word16位设置。因为12位ADC数据寄存器是16位宽但高4位没有意义如果你用了8位分辨率才需要考虑Byte宽度初次使用建议统一用Half Word。下面是一份HAL库初始化DMA部分的代码DMA_HandleTypeDef hdma_adc1; void MX_DMA_Init(void) { __HAL_RCC_DMA1_CLK_ENABLE(); hdma_adc1.Instance DMA1_Channel1; hdma_adc1.Init.Direction DMA_PERIPH_TO_MEMORY; // 外设到内存 hdma_adc1.Init.PeriphInc DMA_PINC_DISABLE; // 外设地址不递增 hdma_adc1.Init.MemInc DMA_MINC_ENABLE; // 内存地址递增 hdma_adc1.Init.PeriphDataAlignment DMA_PDATAALIGN_HALFWORD; hdma_adc1.Init.MemDataAlignment DMA_MDATAALIGN_HALFWORD; hdma_adc1.Init.Mode DMA_CIRCULAR; // 循环模式持续搬运 hdma_adc1.Init.Priority DMA_PRIORITY_HIGH; HAL_DMA_Init(hdma_adc1); __HAL_LINKDMA(hadc1, DMA_Handle, hdma_adc1); }启动采集的主逻辑如下#define ADC_SAMPLE_COUNT 32 // 单次DMA搬运的样本数 uint16_t adc_buf[ADC_SAMPLE_COUNT]; void ADC_Start_DMA_Sampling(void) { HAL_ADC_Start_DMA(hadc1, (uint32_t *)adc_buf, ADC_SAMPLE_COUNT); } // DMA传输完成回调 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) { if (hadc-Instance ADC1) { // 到这里adc_buf里已经有32个样本可供处理 // 注意DMA还在继续搬运所以此回调里不要做耗时操作 // 简单做法是置一个标志位在主循环里处理 adc_data_ready 1; } }推荐在主循环中判断adc_data_ready标志后再做平均值计算等操作不要在中断回调里做复杂计算。回调进出的开销已经不小了再来一个浮点平均值运算你会把其他中断的响应时间拖到不可接受。4.3 第一次上电就会踩到的三个经典坑坑一DMA搬运的数据全零或全满。这个现象八成是ADC没有真正启动。HAL库的规则是HAL_ADC_Start_DMA必须在ADC初始化之后调用且如果在之前有手动调用过HAL_ADC_Start要先做HAL_ADC_Stop。另一个常见原因是没有给ADC校准部分STM32系列比如F3、F4、G0等要求上电后做一次HAL_ADCEx_Calibration_Start(hadc1)不做的话转换结果会整体偏移甚至输出全0。F1系列自动校准不那么明显但我不建议新手绕过这一步。坑二读取数组里的值发现前几个样本不准。首次开启DMA搬运时外设刚上电内部状态还没稳定前面几个转换结果可能异常。这是一个非常典型的现象不是电路问题。解决办法也很简单DMA中断回调里不要使用数组的前几个数据或者多采集几个样本再做丢弃处理例如采集32个样本实际只用后28个做平均。我习惯把样本数配置成比实际需要多4个从索引4开始取数这4个样本充当“热身数据”。坑三切换通道后DMA搬运的是旧通道的数据。我在调试多通道时遇到过这种诡异现象代码里明明配置了通道2读出来的数据却和通道1上电时一致。后来排查才确认DMA缓存里的数据需要先清空一轮配置新通道后再启动DMA采集如果缓存里残留的是上一轮的旧数据你拿到的第一批数据全是旧的。工程上我的处理方式是配置完通道后先启动DMA等它搬完一轮数据进入回调后再判断这批数据有效即每次切换通道后丢弃第一批样本。5. 让ADC数据真正靠谱滤波、校准与前端匹配如果说前面几节讲的是“怎么把数据采出来”那这一节就是“怎么把数据采得准”。经过前面所有这些步骤后数据虽然能读出来了但你会发现它经常有毛刺、有波动甚至整体偏离真实值。这是正常的——ADC系统从来不是“接上就能测准”的模块。这里分享三段经验一是什么导致数据乱跳二是常用滤波手段怎么选三是外部三点校准到底做了什么。5.1 数据乱跳的根源噪声与信号源阻抗读ADC时数值在几个LSB之间来回跳说明系统受到了噪声干扰。最常见的噪声源有三个开关电源的纹波、板级地弹噪声、相邻引脚的数字信号串扰。开关电源频率通常几十到几百kHz它产生的纹波会直接窜到供电网络和参考电压上ADC的结果就会跟着周期性波动。地弹噪声主要来自高频数字信号回流路径不理想模拟地和数字地如果没有合理规划数字电路的开关噪声就会通过地平面串进模拟信号里。如果你遇到的是一个高输出阻抗的信号源比如通过100kΩ分压电阻送到ADC引脚哪怕只有几个纳安的漏电流流入ADC内部也会在信号源内阻上产生几百微伏的压降直接形成误差。这种情况下硬件上最优解是加一级电压跟随器运放缓冲用运放的低输出阻抗驱动ADC输入端。软件上如果一时改不了硬件可以把采样时间拉长到最大尽量让采样电容充得更接近真实电压误差会小一些但不会根除。5.2 三种常用滤波手段的适用场景软件滤波本质是牺牲“反应速度”换取“稳定性”。实际应用中不同场景要选不同策略不能一个平均值打天下。限幅滤波用于剔除明显异常值。例如正常采集值应该在0到4095之间但如果某次瞬态干扰把容值打到VCC以上ADC内部保护二极管会把电压钳位在VCC加一个二极管压降此时读数会接近满量程。用限幅滤波可以直接丢弃这种明显不合理的值。滑动平均滤波是最常用的手段相当于一个低通滤波器取最近N次的平均值。N越大越平滑但滞后越明显。用一个经验公式来定N信号有效带宽除以ADC采样率再乘2到4倍。比如一个温度传感器信号带宽极低1Hz都不到采样率1000Hz那N取64、128甚至256都没问题但如果采的是电机转速信号带宽有几十HzN就不要超过16否则动态响应跟不上。一个简单的滑动平均实现#define FILTER_WINDOW 8 uint16_t sliding_average_filter(uint16_t new_sample) { uint32_t sum 0; static uint16_t buf[FILTER_WINDOW] {0}; static uint8_t index 0; static uint8_t count 0; buf[index] new_sample; index (index 1) % FILTER_WINDOW; if (count FILTER_WINDOW) count; for (uint8_t i 0; i count; i) { sum buf[i]; } return sum / count; }一阶低通滤波是滑动平均的频域版本代码极简适合对内存占用敏感的环境uint16_t lowpass_filter(uint16_t new_sample, uint16_t *prev_output, uint8_t alpha) { // alpha取值范围0-255越小滤波越强 *prev_output (uint16_t)((((uint32_t)*prev_output * (255 - alpha)) ((uint32_t)new_sample * alpha)) 8); return *prev_output; }两种滤波在实际使用中我一般这样取舍如果信号周期性或者缓慢变化用滑动平均更直观如果采样率很高而对延迟又敏感一阶低通Rc滤波更合适。5.3 外部ADC三点校准一套能落地的标定流程芯片出厂时都会做内部校准但内部的参考电压精度有限而且外部采样电路比如电阻分压网络的阻值误差、运放的零点偏置都会叠加到测量链路里。如果想把整个链路误差纠正到合理范围就需要外部校准一点校准只能在某个电压点附近修正偏置三点校准可以同时校正零位误差、增益误差和线性度误差。这也是为什么很多计量类产品会做三点校准在测量范围的低、中、高三点分别给一个已知基准电压测出ADC读数和真实电压的关系然后用分段线性插值去修正。校准过程不复杂但需要高精度仪器配合。假设量程是0到3.3V我取0.5V、1.5V、2.5V三个校准点用精密电压源分别输入这三个电压记录ADC原始读数得到三组坐标(V1, code1)、(V2, code2)、(V3, code3)。之后任意电压V对应的原始码code先判断它落在哪一段区间再按该区间的斜率和偏移修正float correction_lookup_table[3] {0.5f, 1.5f, 2.5f}; uint16_t correction_adc_value[3] {0}; // 实际校准时写入 float adc_to_voltage_calibrated(uint16_t adc_code) { if (adc_code correction_adc_value[0]) { // 首段使用第一个区间斜率 float slope (correction_lookup_table[1] - correction_lookup_table[0]) / (float)(correction_adc_value[1] - correction_adc_value[0]); return correction_lookup_table[0] slope * (int32_t)(adc_code - correction_adc_value[0]); } else if (adc_code correction_adc_value[1]) { float slope (correction_lookup_table[1] - correction_lookup_table[0]) / (float)(correction_adc_value[1] - correction_adc_value[0]); return correction_lookup_table[0] slope * (int32_t)(adc_code - correction_adc_value[0]); } else { float slope (correction_lookup_table[2] - correction_lookup_table[1]) / (float)(correction_adc_value[2] - correction_adc_value[1]); return correction_lookup_table[1] slope * (int32_t)(adc_code - correction_adc_value[1]); } }注意上面的斜率计算本质上就是“ADC读数变化多少对应多少伏电压”的标定常数。第一段和第二段可能斜率不同这是因为实际电路在低端和高端非线性不同三点校准的好处就是能分别修正这两段。实测过程中我用这个方法把一块12位ADC的电压测量误差从满量程的1%以上压到了0.2%以内。同志们在批量校准的时候还要注意一致性如果每块板子都手工校准一遍人力成本会很高如果只是做研发阶段验证那手工校准完全够用。校准系数建议存放在片内Flash或外部EEPROM中上电后先加载并校验如果发现值超出合理范围就回退到默认系数并给出错误提示这样避免用户拿到未校准数据的设备后测量出错。从“量个电压”这个小需求出发一路拆到信号本质、SAR原理、外设配置、DMA实操、滤波校准这就是我理解的一条最完整的ADC入门路径。调试ADC有个习惯我想分享给所有人**永远先怀疑参考电压再怀疑配置最后才怀疑单片机坏了。**我在这行修过的ADC相关BUG里一半以上都跟参考电压或者地平面噪声有关而不是芯片本身有什么问题。在嵌入式领域折腾真正拉开差距的往往不是会调用哪个函数而是能不能把一个看似简单的“读电压”搞懂、搞准、搞稳定。把这套思路顺着捋下来你再去看任何一款新单片机的ADC外设花十分钟读数据手册就能快速上手。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价