GD32L233C-START开发板ADC采样精度提升实战:巧用内部1.2V参考电压校准VDD波动
如果你正在用GD32L233C-START开发板做电池供电的传感器节点,或者任何对电压测量精度有要求的项目,大概率遇到过这样的困扰:明明用万用表量着是稳定的3.3V电源,ADC读回来的电压值却总在飘,有时能差出几十毫伏。这问题在低功耗场景下尤其明显——MCU进入休眠再唤醒,VDD电压可能因为负载变化产生微小波动,直接导致你的温度、电池电压采样结果不可靠。
其实,GD32L233C这颗芯片的设计者早就考虑到了这一点,在ADC模块里藏了一个“秘密武器”:一个出厂时校准好的、高度稳定的1.2V内部参考电压源(VREFINT),并且专门引出了一个ADC通道(ADC_IN17)让你能随时读取它。这个设计思路很巧妙——既然VDD会波动,导致ADC的参考电压不准,那我就用一个已知的、稳定的电压作为“标尺”,反过来推算出当前VDD的真实电压值。今天我们就来彻底拆解这个方法的原理,并给出可以直接抄作业的代码实现,以及我在实际项目中踩过的几个坑。
1. 理解问题的根源:为什么VDD波动会让ADC“失准”
在深入代码之前,我们得先搞清楚ADC采样误差的来源。很多工程师会下意识认为,只要给MCU供电的LDO或者DC-DC输出是3.3V,ADC的参考电压就是稳定的3.3V。这个想法在理想情况下成立,但现实中的嵌入式系统要复杂得多。
GD32L233C的ADC模块,其参考电压通常直接连接到芯片的VDD电源引脚(除非你使用了外部参考电压芯片)。这意味着,ADC转换的“满量程”基准就是VDD的实时电压。ADC输出的数字值Dout和输入电压Vin的关系是:
Dout = (Vin / VDD) * (2^N - 1)
其中N是ADC的分辨率位数,对于12位ADC,最大值是4095。从这个公式能直观看出,如果VDD升高,同样的Vin会算出更小的Dout;反之VDD降低,Dout会变大。你的电源哪怕只有1%的波动(33mV),在测量一个1V的信号时,就会引入约10mV的绝对误差,这对于需要精确测量电池电量(例如锂电池从4.2V到3.0V的区间)或者传感器微小电压变化的场景来说,是完全不能接受的。
那么VDD为什么会波动?我总结了几种常见情况:
- 负载瞬变:当MCU从休眠模式唤醒,瞬间电流可能从几个微安跳到几十毫安,电源路径上的寄生电感会导致电压瞬间跌落。
- 电源纹波:尤其是使用开关电源(DC-DC)供电时,即使输出平均电压稳定,也会存在一定频率和幅度的纹波。
- 温度影响:LDO的输出电压会有温漂,虽然很小,但在宽温环境下(-40°C到85°C)累积起来也不容忽视。
- 电池放电:在电池供电设备中,VDD会随着电池电量下降而缓慢降低,这是最需要动态校准的场景。
所以,指望VDD绝对稳定是不现实的。我们需要一种方法,能实时感知VDD的变化,并对ADC采样结果进行补偿。这就是内部参考电压校准登场的时候了。
2. 揭秘GD32L233C的ADC内部通道与校准原理
GD32L233C的ADC模块支持最多10个外部通道(ADC_IN0到ADC_IN9)和4个内部通道。很多开发者只关注外部GPIO连接的通道,却忽略了内部通道这个宝藏。我们通过查阅芯片的数据手册(Datasheet)和参考手册(Reference Manual),可以整理出内部通道的完整信息:
| 内部通道编号 | 信号来源 | 典型用途 | 备注 |
|---|---|---|---|
| ADC_IN16 | 内部温度传感器 | 监测芯片结温 | 输出电压与温度成反比,需配合校准值计算 |
| ADC_IN17 | 内部参考电压 (VREFINT) | VDD动态校准 | 核心!出厂校准的1.2V带隙基准 |
| ADC_IN18 | VBAT/3 | 监测电池电压 | 用于高电压电池直接分压采样 |
| ADC_IN19 | VSLCD/3 | 监测LCD驱动电压 | 用于带LCD驱动的应用 |
今天的主角是ADC_IN17,它连接到一个叫做VREFINT的模块。这是一个基于带隙(Bandgap)原理的电压基准源,它的特点是输出电压非常稳定,几乎不受电源电压和温度变化的影响。GD32在生产测试时,会测量每一颗芯片VREFINT的实际电压值(虽然标称1.2V,但每颗芯片略有差异,比如在1.18V到1.22V之间),并将这个测量时的ADC采样值(我们称为VREFINT_CAL)固化在芯片的系统存储区(System Memory)中。
提示:这个
VREFINT_CAL值是在芯片出厂测试时,在标准的VDD电压(比如3.3V)和温度下,对ADC_IN17通道采样得到的12位原始数据。它是我们进行所有校准计算的“黄金标准”。
校准的核心思想,就是利用这个已知的、稳定的VREFINT电压作为参照物。我们分两步走:
-
实时测量VDD:在代码中,周期性地对ADC_IN17通道进行采样,得到当前VREFINT的ADC原始值
VREFINT_RAW。由于VREFINT的真实电压VREFINT_VOLT是已知的(或从VREFINT_CAL反推),我们就可以利用ADC的公式反推出当前VDD的实际电压:VDD


2686

被折叠的 条评论
为什么被折叠?



