STM32内部参照电压(Vrefint)原理与应用:提升ADC测量精度的工程实践
2026/6/5 14:21:51 网站建设 项目流程

1. 项目概述:为什么需要关注STM32的内部参照电压?

在嵌入式开发,尤其是涉及模拟信号采集的项目里,ADC(模数转换器)的精度是绕不开的话题。很多工程师在调试时发现,明明代码逻辑正确,但ADC读回来的电压值就是飘忽不定,或者在不同供电条件下测出的结果不一致。这时候,大家往往会去检查外部基准源、电源纹波或者PCB布局,却常常忽略了一个芯片内部自带的“标尺”——内部参照电压(Internal Reference Voltage)。

这个参照电压,在STM32的ADC1中固定映射到通道17(或某些系列是通道18)。它不是给ADC提供参考电压的Vref+,而是一个独立、稳定的内部电压源,典型值在1.20V左右。它的核心价值在于其稳定性:相比容易受到外部供电(VCC/VDD)波动、负载变化、走线干扰影响的ADC参考电压,这个内部参照电压由芯片内部的带隙基准源(Bandgap Reference)产生,其值几乎不随外部供电电压和温度(在一定范围内)的变化而剧烈波动。这就好比一把刻度会热胀冷缩的尺子(外部Vref)和一把用特殊材料制成的、刻度基本不变的尺子(内部Vrefint),当我们需要精确测量时,当然更信任后者。

因此,这个功能主要解决两个核心痛点:一是当系统没有使用高精度外部基准电压源,而是采用VCC作为ADC参考电压(常见于引脚较少的封装)时,如何补偿VCC波动带来的测量误差;二是在一些对成本敏感或空间受限的应用中,如何在不增加外部元件的前提下,尽可能地提升ADC测量的相对精度。它并不旨在实现绝对的高精度测量(那需要外部基准源),而是提供一种“自校准”机制,让测量结果更可靠、更一致。接下来,我将结合多年项目经验,从设计思路到代码实现,再到避坑指南,为你完整拆解这个功能的正确使用姿势。

2. 核心原理与设计思路拆解

2.1 参照电压与ADC参考电压的根本区别

这是最容易混淆的概念,必须首先厘清。很多初学者看到“参考”二字就以为是一回事,其实它们在芯片内部扮演着完全不同的角色。

ADC参考电压(Vref+):这是ADC转换器的“满量程基准”。ADC的工作原理是将输入引脚(Vin)的模拟电压与这个参考电压进行比较和量化。公式可以简化为Digital Output = (Vin / Vref+) * (2^N - 1),其中N是ADC的分辨率(如12位)。如果Vref+是3.3V,那么0V对应数字量0,3.3V对应数字量4095(12位时)。Vref+的稳定性直接决定了ADC的绝对精度。在STM32中,对于引脚数较多的型号(如100脚以上),Vref+是一个独立的引脚,可以连接一个干净、稳定的外部电压基准(如2.5V的REF3025)。而对于小封装型号(如64脚及以下),为了节省引脚,Vref+在内部直接与MCU的电源VCC相连。这意味着,当你的系统电源因为电机启动、无线模块发射等原因产生跌落或纹波时,ADC的“尺子”本身就在伸缩,测量结果自然不准。

内部参照电压(Vrefint):这是一个由芯片内部电路产生的、相对稳定的电压信号,其典型值约为1.20V。它不是ADC的参考电压,而是作为ADC的一个普通输入信号,被连接到了ADC的一个固定内部通道(通常是ADC1的通道17)。你可以像测量外部引脚电压一样,去测量这个内部电压源的ADC转换值。它的价值在于其稳定性优于一般的VCC。当Vref+(可能是VCC)变化时,你用ADC去测量一个稳定的外部电压(比如一个分压得到的1.0V),读数和用ADC去测量内部Vrefint的读数,会受到相同比例的影响。利用这个关系,我们就可以反推出真实的电压值。

注意:Vrefint的绝对精度并不高,数据手册给出的典型值是1.20V,但最小值可能是1.16V,最大值是1.24V,存在±40mV的初始误差。因此,它不适合用于需要知道绝对电压值的场景(例如,你需要精确知道电池电压是3.65V还是3.70V),但它非常适合于需要相对精度比率测量的场景(例如,监测一个电阻分压网络的比值变化来判断位置、压力等)。

2.2 校准公式的推导与理解

项目正文中给出的公式是核心:V_chx = V_refint * (AD_chx / AD_refint)。我们来深入理解一下这个公式是如何来的,以及为什么它能消除Vref+波动的影响。

假设:

  • V_refint是内部参照电压的真实值(一个接近1.20V的恒定值)。
  • V_chx是我们待测通道的外部电压真实值。
  • V_ref+是ADC当前的参考电压(可能等于波动的VCC)。
  • AD_refint是ADC测量Vrefint通道得到的数字量。
  • AD_chx是ADC测量外部通道得到的数字量。

根据ADC的转换原理,对于12位ADC:AD_refint = (V_refint / V_ref+) * 4095AD_chx = (V_chx / V_ref+) * 4095

注意,这两个公式中的V_ref+是同一个值,因为它发生在同一时刻、同一个ADC模块上。我们将第二个公式除以第一个公式:

AD_chx / AD_refint = (V_chx / V_ref+) / (V_refint / V_ref+) = V_chx / V_refint

看,V_ref+被完美地约掉了!这个比值不再依赖于波动的ADC参考电压。于是我们得到:

V_chx = V_refint * (AD_chx / AD_refint)

设计思路的精髓就在这里:我们通过同时测量一个稳定的内部电压(Vrefint)和一个外部未知电压,利用它们的ADC读数之比,来抵消掉公共的、不稳定的参考电压(Vref+)的影响。最终结果的精度,主要取决于Vrefint的稳定性,以及ADC本身的比例线性度。STM32的ADC在比例线性度方面通常表现很好。

2.3 适用场景与局限性分析

理解了原理,我们就能更准确地判断何时该用这个功能。

非常适合的场景:

  1. 电池供电设备的电池电压监测:设备用VCC直接给MCU供电,同时用电阻分压来监测电池电压。当电池放电导致VCC缓慢下降时,用此方法可以准确计算出电池电压的真实下降曲线,而不受VCC下降带来的测量误差影响。
  2. 电阻式传感器测量(如热敏电阻、应变片):传感器通常组成分压电路,MCU测量的是分压点的电压。使用内部参照电压法,可以消除供电电压波动对分压比的影响,从而更精确地反推电阻值。
  3. 内部温度传感器补偿:正如项目正文提到的,STM32的内部温度传感器输出电压与温度成线性关系,但其斜率与Vref+(或VCC)有关。使用内部参照电压进行校准,可以显著提高温度测量的准确性。
  4. 成本与空间极度敏感的应用:无法容纳外部基准电压芯片,但又需要比“裸测”更高一致性的场合。

不适用或效果有限的场景:

  1. 需要高绝对精度的测量:例如,精密电子秤、高精度数据采集系统。Vrefint自身的初始误差(±40mV)和温漂会直接成为系统误差。
  2. Vref+非常稳定:如果你已经使用了高质量的外部基准电压源(如REF5025),其稳定性远优于内部Vrefint,那么直接使用ADC读数换算即可,无需多此一举。
  3. 超低功耗模式下的快速采样:启用内部参照电压需要一定的稳定时间,会增加采样周期和功耗。在需要极速或极低功耗采样的场景需权衡。

3. 硬件连接与ADC配置要点

3.1 硬件设计注意事项

虽然内部参照电压是芯片内部的信号,但硬件设计的好坏依然会影响其测量效果。

电源去耦是重中之重:即使我们使用内部参照电压来抵消Vref+(VCC)波动的影响,但极度恶劣的电源噪声仍可能通过其他途径干扰ADC和内部基准源电路。务必在MCU的每个VDD/VSS电源引脚附近放置一个100nF的陶瓷电容,并在电源入口处放置一个10μF的钽电容或电解电容。对于模拟部分(VDDA、VSSA),建议使用独立的磁珠或0Ω电阻从数字电源隔离,并搭配1μF和10nF的并联去耦电容。

优化PCB布局

  • 将ADC采样的外部信号走线远离数字信号线(如时钟、PWM、数据总线),特别是高频信号线。
  • 如果采样信号来自板载分压电阻,请将这些电阻尽量靠近MCU的ADC输入引脚,并用地线包围保护。
  • 对于高阻抗信号源,需要考虑ADC采样时间对输入信号建立的影响,必要时可增加一个小的滤波电容(如100pF)或使用运放进行缓冲。

理解不同封装的Vref+连接:这是硬件设计的基础。在设计原理图时,必须查阅你所使用型号的数据手册(Datasheet)和引脚定义图(Pinout)。

  • 对于有独立Vref+引脚的型号:强烈建议将此引脚连接到一个干净、稳定的基准电压源。即使你计划使用内部参照电压校准,一个稳定的Vref+也能让ADC工作在线性度最佳的区域。如果暂时不用,可以将其连接到VDDA。
  • 对于Vref+内部连接VCC的型号:这意味着整个系统的电源质量直接决定了ADC的“原始精度”。需要更加重视电源网络的设计,确保VCC在MCU引脚处的纹波尽可能小。

3.2 ADC初始化与通道配置详解

以STM32F1系列和HAL库为例,讲解具体的配置步骤和参数选择。其他系列(F4, H7, G0等)原理类似,寄存器或LL库的配置逻辑相通。

步骤一:ADC外设初始化首先,需要初始化ADC的基础参数。关键点在于参考电压的选择,这里我们需要做特殊设置,因为Vref+的连接是硬件决定的。我们需要关注的是采样时间和分辨率。

// 假设使用ADC1 ADC_HandleTypeDef hadc1; 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; // 转换序列数为1 // 关键参数:分辨率。12位提供最高精度。 hadc1.Init.Resolution = ADC_RESOLUTION_12B; if (HAL_ADC_Init(&hadc1) != HAL_OK) { Error_Handler(); }

步骤二:配置采样通道(包括Vrefint通道)内部参照电压通道在STM32中通常需要单独使能。在HAL库中,它被抽象为一个内部通道。

// 配置用于测量外部电压的通道(例如,ADC1的通道0,对应PA0引脚) ADC_ChannelConfTypeDef sConfig = {0}; sConfig.Channel = ADC_CHANNEL_0; // 外部通道 sConfig.Rank = ADC_REGULAR_RANK_1; // 序列中的第一个(也是唯一一个) sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; // 采样时间 // 采样时间是关键!对于高阻抗源或需要高精度时,需要更长的采样时间。 // 239.5个周期是F1系列较长的选择,可以确保采样电容充分充电。 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } // 特别注意:内部参照电压通道(VREFINT)在每次测量前都需要重新配置。 // 因为它不是一个固定的外设引脚映射,而是一个内部信号源。 // 通常,我们会写一个专门的函数来测量Vrefint。

实操心得:ADC的采样时间(Sampling Time)对精度影响巨大。时间太短,采样电容未充满,读数会偏小且不稳定;时间太长,则降低转换速率。规则是:信号源阻抗越高,所需的采样时间越长。对于内部Vrefint通道,由于其驱动能力较强,可以使用相对较短的采样时间(如71.5个周期)。但对于外部高阻抗分压电路,必须使用更长的采样时间(如239.5个周期)。最佳值需要通过实验确定:观察一个稳定电压的ADC读数,不断增加采样时间,当读数不再显著增加时,即为合适值。

4. 软件实现:校准测量流程与代码实战

软件实现的核心是组织一个正确的测量流程:先测Vrefint,再测目标通道,然后套用公式计算。这里提供两个层次的代码示例:基础单次测量和带平均滤波的稳健测量。

4.1 基础单次测量函数实现

首先,我们需要一个专门函数来获取内部参照电压的ADC原始值。注意,在STM32的HAL库中,需要先使能内部参照电压通道。

/** * @brief 读取内部参照电压(Vrefint)的ADC原始值 * @param hadc: ADC句柄指针 * @retval Vrefint的ADC原始值(0-4095),若失败返回0 */ uint32_t Read_Vrefint_ADC(ADC_HandleTypeDef* hadc) { ADC_ChannelConfTypeDef sConfig = {0}; uint32_t adc_value = 0; // 1. 配置ADC通道为内部Vrefint通道 // 对于STM32F1,内部Vrefint通道是ADC_CHANNEL_VREFINT // 对于其他系列,可能是ADC_CHANNEL_VREFINT或ADC_CHANNEL_REFSENSOR,需查手册 sConfig.Channel = ADC_CHANNEL_VREFINT; sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5; // Vrefint驱动能力强,时间可短些 if (HAL_ADC_ConfigChannel(hadc, &sConfig) != HAL_OK) { return 0; // 配置失败 } // 2. 启动ADC,开始转换 HAL_ADC_Start(hadc); // 3. 等待转换完成,超时时间根据ADC时钟设置,通常10ms足够 if (HAL_ADC_PollForConversion(hadc, 10) == HAL_OK) { // 4. 读取转换结果 adc_value = HAL_ADC_GetValue(hadc); } // 5. 停止ADC HAL_ADC_Stop(hadc); return adc_value; }

接下来,实现一个使用Vrefint进行校准的电压测量函数。

/** * @brief 使用内部参照电压法,测量指定ADC通道的电压值 * @param hadc: ADC句柄指针 * @param channel: 要测量的外部ADC通道(如ADC_CHANNEL_0) * @param samplingTime: 该外部通道建议的采样时间 * @retval 计算得到的电压值,单位:伏特(V) */ float Measure_Voltage_With_Vrefint(ADC_HandleTypeDef* hadc, uint32_t channel, uint32_t samplingTime) { ADC_ChannelConfTypeDef sConfig = {0}; uint32_t adc_value_vrefint = 0; uint32_t adc_value_channel = 0; float voltage_calculated = 0.0f; const float VREFINT_CALIB_VALUE = 1.20f; // 典型值,可从芯片Flash特定地址读取更准 // --- 第一步:测量内部参照电压Vrefint的ADC值 --- adc_value_vrefint = Read_Vrefint_ADC(hadc); if (adc_value_vrefint == 0) { return -1.0f; // 测量Vrefint失败 } // --- 第二步:测量目标外部通道的ADC值 --- // 重新配置通道为外部目标通道 sConfig.Channel = channel; sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = samplingTime; // 使用传入的采样时间 if (HAL_ADC_ConfigChannel(hadc, &sConfig) != HAL_OK) { return -1.0f; } HAL_ADC_Start(hadc); if (HAL_ADC_PollForConversion(hadc, 10) == HAL_OK) { adc_value_channel = HAL_ADC_GetValue(hadc); } HAL_ADC_Stop(hadc); // --- 第三步:应用公式计算真实电压 --- // 公式:V_channel = VREFINT_CALIB * (adc_value_channel / adc_value_vrefint) // 为防止整数除法丢失精度,先转换为浮点数 if (adc_value_vrefint > 0) // 避免除零错误 { voltage_calculated = VREFINT_CALIB_VALUE * ((float)adc_value_channel / (float)adc_value_vrefint); } else { voltage_calculated = 0.0f; } return voltage_calculated; }

使用示例

// 在主循环或某个任务中调用 float battery_voltage; // 假设电池电压通过分压连接到PA0 (ADC1_IN0),分压比为2:1,采样时间用长的。 battery_voltage = Measure_Voltage_With_Vrefint(&hadc1, ADC_CHANNEL_0, ADC_SAMPLETIME_239CYCLES_5); // 注意:battery_voltage是分压点电压,实际电池电压需要乘以分压比(例如乘以3)。 printf("Measured Voltage: %.3f V\r\n", battery_voltage * 3);

4.2 进阶:提升精度与稳定性的工程化技巧

上面的基础函数在理想情况下可用,但在实际工程中,噪声、ADC非线性、Vrefint本身波动都会引入误差。以下是几个提升测量质量的实用技巧。

技巧一:使用出厂校准值替代典型值STM32芯片在出厂时,会在系统存储区(通常是Flash的特定地址)存储一个校准值。这个值是芯片在3.3V Vref+、30°C条件下实测得到的Vrefint的ADC转换值(通常记为VREFINT_CAL)。使用这个值比使用1.20V的典型值准确得多,因为它补偿了芯片之间的个体差异。

对于STM32F1,这个值通常在0x1FFFF7BA(小端序,16位数据)。我们可以这样读取:

// 对于STM32F103,从指定地址读取Vrefint校准值 #define VREFINT_CAL_ADDR ((uint16_t*) (0x1FFFF7BA)) uint16_t vrefint_calibrated_value = *VREFINT_CAL_ADDR; // 计算电压时,公式演变为: // V_channel = 3.3V * (adc_value_channel / vrefint_calibrated_value) // 因为出厂时是在Vref+=3.3V下测得的vrefint_calibrated_value。 // 但注意!这个方法的前提是你当前的Vref+也必须是3.3V。 // 如果你的Vref+是其他值(比如3.0V),或者Vref+连接的是变化的VCC,这个方法就失效了。 // 因此,在Vref+不固定时,我们仍然需要采用“比值法”,但可以结合校准值来得到更准的Vrefint真实值。

更通用的方法是,利用这个校准值和当前测得的Vrefint ADC值,来反推出当前实际的Vref+电压,然后再用这个Vref+去计算外部通道电压。这适用于Vref+固定但非3.3V的情况。但对于Vref+变化(VCC供电)的场景,我们最初介绍的比值法仍然是主流。

技巧二:多次采样与数字滤波ADC单次采样值易受噪声干扰。对Vrefint通道和目标通道都进行多次采样取平均,能有效抑制随机噪声。

#define SAMPLE_TIMES 64 // 采样次数,取2的幂次便于计算 uint32_t Get_ADC_Average(ADC_HandleTypeDef* hadc, uint32_t channel, uint32_t samplingTime, uint8_t times) { ADC_ChannelConfTypeDef sConfig = {0}; uint32_t sum = 0; sConfig.Channel = channel; sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = samplingTime; HAL_ADC_ConfigChannel(hadc, &sConfig); for(uint8_t i=0; i<times; i++) { HAL_ADC_Start(hadc); HAL_ADC_PollForConversion(hadc, 1); sum += HAL_ADC_GetValue(hadc); HAL_ADC_Stop(hadc); // 可在此处加入短暂延时,尤其在高采样率时,让ADC前端电路恢复 // HAL_Delay(1); } return (sum + times/2) / times; // 四舍五入 } // 改进后的测量函数 float Measure_Voltage_With_Vrefint_Robust(ADC_HandleTypeDef* hadc, uint32_t channel, uint32_t samplingTime) { uint32_t adc_vrefint_avg, adc_ch_avg; const float VREFINT_TYPICAL = 1.20f; // 测量Vrefint平均值 adc_vrefint_avg = Get_ADC_Average(hadc, ADC_CHANNEL_VREFINT, ADC_SAMPLETIME_71CYCLES_5, SAMPLE_TIMES); // 测量外部通道平均值 adc_ch_avg = Get_ADC_Average(hadc, channel, samplingTime, SAMPLE_TIMES); if(adc_vrefint_avg == 0) return 0.0f; return VREFINT_TYPICAL * ((float)adc_ch_avg / (float)adc_vrefint_avg); }

技巧三:合理安排测量顺序与时机为了最大程度抵消Vref+在两次测量期间发生的微小变化,应尽可能缩短测量Vrefint和测量目标通道的时间间隔。最好在一次“测量会话”中连续完成。避免在两次测量中间插入长时间的任务或中断。如果系统中有大功率负载周期性工作(如电机、射频模块),应避开其开启时段进行ADC采样,或在其稳定后再采样。

5. 典型应用案例:电池电压监测与内部温度传感器

5.1 高精度电池电压监测方案

在便携式设备中,准确监测电池电压至关重要。假设系统由单节锂离子电池(标称3.7V,满电4.2V,截止2.8V)通过LDO降压到3.3V给MCU供电。我们使用一个电阻分压网络(例如,R1=100k, R2=33k,分压比约0.248)将电池电压降到ADC量程内,连接到MCU的ADC引脚。

挑战:电池放电时,其电压下降,同时LDO输入电压也下降。虽然LDO输出(MCU的VCC)能稳定在3.3V,但很多小封装MCU的Vref+内部连接的是VCC之前的电源网络(或就是VCC本身),实际上会随着电池电压轻微波动。直接测量分压点电压再乘以分压比,得到的电池电压会包含Vref+波动引入的误差。

解决方案:使用内部参照电压法。

  1. 测量分压点电压V_sense(校准后的值)。
  2. 计算电池电压V_bat = V_sense * ( (R1+R2) / R2 )

由于V_sense是通过Vrefint校准得到的,已经消除了Vref+波动的影响,因此计算出的V_bat能更真实地反映电池电压的变化。代码实现就是前面Measure_Voltage_With_Vrefint_Robust函数的直接应用。

注意事项:分压电阻的精度和温漂会直接影响最终结果的绝对精度。如果对绝对精度要求高,需选择1%精度、低温度系数的精密电阻。此外,分压电阻会持续消耗电池电量(本例中约4.2V/(133k)≈31.6μA),在待机功耗要求极低的场景需要权衡,或采用MOSFET在测量时才接通分压电路。

5.2 内部温度传感器的校准与使用

STM32芯片内部集成了一个温度传感器,它产生一个随温度变化的电压(VSENSE)。这个电压同样被连接到ADC的一个内部通道(通常与Vrefint通道不同,例如ADC1_CHANNEL_16)。数据手册会给出其典型参数:在30°C时输出电压典型值(如1.43V),以及平均斜率(如4.3mV/°C)。

原始计算公式Temperature = ( (V30 - VSENSE) / Avg_Slope ) + 30其中,V30是30°C时的典型电压值,VSENSE是ADC测得的传感器电压,Avg_Slope是负的斜率(温度升高,电压下降)。

问题所在:公式中的VSENSE是ADC的原始读数换算成的电压,这个换算依赖于Vref+。如果Vref+波动,计算出的VSENSE就不准,温度结果自然也不准。

校准方案:在计算VSENSE时,使用内部参照电压法进行校准。

  1. 使用比值法,测量得到校准后的内部温度传感器电压值VSENSE_calVSENSE_cal = VREFINT_TYPICAL * (AD_tempsensor / AD_refint)
  2. VSENSE_cal代入上述温度计算公式。

这样,温度计算就与波动的Vref+解耦了。实测表明,经过此方法校准后,STM32内部温度传感器的精度可以从原来的±10°C提升到±2~3°C左右,对于监测芯片结温、进行温度补偿等应用已经足够。

代码示例片段

float Read_Temperature_Calibrated(ADC_HandleTypeDef* hadc) { uint32_t adc_temp, adc_vrefint; float vsense_cal, temperature; const float VREFINT = 1.20f; const float V30 = 1.43f; // 请替换为具体型号数据手册中的值 const float Avg_Slope = 0.0043f; // 4.3mV/°C,请替换为具体型号数据手册中的值 // 获取温度传感器和Vrefint的ADC原始值(建议取平均) adc_temp = Get_ADC_Average(hadc, ADC_CHANNEL_TEMPSENSOR, ADC_SAMPLETIME_239CYCLES_5, 64); adc_vrefint = Get_ADC_Average(hadc, ADC_CHANNEL_VREFINT, ADC_SAMPLETIME_71CYCLES_5, 64); if (adc_vrefint == 0) return -273.15f; // 错误,返回绝对零度 // 计算校准后的传感器电压 vsense_cal = VREFINT * ((float)adc_temp / (float)adc_vrefint); // 计算温度 temperature = ((V30 - vsense_cal) / Avg_Slope) + 30.0f; return temperature; }

6. 常见问题、调试技巧与避坑指南

即使理解了原理,编写了代码,在实际调试中仍然会遇到各种问题。下面是我在多个项目中总结的常见坑点及解决方案。

6.1 读数不稳定或跳动大

这是最常见的问题。可能的原因和解决思路如下表所示:

现象可能原因排查方法与解决方案
读数在小范围内无规律跳动ADC本身噪声或电源噪声1.软件滤波:如前所述,多次采样取平均、中值滤波。
2.硬件滤波:检查并加强电源去耦,在ADC输入引脚对地添加一个100pF~10nF的电容(注意:会降低输入阻抗,可能影响采样时间)。
3.降低时钟:适当降低ADC时钟(ADCCLK),可以提高信噪比。STM32的ADC时钟最好不超过14MHz(F1系列)。
读数呈周期性规律波动系统存在周期性干扰源1.定位干扰源:可能是PWM、定时器中断、通信接口(SPI/I2C)或电机驱动等。尝试关闭这些外设观察。
2.错开采样时机:在干扰源的静默期进行ADC采样。
3.物理隔离:优化PCB布局,让模拟走线远离干扰源。
测量Vrefint和外部通道的读数比例不稳定两次测量间隔过长,Vref+已发生变化1.缩短间隔:将测量Vrefint和测量外部通道的代码紧挨着执行,中间不要插入其他任务或长延时。
2.使用DMA+双通道扫描:高级用法。配置ADC在扫描模式下,依次转换Vrefint通道和外部通道,并用DMA自动搬运数据。这样可以确保两个通道的转换几乎同时完成,最大程度抵消Vref+变化。
读数始终为0或4095通道配置错误或信号超量程1.检查通道号:确认外部通道号与引脚对应关系正确,内部Vrefint通道号正确(查数据手册)。
2.检查引脚模式:ADC引脚应配置为模拟输入,无上拉下拉。
3.检查信号电压:用万用表测量ADC输入引脚电压,确认其在0-Vref+范围内。

6.2 测量结果存在固定偏差

如果测量一个已知的、稳定的基准电压(如TL431输出的2.5V),发现结果总是偏大或偏小一个固定比例。

  • 原因一:Vrefint典型值不准。1.20V只是典型值,你的芯片实际值可能是1.18V或1.22V。这是系统性的比例误差。
    • 解决方案:如果条件允许,可以进行一次“单点校准”。在已知Vref+稳定(例如,使用精密外部基准源)的情况下,测量Vrefint的ADC值,反推出该芯片实际的Vrefint电压值,并存储到Flash中,后续使用这个校准值。或者,直接使用前面提到的出厂校准值VREFINT_CAL来推算(需在Vref+固定的前提下)。
  • 原因二:分压电阻精度误差。如果你测量的是经过分压的信号,电阻的精度误差会导致固定比例偏差。
    • 解决方案:使用更高精度的电阻(1%或0.1%),或者在产品出厂前进行软件校准,测量一个标准电压并计算出一个校准系数。

6.3 低功耗模式下的使用注意事项

在需要ADC间歇性工作的低功耗项目中,需要注意:

  1. 唤醒与稳定时间:从低功耗模式唤醒ADC和内部参照电压源需要时间。在启动ADC转换前,必须插入足够的延时,或者查询ADC/参照电压的就绪标志位。具体时间请参考芯片数据手册的“ADC启动时间”和“内部参照电压稳定时间”。
  2. 功耗权衡:内部参照电压电路本身会消耗一定的电流(通常为几十μA)。如果设备处于深度睡眠状态,仅靠RTC唤醒进行极低频度的采样,可能需要考虑在每次采样后完全关闭参照电压和ADC,以节省电量。
  3. 代码示例(HAL库)
    // 进入低功耗前 HAL_ADC_Stop(&hadc1); HAL_ADC_DeInit(&hadc1); __HAL_RCC_ADC1_CLK_DISABLE(); // 关闭ADC时钟 // ... 进入STOP模式等 // 唤醒后 __HAL_RCC_ADC1_CLK_ENABLE(); MX_ADC1_Init(); // 重新初始化ADC HAL_Delay(10); // 等待内部电压稳定,时间需实测调整 // 再进行测量

6.4 关于不同STM32系列的差异

不同系列的STM32,内部参照电压的使用细节可能有差异,务必查阅对应型号的参考手册(Reference Manual)

  • 通道编号:大多数系列Vrefint连接在ADC1的通道17,但有些系列(如某些L0/L4)可能在通道0或通道18。温度传感器通道也不同。
  • 校准值地址:出厂校准值VREFINT_CAL的存储地址因系列和型号而异。在参考手册的“ADC”章节或“芯片唯一ID与校准值”章节可以找到。
  • 使能方式:除了在ADC通道配置中选中,有些系列可能需要通过ADC的CCR(通用控制寄存器)中的特定位(如VREFEN)来使能内部参照电压源。HAL库的ADC_CHANNEL_VREFINT宏通常会处理这些细节,但若使用LL库或寄存器操作,则需要留意。

最后的建议:在项目初期,务必搭建一个简单的测试电路,用可调稳压源或已知精度的电池作为输入,用万用表作为基准,来验证你的内部参照电压测量方案的准确性和稳定性。通过串口打印出原始ADC值、计算后的电压值,与万用表读数对比。这个过程能帮你快速定位是硬件问题、配置问题还是算法问题,是确保方案可靠的必经之路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询