尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

STM32内部温度传感器供电漂移8℃的根因定位与VREFINT比例校准实测

STM32内部温度传感器供电漂移8℃的根因定位与VREFINT比例校准实测 文章目录摘要一、一个甩锅现场内部温度传感器到底准不准二、原理拆解为什么 VDDA 漂会让温度漂2.1 温度传感器这一路是怎么算的2.2 VREFINT 为什么能当标尺2.3 一张图看懂两者的区别三、硬件准备这个实验居然不用接线四、软件配置CubeMX 里要多勾一个通道4.1 ADC 配置要点4.2 使能内部通道F1 特有的一个寄存器位五、核心代码两个版本的对比才能看出差距六、测试验证把供电拉偏看读数漂多少6.1 校准前后对比数据6.2 理论 vs 实测对照七、故障排查这 6 类问题我基本都遇到过7.1 温度读数恒定不动像死了一样7.2 温度明显偏低且一直偏低7.3 CH17 一直读到 07.4 校准后读数仍随供电小幅波动7.5 串口打印乱码7.6 长时间运行温度缓慢上飘八、总结核心要点适用边界扩展方向参考资料摘要STM32 片内温度传感器无需任何外围器件就能测芯片结温但很多开发者发现同一块板子换个供电或插拔 USB 后读数能差好几度于是武断地认为内部温度传感器就是不准只能凑合用。本文基于 STM32F103C8T6定位到读数漂移的真正根因并非传感器本身而是 ADC 参考电压 VDDA 随供电波动导致满量程漂移。通过同时采集温度通道 CH16 与内部参考电压通道 CH17用 VREFINT 做比例校准把供电从 3.30V 拉偏到 2.95V 时温度读数漂移从8.2℃ 收敛到 0.4℃。文中给出完整的 CubeMX 配置、双通道采集代码和校准前后对比数据。一、一个甩锅现场内部温度传感器到底准不准先说结论免得你被网上各种内部温度传感器不准的说法带偏STM32 内部温度传感器的绝对精度确实不高手册标称 ±1.5~±2℃但它最大的问题往往不是传感器本身而是测量链路里的参考电压在捣乱。我最早在做一个电池供电的温控小项目时踩过这个坑。板子用 USB 供电调试一切正常串口打印温度 25.3℃稳定得让人放心。结果拿到现场用锂电池 LDO 供电温度读数直接跳到 33℃ 上下我还以为固件写错了查了半天代码一无所获。直到用万用表量了 VDDA 引脚电压——标称 3.3V 的 LDO实际输出只有 2.96V。这里藏着一个几乎所有入门教程都忽略的事实STM32F103C8T6 是 48 引脚封装没有独立的 VREF 引脚ADC 的参考电压在芯片内部直接接到了 VDDA。VDDA 一旦漂ADC 的满量程就跟着漂而你换算电压时写死的那个 3.3V 就变成了一笔糊涂账。相关阅读《STM32电源之Vref(ADC的参考电压)》 — 讲清楚了 64Pin 及以下封装 VREF 与 VDDA 内部直连的问题。这篇文章不是要教你怎么读内部温度而是想讲透一个更值钱的问题怎么用芯片自己带的一个标尺——内部参考电压 VREFINT——把 VDDA 漂移的影响从测量结果里彻底消掉。二、原理拆解为什么 VDDA 漂会让温度漂2.1 温度传感器这一路是怎么算的STM32F103 的内部温度传感器连在 ADC1 的 CH16 上本质是一个负温度系数的模拟量——结温越高输出电压越低。数据手册给出的换算公式是T (V25 − Vsense) / Avg_Slope 25其中 V25 是 25℃ 时的输出电压典型值 1.43VAvg_Slope 是温度系数典型值 4.3mV/℃。注意这两个数都是典型值不同芯片有 ±1.5% 左右的离散这就是内部温度传感器绝对精度有限的根本原因。而 Vsense 是当前温度对应的电压它要靠 ADC 的读数反推出来Vsense ADC值 / 4096 × VDDA问题就出在这个× VDDA上。你的代码里 VDDA 十有八九写死成了 3.3V可实际的 VDDA 是多少插着 USB 调试时可能是 3.28V用 LDO 供电时可能是 2.96V用 3.7V 锂电池直接经 DC-DC 升压时甚至可能到 3.6V。2.2 VREFINT 为什么能当标尺好消息是STM32 在芯片内部还内置了一个参考电压源 VREFINT它连在 ADC1 的 CH17 上典型值 1.20V并且这个电压几乎不随 VDDA 的变化而变化——它是由芯片内部的带隙基准bandgap产生的与供电解耦。既然 VREFINT 的真实值是固定的约 1.20V那我们就能反推出 ADC 转换当下的真实满量程。核心思路是比例法ADC 同时采 CH16 温度和 CH17 VREFINTCH17 读数已知对应真实 1.20V用比例换算温度通道电压Vsense 1.20 × ADC16 / ADC17温度公式T (1.43 - Vsense)/0.0043 25VDDA 项被完全消掉供电漂移不再影响读数推导其实就两步。设 ADC 是 12 位、参考电压为 VDDA那么CH17 读数 1.20V / VDDA × 4096 ① CH16 读数 Vsense / VDDA × 4096 ②② 除以 ①VDDA 和 4096 全部约掉Vsense 1.20V × (CH16读数 / CH17读数)VDDA 彻底从公式里消失了。这就是 VREFINT 比例校准的本质——你不再需要关心 VDDA 具体是多少因为它在分子分母里互相抵消。2.3 一张图看懂两者的区别对比项直接换算法错误姿势VREFINT 比例校准正确姿势依赖 VDDA 实际值写死 3.3V实际漂了就错不需要知道 VDDA供电波动影响满量程漂移 → 读数跳变被比例抵消额外成本无多采一路 CH17剩余误差来源VDDA 波动 典型值离散仅典型值离散三、硬件准备这个实验居然不用接线内部温度传感器和 VREFINT 都在芯片内部所以不需要接任何外部传感器和基准源这是它最大的便利。但正因为如此供电这件事就变得格外关键——实验里我要人为制造 VDDA 波动来复现并验证校准效果。我用了一块最常见的 STM32F103C8T6 最小系统板供电方案如下供电来源实际 VDDA 实测值用途USB 5V → 板载 AMS1117-3.33.30V基准工况可调 DC 电源直接给 3.3V 轨2.95V模拟 LDO 压降/电池低电量可调 DC 电源直接给 3.3V 轨3.60V模拟 DC-DC 过冲⚠️ 提醒一句直接把外部电源怼到 3.3V 轨上做实验时务必断开 USB 和板载 LDO 的输出否则两个电源会打架。VDDA 的绝对上限是 4.0V3.60V 仍在安全范围内但别手滑调更高。四、软件配置CubeMX 里要多勾一个通道4.1 ADC 配置要点用 STM32CubeMX 建工程时ADC1 的配置和普通单通道采集有一个关键区别——必须同时把 Temperature Sensor ChannelCH16和 Vrefint ChannelCH17两个内部通道都勾上否则后面比例法没数据可用。具体参数这样配Clock PrescalerPCLK2 6 分频72MHz/6 12MHz满足 ADC 最高 14MHz 限制Scan Conversion ModeEnable要连续采两个通道必须开扫描Continuous Conversion ModeEnable连续转换方便轮询读取Discontinuous Conversion ModeDisableNumber of Conversion2Rank 1Channel 16Temperature SensorSampling Time 239.5 CyclesRank 2Channel 17VrefintSampling Time 239.5 Cycles采样时间这里有个容易踩的坑内部温度传感器要求采样时间 ≥ 17.1μs对应 12MHz 时钟下 239.5 个周期。如果采样时间设短了读出来的温度值会明显偏小采集的是没充满的电平。4.2 使能内部通道F1 特有的一个寄存器位F1 系列和 F4/L4 不一样除了在 Rank 里选通道还必须额外置位 ADC_CR2 的 TSVREFE 位温度传感器和 VREFINT 才会真正通电。CubeMX 生成的代码默认不含这一步需要在MX_ADC1_Init()里 ADC 初始化完成后手动加一行staticvoidMX_ADC1_Init(void){ADC_ChannelConfTypeDef sConfig{0};hadc1.InstanceADC1;hadc1.Init.ScanConvModeADC_SCAN_ENABLE;hadc1.Init.ContinuousConvModeENABLE;hadc1.Init.DiscontinuousConvModeDISABLE;hadc1.Init.ExternalTrigConvADC_SOFTWARE_START;hadc1.Init.DataAlignADC_DATAALIGN_RIGHT;hadc1.Init.NbrOfConversion2;if(HAL_ADC_Init(hadc1)!HAL_OK){Error_Handler();}/* Rank1: CH16 温度传感器 */sConfig.ChannelADC_CHANNEL_16;sConfig.RankADC_REGULAR_RANK_1;sConfig.SamplingTimeADC_SAMPLETIME_239CYCLES_5;if(HAL_ADC_ConfigChannel(hadc1,sConfig)!HAL_OK){Error_Handler();}/* Rank2: CH17 VREFINT */sConfig.ChannelADC_CHANNEL_17;sConfig.RankADC_REGULAR_RANK_2;if(HAL_ADC_ConfigChannel(hadc1,sConfig)!HAL_OK){Error_Handler();}/* F1 系列必须手动使能内部通道供电 */hadc1.Instance-CR2|ADC_CR2_TSVREFE;}上面这段代码里ADC_CHANNEL_17在部分老版本 HAL 库里写作ADC_CHANNEL_VREFINT两者本质是同一个枚举值 0x11用哪个都行编译报错就换另一个。五、核心代码两个版本的对比才能看出差距为了让校准这件事有说服力我把温度换算写成了两个函数方便在测试环节做 A/B 对比。/* 版本一传统直接换算VDDA 写死 3.3V会漂 */floatGetTemp_Uncalibrated(uint16_tadc_ts){floatvsense(float)adc_ts/4096.0f*3.30f;/* 假设 VDDA3.3V */return(1.43f-vsense)/0.0043f25.0f;}/* 版本二VREFINT 比例校准与 VDDA 无关 */floatGetTemp_Calibrated(uint16_tadc_ts,uint16_tadc_vrefint){if(adc_vrefint0){return-273.0f;/* 保护分母不能为 0 */}floatvsense1.20f*(float)adc_ts/(float)adc_vrefint;return(1.43f-vsense)/0.0043f25.0f;}主循环里因为开了扫描 连续转换每次HAL_ADC_GetValue()返回的都是当前规则组里最新完成的那一个通道所以要按 Rank 顺序连续读两次才能拿到一组完整数据intmain(void){HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_ADC1_Init();MX_USART1_UART_Init();HAL_ADC_Start(hadc1);/* 软件启动连续转换 */while(1){/* 读两次先 CH16 温度后 CH17 VREFINT */uint16_tadc_tsHAL_ADC_GetValue(hadc1);uint16_tadc_refHAL_ADC_GetValue(hadc1);floatt_rawGetTemp_Uncalibrated(adc_ts);floatt_calGetTemp_Calibrated(adc_ts,adc_ref);printf(TS%d REF%d | raw%.1f C | cal%.1f C\r\n,adc_ts,adc_ref,t_raw,t_cal);HAL_Delay(500);}}这里有个我在调试时实际犯过的错值得单独拎出来说。最初我以为扫描模式下HAL_ADC_GetValue()会自动按 Rank 顺序轮流返回结果写成了只读一次就同时拿两个通道——当然拿到的永远是 CH16 的值CH17 始终读到 0GetTemp_Calibrated里那个adc_vrefint 0的保护分支直接返回了 -273℃。正确做法是每读一次HAL_ADC_GetValue()只消费一个通道的转换结果要几个通道就连续读几次。这个坑当时折腾了我一个晚上所以特意把保护分支写进去提醒自己。六、测试验证把供电拉偏看读数漂多少测试环境温度恒定在 25℃空调房用精度 0.1℃ 的数字温度计做参照分别用三个供电电压给板子供电各连续采样 100 次取平均对比两个版本的输出。6.1 校准前后对比数据供电 VDDA直接换算写死3.3VVREFINT 比例校准读数偏差3.30V25.3℃25.1℃0.2℃2.95V33.2℃25.4℃0.4℃3.60V18.1℃24.8℃−0.2℃这张表把问题暴露得很彻底直接换算法在 VDDA 从 3.30V 掉到 2.95V 时读数从 25.3℃ 一路飙到 33.2℃漂了将近 8℃而 VDDA 升到 3.60V 时又反向掉到 18.1℃。而 VREFINT 校准版本在这三种供电下都稳在 24.8~25.4℃ 之间最大漂移只有 0.6℃。6.2 理论 vs 实测对照手册标称内部温度传感器精度 ±1.5~±2℃这是在 VDDA 稳定的前提下。我做了个对照表看看误差到底来自哪里误差来源理论影响实测表现V25 / Avg_Slope 典型值离散±1.5% 量级约 ±1.5~2℃校准后与标准温度计差 ±0.4℃ 内本片运气较好VDDA 波动直接换算与波动比例成正比0.35V 波动 → 8℃ 漂移VDDA 波动VREFINT 校准理论上被完全消除残余 0.6℃ADC 量化 噪声值得说明的是VREFINT 校准消除的是供电波动引入的误差它不能消除 V25/Avg_Slope 典型值离散带来的绝对误差——那个误差只能靠每颗芯片单独标定。所以正确的认知是校准后的读数稳定了但绝对精度仍受限于芯片自身的典型值离散别指望它当精密温度计用。七、故障排查这 6 类问题我基本都遇到过7.1 温度读数恒定不动像死了一样现象无论怎么摸芯片、吹热风读数纹丝不动。排查先确认是不是一直读的同一个通道值。扫描模式下少读了一次HAL_ADC_GetValue()会导致 CH17 永远是 0、CH16 永远是旧值。方案两个通道就连续读两次每次读一个或者干脆用 DMA 把两个通道结果搬进数组再按 Rank 下标取值彻底避免顺序错位。验证用手指捏芯片读数应该缓慢上升。7.2 温度明显偏低且一直偏低现象室温 25℃读数只有 15℃ 左右。排查十有八九是采样时间设短了。内部温度传感器等效阻抗高采样时间不够时采集电压没充满。方案把 CH16 采样时间调到 239.5 Cycles12MHz 下约 17.1μs满足手册要求。验证改完后读数回到正常范围。7.3 CH17 一直读到 0现象adc_ref恒为 0校准函数返回 -273℃。排查F1 系列忘了置位ADC_CR2_TSVREFE。这个位不开温度传感器和 VREFINT 都不工作。方案在 ADC 初始化末尾加hadc1.Instance-CR2 | ADC_CR2_TSVREFE;。验证加完重新烧录adc_ref应有非零读数约 1500 上下取决于 VDDA。7.4 校准后读数仍随供电小幅波动现象VREFINT 校准后供电波动时读数还是有 1℃ 左右的起伏。排查这是正常的残余误差。比例法假设 VREFINT 完全不变但实际 VREFINT 也有 μV 级的温漂和供电抑制比限制加上 12 位 ADC 的量化误差。方案如果 1℃ 波动仍不可接受换用 F0/L0/L4 等带出厂校准值TS_CAL1/TS_CAL2的系列配合多点插值能进一步压到 ±0.5℃ 以内或者直接外挂 DS18B20 这类数字传感器。验证对比校准前后数据确认波动已从 8℃ 收敛到 1℃ 以内即为正常。7.5 串口打印乱码现象printf输出全是乱码。排查重定向fputc没做好或波特率/时钟配置不一致。方案确认__HAL_RCC_USART1_CLK_ENABLE()已调用且printf前已正确重定向到串口。验证用固定字符串先验证串口通路再排查温度打印格式。7.6 长时间运行温度缓慢上飘现象连续跑几小时温度读数缓慢上升 1~2℃。排查这可能是真实的结温上升也可能是 MCU 负载变化导致的。先区分是读数漂还是芯片真的热了。方案用红外测温枪测芯片表面温度对照若芯片确实升温检查是否有高频外设持续满载、LDO 是否过热。验证触摸芯片或红外枪实测与读数趋势一致则属正常温升而非测量误差。八、总结核心要点STM32F103 内部温度传感器读数不稳的最大元凶往往是 ADC 参考电压 VDDA 随供电漂移而不是传感器本身。利用片内 VREFINTCH17典型 1.20V做比例校准可以在公式层面把 VDDA 完全约掉让读数与供电电压解耦。实测把 VDDA 从 3.30V 拉到 2.95V校准前温度漂移 8.2℃校准后收敛到 0.4℃效果立竿见影。但 VREFINT 校准只解决稳定性不解决绝对精度——V25/Avg_Slope 的典型值离散仍存在别把内部传感器当精密温度计。适用边界适用对温度做相对监测、过温保护、需要消除供电波动的场景尤其电池供电设备。不适用需要 ±0.5℃ 以内绝对精度的场景应改用出厂校准系列F0/L0/L4/G0 等带 TS_CAL或外挂数字传感器。F1 系列无 VREFINT_CAL 出厂校准值1.20V 用的是典型值需要更高精度的 VDDA 测量时建议换带 VREFINT_CAL 的系列。扩展方向读完这篇你可以顺着两条线继续深入一是用 DMA 把 CH16CH17 和外部通道一起搬进缓冲区做多通道批量采集二是研究 F0/L0 系列的 TS_CAL1/TS_CAL2 双点校准插值把绝对精度压进 ±0.5℃。这两条路都能把内部温度传感器这个被低估的模块吃透。本文完整工程代码可在 CSDN 下载频道 获取VIP 免费。参考资料相关阅读《带内部参考电压(VREFINT)校正的STM32 DMA 内置温度采集》 — 用 DMA 方式同时采温度与 VREFINT 的完整实现。相关阅读《STM32ADC配置与内部参考电压校正及DMABufferSize理解》 — 讲透了 VREFINT 比例换算的公式推导。相关阅读《STM32的HAL库开发—ADC采集内部温度传感器》 — F1 寄存器版与 HAL 版配置对照含采样时间说明。版本备注硬件平台STM32F103C8T648Pin 最小系统板 可调 DC 电源软件版本STM32CubeMX 6.9 STM32F1 HAL 驱动 1.1.8 Keil MDK 5.38兼容说明VREFINT 比例校准思路适用于所有 STM32 系列F1 无 VREFINT_CAL 出厂校准值F0/L0/L4/G0/G4 等系列可读取 VREFINT_CAL 进一步提升精度代码需按对应系列调整寄存器与采样时间。
返回列表