朋友们,在论坛里经常看到有人求助,说STM32的ADC采集电池电压或者传感器数据时,数值总是上下乱跳。其实这未必是硬件设计的问题,很多时候是软件配置没有吃透ADC的工作机制。首先,ADC是一个对时序和电源极其敏感的模拟外设。在每次使能ADC之后,必须严格执行复位校准和启动校准这两个步骤。如果不做校准,内部的电容误差会导致转换结果存在固定的偏差。其次,ADC的时钟频率不能太高,F1系列通常要求APB2分频后不超过14MHz,否则采样精度会大幅下降。
更重要的是,在采集多通道数据时,强烈建议大家放弃在中断里手动读取DR寄存器的做法,而是直接开启DMA传输。让DMA把ADC的数据自动搬运到内存数组里,配合定时器触发采样,这样不仅数据连贯,还能彻底避免因为中断响应不及时导致的数据覆盖问题。硬件校准加上DMA搬运,才是ADC采集的正确打开方式。
当我们把ADC和DMA配合起来使用时,还有一个极其隐蔽的坑等待着新手,那就是多通道扫描模式下的数据错位问题。STM32的ADC数据输出寄存器(DR)是唯一的,当我们在扫描模式下连续转换多个通道时,如果没有开启DMA,后一个通道的转换结果就会无情地覆盖前一个通道的结果。等你在中断里去读取时,拿到的永远是最后一个通道的值。而开启了DMA之后,DMA会自动将每次转换的结果依次存入我们预先分配好的数组中。但这里有一个致命的细节:DMA的外设数据宽度和内存数据宽度必须与ADC的分辨率严格匹配。例如,12位的ADC数据是16位的,如果你的DMA配置成了32位(Word)宽度,DMA每次就会搬运4个字节,这会导致内存中的数组数据发生严重的错位和串台,你读出来的电压值将完全是乱码。
除了数据搬运,ADC采集的精度还极大地依赖于外部模拟电路的设计。ADC内部在采样时,实际上是通过一个极小的采样电容对输入信号进行充电。如果你的信号源内阻非常大(比如直接使用NTC热敏电阻进行分压),而你在软件中配置的采样时间又太短(例如只有1.5个周期),那么这个采样电容根本无法在规定的时间内被充满。最终转换出来的数字量就会严重偏低,并且伴随极大的随机噪声。面对这种高阻抗信号源,我们要么在软件中将采样时间拉长到239.5个周期,要么在硬件上增加一个运算放大器作为电压跟随器来降低输出阻抗。从底层的寄存器宽度匹配,到模拟电路的阻抗分析,ADC的开发从来都不是单纯的写代码,而是软硬件深度协同的艺术。
我要赚赏金
