尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

STM32 ADC从原理到实战:采样时间、DMA多通道与滤波调试指南

发布时间:2026/9/27 20:28:39

资讯中心
01
ARTICLE

STM32 ADC从原理到实战:采样时间、DMA多通道与滤波调试指南

STM32 ADC从原理到实战:采样时间、DMA多通道与滤波调试指南
做嵌入式这几年ADC这个外设几乎出现在每块板子上。单片机之间传数据走的是数字量而温度、压力、光照、电流这些物理量天生是连续的模拟信号要让STM32认识它们就必须先把模拟量数字化——这就是ADC模数转换器的核心任务。也正因为如此ADC怎么用、用得好不好直接决定了一个采集类项目能不能落地。这篇文章把STM32的ADC从原理到应用编程完整过一遍包括逐次逼近型内部结构、分辨率与采样时间这些关键参数、HAL库配置代码、DMA多通道采集、软件滤波和常见坑。先把结论放在前面ADC本身并不难真正折磨人的是它的周边——参考电压干不干净、输入阻抗搭不搭、采样时间够不够、DMA有没有对齐。这篇文章会沿着这个顺序一层层往下走适合刚开始学STM32的朋友也适合已经在做传感器采集、电源监测、仪器仪表类项目的工程师当成一份排查手册来翻。1. ADC原理模拟量到数字量中间发生了什么1.1 逐次逼近型SAR是怎么一路“猜”出来的STM32主流型号搭载的ADC大多采用逐次逼近型结构SARSuccessive Approximation Register这种结构在分辨率、速度和功耗之间取得了不错的平衡适合绝大多数MCU场景。它内部不算复杂核心就是比较器、数模转换器DAC网络、逐次逼近寄存器SAR外加一个采样保持电路。你可以把它的工作过程想象成一个“猜价格”游戏主持人心里定了一个0到4095之间的数字你每次报一个数他只告诉你“猜高了”还是“猜低了”你要用最少的次数把这个数猜中。最优策略闭着眼都知道——二分法先猜2048如果高了说明真实值在0~2048之间再猜1024如果低了说明真实值在2048~4095之间再猜3072。每猜一次把范围缩小一半12位精度最多猜12次就能锁定结果。SAR ADC干的事完全一样。转换开始前采样保持电路先把输入电压的瞬时值“冻结”到采样电容上然后SAR寄存器开始干活先把最高位置1让内部DAC输出一个Vref/2的参考电压比较器把这个参考电压和采样到的输入电压做比较。如果输入更高最高位保留为1说明真实电压落在上半区间否则清零最高位落到下半区间。接着用同样的逻辑去试探下一位。每一位试探都需要一个ADC时钟周期12位精度就是12个比较周期转换完成后SAR里的二进制码就是最终的转换结果。这里有个容易忽略的点采样保持电容在充电瞬间会从输入端“抽取”电荷如果信号源的内阻太高电容没充满就开始比较结果必然偏低。很多新人只盯着转换时间看却忽略了输入源阻抗结果读到的值总差那么几个LSB怎么查都查不出来根子其实就在采样阶段。1.2 分辨率、参考电压与量化误差读数精度的天花板STM32常见的ADC是12位意思是把参考电压分成4096格。这个“刻度尺”的粗细决定了最小分辨率如果参考电压Vref是3.3V那么1个LSB最低有效位就是3.3 ÷ 4096 ≈ 0.8057mV。读到一个码值比如3800对应的电压大约是3800 × 0.8057mV ≈ 3.06V。很多人用3.3/4096算系数这个思路没错但忽略了一件事板子上实际的参考电压并不一定严格等于3.3V。F103的VDDA和Vref通常直接接在3.3V电源上可LDO输出本身有温漂线路压降也可能让参考电压落到3.27V。这时候再用3.3做分母去反推真实电压算出来的结果自然信不过。严谨的做法是使用片内的VREFINT通道去反推实际VDDA或者在硬件上接一颗精密基准源。量化误差则是ADC的“出身缺陷”。输入电压是连续量但输出码值只有4096个整数值任何落在两个码值之间的电压都只能四舍五入到某一个整数上。这个误差最多±0.5 LSB是结构性的、无法通过滤波消除的随机误差。滤波能滤掉的是叠加在信号上的随机噪声滤不掉的是量化误差和系统性的增益偏差这一点想明白后面做校准时才不会瞎折腾。不同位数的ADC最小分辨率差距很大直观感受一下ADC位数满量程档位数3.3V参考下的1 LSB电压8位256约12.89mV10位1024约3.22mV12位4096约0.81mV16位65536约50μV位数越高分辨能力越强但成本和转换时间也会上去。STM32的12位ADC对于电池电压、环境温度、普通压力传感器这类应用已经完全够用没必要盲目追求高位数。1.3 采样时间与转换时间快和准之间的权衡ADC的时钟频率不是随便给的。F103的数据手册规定ADC时钟最高不能超过14MHz一般工程上配置为12MHz也就是APB2的72MHz做6分频。想用2分频得到36MHz不行直接超规格。一次完整的转换由采样阶段和转换阶段组成。转换阶段固定消耗12.5个ADC时钟周期而采样阶段可以通过寄存器配置为1.5、7.5、13.5、28.5、41.5、55.5、71.5、239.5个周期这几个档位。于是最短转换时间就是(1.5 12.5) ÷ 12MHz ≈ 1.17μs最长则是(239.5 12.5) ÷ 12MHz ≈ 21μs。差距近20倍怎么选其实取决于输入端源阻抗。为什么源阻抗会影响采样时间因为采样电容要充满电才能准确反映输入电压。一阶RC充电模型下充到12位精度大概需要8个左右的时间常数。假设外部源阻抗是47kΩ内部开关等效电阻约1kΩ采样电容按8pF估算时间常数τ≈48kΩ × 8pF ≈ 384ns8个τ约3μs换算成ADC时钟就是3μs × 12MHz ≈ 36个周期。这时候选1.5周期的采样时间读数必然偏低至少得选55.5周期那一档才稳。所以选采样周期第一原则是慢不怕但一定要让电容充满。实际项目里我一般是先按55.5周期起步确认读数稳定后再根据信号变化速度去逐档压缩。不要一上来就追求最快采样率那只是在给排查问题制造难度。2. 读懂STM32的ADC外设通道、序列与触发2.1 引脚、规则组和注入组ADC也有自己的“任务队列”STM32的ADC不像独立ADC芯片那样只有两三个输入引脚它内部自带一个多通道模拟开关。拿F103C8T6来说ADC1有PA0~PA7、PB0~PB1共10个外部通道外加一个内部温度传感器通道和一个内部基准电压VREFINT通道。每个引脚被复用为ADC输入时对应的GPIO必须配置成模拟输入模式这一点经常有人漏掉——配成复用推挽或者浮空输入采样结果都会出问题。通道之上还有“规则组”和“注入组”两套概念。规则组可以理解成一个普通的排队序列最多能编排16个转换项可以重复编同一个通道转换结果依次落进唯一的数据寄存器DR。由于DR只有一个多通道扫描模式下必须在每次转换完成时立刻把数据读走否则下一次转换结果会直接把它覆盖掉。注入组则像一个“特权通道”可以在规则转换过程中插队适合那些需要抢占采样周期的场景比如电机控制里的三相电流同步采样。实际调试中90%的场景用规则组就够了。注入组听起来高级但对大多数传感器采集项目来说属于锦上添花的功能不用急着掌握。2.2 四种转换模式怎么选别一上来就“全开”STM32的ADC支持单次转换、连续转换、扫描模式和间断模式。这四个概念可以自由组合但新手最容易把它们一股脑全开结果行为完全失控。单次转换模式适配“软件触发一次只转一个通道转完就停”的用法适合低速轮询功耗也低。连续转换模式则是转换完成立即开始下一次适合持续检测某一组信号多通道时配合扫描模式就能循环转换整个序列。扫描模式是指一次触发能够把规则组里排好的多个通道依次转换完。间断模式相对冷门它把序列拆成几个小批次每触发一次只转换一小批用在某些需要把大序列切碎的特定场景。我的建议是单通道采集用“单次转换关闭扫描”多通道数据需要用循环刷新用“连续转换扫描模式”只要你不在一次转换里同时要多个通道的结果就不要开扫描DMA以外的额外功能。项目调试阶段配置越简单越容易定位问题。这里还要注意一个非常重要且容易踩的坑当启用“扫描模式连续转换”且用DMA搬运数据时DMA会持续不断地把转换结果往内存里填。如果DMA配置成Normal模式只搬一轮那么一轮搬完后就永远停在那了后续的转换结果无人接管如果配置成Circular模式则会形成一个环形缓冲区数据不断被刷新。两种模式用途完全不同很多人数据“不动”了其实就是把Normal模式当成Circular模式在用。2.3 外部触发与DMA让ADC学会自己干活ADC不一定要用软件启动。很多型号支持定时器触发或者外部引脚触发典型应用是电机控制和开关电源PWM的定时器更新事件在MOSFET开关的特定时刻触发ADC精确地采到该时刻的电流值。如果用软件轮询去碰这个时机很难做到真正的同步。F103里这类触发源通过ADC的EXTSEL位来选具体映射要在参考手册里查CubeMX的图形界面也能直接选择。软件触发适合普通传感器采集但一旦进入多通道高频采样软件轮询基本没法腾出手来干正事。此时ADC的核心搭档是DMA每次转换结束产生EOC信号硬件自动把DR里的数据搬进内存CPU完全不用干预。代码上看就是调一个HAL_ADC_Start_DMA剩下的全由外设自己跑。DMA这里有三个细节必须说清楚。第一数据宽度建议配成Half Word并对应uint16_t数组不要配Word宽度然后申请uint32_t数组——虽然也能用但高16位始终是残留值容易让你怀疑人生。第二DMA循环模式下缓冲区会被硬件持续覆盖想拿到某一时刻的数据要么用DMA传输完成中断做标志位要么用双缓冲切换。第三多通道扫描时缓冲区里的数据顺序和Rank编排顺序一一对应不要指望代码能替你重新排序。3. 应用编程实战从CubeMX到真实数值3.1 CubeMX图形化配置先跑起来再谈优化用STM32CubeMX做初始化并不是偷懒它能帮你少翻几百页参考手册项目初期效率高得多。以F103C8T6配单通道为例流程大致是时钟树里确认系统时钟跑在72MHzAPB2输出72MHzADC分频器设为6分频让ADCCLK维持在12MHz附近。在ADC1的Channel配置里勾选你要用的通道比如IN0对应PA0。参数配置页里把Resolution选12位ScanConvMode按需打开或关闭ContinuousConvMode按需使能采样时间先选55.5周期外部触发选Software Trigger。如果要多通道循环采集在DMA Settings里添加一个ADC1到Memory的请求Mode选Circular数据宽度选Half Word。生成代码工程里就会自动生成MX_ADC1_Init。有个经验想单独提一下第一次上板采样时间一定先往大里配。比如55.5、71.5甚至在低速信号上用239.5周期。先确认通道、参考电压、电源环境都正常再慢慢压缩采样时间换取速度。如果一上来就追求1.5周期的极限速度万一板子布线不太好读到的数据乱跳你会分不清到底是配置问题还是硬件问题。3.2 单通道轮询代码最小可用的完整流程CubeMX生成的初始化代码长这样ADC_HandleTypeDef hadc1; void MX_ADC1_Init(void) { hadc1.Instance ADC1; hadc1.Init.ScanConvMode ADC_SCAN_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; HAL_ADC_Init(hadc1); ADC_ChannelConfTypeDef sConfig {0}; sConfig.Channel ADC_CHANNEL_0; sConfig.Rank ADC_REGULAR_RANK_1; sConfig.SamplingTime ADC_SAMPLETIME_55CYCLES_5; HAL_ADC_ConfigChannel(hadc1, sConfig); }读取一个值的函数更简单uint16_t read_adc_once(void) { uint16_t value 0; HAL_ADC_Start(hadc1); // 启动转换 if (HAL_ADC_PollForConversion(hadc1, 10) HAL_OK) { value HAL_ADC_GetValue(hadc1); // 从DR寄存器读结果 } HAL_ADC_Stop(hadc1); return value; }这段代码有几个点值得展开HAL_ADC_Start负责真正给ADC上电启动HAL_ADC_PollForConversion会阻塞等待转换结束超时时间设10ms已经足够HAL_ADC_GetValue读到的是右对齐的12位原始码值。注意在F1的HAL库里单次启动后最好调用HAL_ADC_Stop把外设停掉否则一些状态位会残留到下一次启动。轮询模式的缺点是CPU在转换期间被白白占住了只适合低速采样速度要求高或者有多通道刷新需求就得上DMA。3.3 多通道扫描DMA采集真正实用的写法多通道循环采集在工程里最常见CubeMX里做完初始化主程序只需要做两件事把多通道都配进规则组然后启动DMA搬运。// 假设要采集PA0、PA1、PB0三个通道 ADC_ChannelConfTypeDef sConfig {0}; sConfig.Channel ADC_CHANNEL_0; sConfig.Rank ADC_REGULAR_RANK_1; sConfig.SamplingTime ADC_SAMPLETIME_55CYCLES_5; HAL_ADC_ConfigChannel(hadc1, sConfig); sConfig.Channel ADC_CHANNEL_1; sConfig.Rank ADC_REGULAR_RANK_2; HAL_ADC_ConfigChannel(hadc1, sConfig); sConfig.Channel ADC_CHANNEL_8; // 注意PB0对应的是IN8 sConfig.Rank ADC_REGULAR_RANK_3; HAL_ADC_ConfigChannel(hadc1, sConfig); uint16_t adc_buf[3]; HAL_ADC_Start_DMA(hadc1, (uint32_t*)adc_buf, 3);这段代码配合CubeMX里的“扫描模式连续转换DMA循环模式”此后adc_buf[0]对应PA0的值adc_buf[1]对应PA1adc_buf[2]对应PB0硬件会一直自动刷新你只在需要的时候去读数组就行。通道序号需要格外小心PA0~PA7对应IN0~IN7PB0、PB1对应IN8、IN9而PC0~PC5是IN10~IN15不同的封装引脚不一样CubeMX里勾选引脚时它会自动帮你映射但手写代码时非常容易把通道号搞错。特别是PB0新手经常写成ADC_CHANNEL_0或者ADC_CHANNEL_10结果读出来永远是看起来“合理但没意义”的数。缓冲区类型用uint16_t别用uint32_t数组去接收Half Word宽度的DMA转移我之前提到过高半字没数据调试时那串地址里的“脏数据”会让你误以为DMA配错了。4. 数据滤波与抗干扰让读数从“能看”变“能用”4.1 ADC读数为啥会乱跳噪声源逐个排查读ADC最气的不是读不出来而是读出来了但数据一直在跳。这时候先别急着怀疑单片机按下面几个来源逐个排查多数情况下几分钟就能定位。第一个也是最常见的输入引脚悬空。输入什么都没有引脚周围的电磁场耦合、板子上的漏电流都会在内部采样电容上形成随机电压读出来的数当然是杂乱无章的。测试时要么短接到GND要么短接到VCC没有明确电平来源的“空读数”没有任何意义。第二个是电源噪声。ADC的VDDA和VSSA如果没做好去耦开关电源的纹波、LED驱动、电机换相这些瞬态干扰就会直接叠加到参考电平上。注意VDDA不仅是给ADC模拟电路供电它还作为内部转换的参考基准它脏了读数必然跳。第三个是采样时机不巧。比如采样瞬间恰好落在某个开关干扰脉冲上偶尔会读到一个大跳变。这是典型的偶发毛刺软件滤波能消化掉一部分但根治手段还是要用定时器触发把采样点固定到干扰最小的时刻。第四个是地弹和串扰。模拟信号线跟PWM线或SPI时钟线并排走得很长数字边沿的高频分量会通过耦合电容串进模拟输入。这不是软件能完全弥补的必须从Layout层面解决。4.2 硬件层面三板斧去耦、RC滤波与layout硬件上的抗干扰思路其实很朴素让ADC看到的输入电平更干净让参考电压更稳定。第一板斧是电源去耦。VDDA和VSSA之间就近放一个100nF的陶瓷电容最好再并联一个10μF的钽电容或电解电容。如果芯片有独立的Vref引脚同样处理。这个电容不是装饰它是给采样保持电路瞬间抽取电荷用的充电宝。第二板斧是输入RC低通滤波。在信号源到ADC引脚之间串一个电阻、并一个电容到地能有效压制高频噪声。但要算一下截止频率fc 1 ÷ (2πRC)。比如R1kΩ、C10nFfc≈16kHz高于这个频率的有用信号就会被衰减。如果被采信号本身是几千赫兹的音频这个参数没问题如果你采的是一毫秒级别的缓变电压那可以放心把电容加大。加了RC之后还需要重新核算采样时间因为R提高了源阻抗采样电容充电变慢采样周期可能要相应调大。第三板斧是Layout。ADC输入线尽量短而粗远离PWM输出和时钟线模拟地和数字地做单点连接。这些属于PCB设计基本功但在MCU小板上经常被压缩空间牺牲掉事后拿软件滤波去补其实补不回来。4.3 软件滤波算法C语言实现从简易到实用软件滤波是ADC项目里性价比最高的部分有时候一组简单的算法代码就能让读数从“没法看”变成“挺稳”。这里给出几种我在项目里反复用的写法。最简单的是限幅滤波核心思想是真实物理量不会瞬间跳变相邻两次采样差值应该在某个范围内超过阈值就认为新值受到了干扰#define LIMIT_THRESHOLD 50 uint16_t limit_filter(uint16_t last_val, uint16_t new_val) { int16_t diff (int16_t)new_val - (int16_t)last_val; if (diff 0) diff -diff; if (diff LIMIT_THRESHOLD) { return new_val; } return last_val; }中值滤波对付尖峰毛刺最好用取5次采样排序后选中间值能轻松剔除偶发的单点脉冲。代价是需要临时数组和排序开销适合低速采集uint16_t median_filter(uint16_t *buf, uint8_t count) { for (uint8_t i 0; i count - 1; i) { for (uint8_t j i 1; j count; j) { if (buf[j] buf[i]) { uint16_t tmp buf[i]; buf[i] buf[j]; buf[j] tmp; } } } return buf[count / 2]; }滑动平均是我最常用的它相当于一个低通滤波器能有效平滑连续噪声配合循环队列实现还特别省时间#define M_WINDOW 8 uint16_t window_buf[M_WINDOW]; uint8_t window_idx 0; uint32_t window_sum 0; uint16_t moving_average(uint16_t sample) { window_sum - window_buf[window_idx]; window_buf[window_idx] sample; window_sum sample; window_idx (window_idx 1) % M_WINDOW; return (uint16_t)(window_sum / M_WINDOW); }这段代码有个细节它维护的是窗口总和每次滑动只需要一次减法和一次加法不需要重新遍历整个窗口求和。8个点的窗口除以8可以用右移3位进一步优化能省掉除法指令。如果对动态响应有要求可以用一阶低通加权滤波也就是让新值和历史值按比例加权// alpha 1/4 的一阶低通 uint16_t lowpass_filter(uint16_t new_sample, uint16_t last_out) { // y 0.25 * new 0.75 * last return (uint16_t)(((uint32_t)new_sample 3u * last_out) 2); }第一次调用时记得把last_out初始化成第一个采样值否则输出会从0慢慢爬上去看起来像在上电漂移。滤波算法切记不要一个项目全上先找噪声到底是什么形态慢漂移用低通、尖峰用中值、连续抖动用滑动平均对症下药比堆砌算法更有意义。4.4 两点校准与自校准把系统偏差补回来如果你发现读数变化规律正常、也不乱跳但就是和万用表差那么一点点那大概率是系统偏差问题。原因可能是参考电压不是标准的3.3V可能是输入分压电阻有5%误差也可能是ADC内部电路存在增益和偏移误差。这时候就该做校准了。最实用的是两点校准。用两个已知且稳定的电压作为标准点比如0.5V和3.0V分别让ADC采集得到码值adc_low、adc_high。然后线性拟合出真正的电压换算斜率和截距// 通过校准得到V adc_value * cal_gain cal_offset float cal_gain (3.0f - 0.5f) / (float)(adc_high - adc_low); float cal_offset 0.5f - ((float)adc_low * cal_gain); float adc_to_voltage(uint16_t adc_value) { return (float)adc_value * cal_gain cal_offset; }两点校准能同时纠正增益误差和偏移误差前提是系统线性度本身够好。STM32的SAR ADC线性度不错两点校准后的精度足以满足绝大多数传感器采集场景。另外F103的ADC还支持自动校准HAL库里对应函数是HAL_ADCEx_Calibration_Start初始化后调用一次即可。它校准的是ADC内部电路的自有偏差跟外部参考电压的偏差没关系两者不是一回事别搞混。5. 常见问题排查实录与速查表5.1 读数全0先从“配置遗漏”查起ADC值恒为0这是新手最容易遇到的现象。多数情况下不是硬件坏了而是配置层面的遗漏。比如ADC外设的时钟没给比如GPIO引脚没配成模拟输入模式又比如CubeMX里明明勾了PA0但实际接线接到的是PA1。还有一种隐蔽情况配置好之后忘了调用HAL_ADC_Start就开始等转换结果了那DR寄存器里永远是复位值0。遇到全0时我习惯直接看寄存器状态调试点展开hadc1.State看转换是否已经启动再展开hadc1.Instance的SR寄存器看EOC位有没有置1。如果EOC从来没置过1说明转换压根没跑起来问题多半在启动函数或者时钟配置。用调试器的这个习惯能帮你省下大量翻阅代码的时间。5.2 读数满码4095多半是悬空或超量程反过来读到的值永远等于4095那大概率是输入悬空或输入电压超过量程上限。输入悬空很好理解内部采样电容的漏电流会把节点电压往某个方向拉有时凑巧就拉到接近Vref的位置表现为满码。更麻烦的是如果输入端再接了一根很长的测试线感应的交流信号还可能让读数在满码和某些随机值之间来回跳。建议先把输入短接到GND确认系统正常再接真实信号。真正危险的超量程情况也要注意如果输入电压超过Vref读数是满码但如果超得太多通道引脚内部的保护二极管会被强制导通时间长了可能损坏芯片。用分压电阻把信号幅度压到ADC范围内是任何采集项目的第一道工序。5.3 抖动大、漂移明显电源、采样时刻与电磁干扰读数来回跳或者缓慢漂移通常指向三个原因。电源噪声首当其冲。给板子单独供电、断开后期接入的电机或继电器如果读数立刻变稳基本就是电源被干扰了。测试时用示波器夹在VDDA引脚上看转换时刻附近有没有毛刺一抓一个准。采样时间不够也会表现为抖动特别是源阻抗比较大的时候。把采样周期从1.5周期改到55.5周期如果跳变幅度明显下降说明就是充电时间不足。这时候加RC滤波还得重新计算采样时间两者是有联动关系的。还有一类“抖动”其实是采样时刻撞上了周期性的开关干扰比如PWM信号的高频边沿。用定时器触发把采样点移到干扰最小的窗口里配合DMA循环采集往往能立竿见影。5.4 电压换算有偏差从参考电压到源阻抗逐一核对读数稳定但电压算出来和万用表不一致按这个顺序排查先量板子上VDDA的实际电压用这个值替换掉代码里写死的3.3作为分母再用一个精密稳压源做两点校准得到自己的gain和offset最后检查输入分压电阻的精度1%电阻和5%电阻的成本差几毛钱但精度差几条街。源阻抗因素也要排如果ADC输入前面串联了10kΩ以上的电阻去分压采样时间又很短读到的电压会偏低。低频信号下最简单的验证办法是把采样时间调到最大档看读数是否明显变大变大了就说明充电时间不够。5.5 问题速查表现象可能原因快速排查手段解决思路读数恒为0时钟未使能、引脚模式错、未启动转换检查hadc1.State与SR寄存器补齐配置调用链读数恒为4095引脚悬空、输入超量程、通道选错短接输入到GND观察变化接明确电平做分压读数乱跳输入悬空、电源噪声、采样时间不足短接GND、查看VDDA波形增加滤波、调大采样周期电压偏低源阻抗大、采样时间短、参考电压偏小改最大采样时间对比加缓冲器或RC、校准电压偏高参考电压偏大、分压电阻误差实测VDDA用实测值做系数校准多通道数据串位Rank顺序和代码读取顺序不对单通道逐个测试按Rank顺序取数组6. 我的几点实操体会与下一步可以玩的方向我接触STM32的ADC这几年最深的体会是ADC项目绝大多数问题都不是芯片本身造成的而是外部环境把它的“感知能力”破坏了。只要把参考电压、输入阻抗、采样时间、电源去耦这四个基础问题理顺一个裸奔的ADC也能读到很干净的数据。软件滤波是锦上添花不是雪中送炭别指望用一大堆滤波算法去挽救硬件设计上的缺陷。另外一个小建议是调ADC时一定要留一个调试串口把原始码值以十六进制打出来。看到的是0x0FFF还是0x0F90比看到一个已被加工过的“电压浮点数”更能暴露问题。原始码值稳定了再去做滤波、校准、换算电压问题范围一下子就能收缩。如果你已经能把单通道、多通道DMA玩顺下一步可以试试用定时器触发ADC做固定间隔采样配合DMA双缓冲做一个简易的音频波形采集或者利用内部温度传感器和VREFINT通道做一个无需外部传感器的自检功能。再进阶一点结合FFT用这个片上ADC做一个简易的频谱分析仪练手效果非常好。ADC本身是一个很经典的模块但它延伸出来的东西几乎覆盖了信号链路的全部知识值得多花点时间把它吃透。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。