ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

STM32F103读取PT100的ADC测温精度优化与实现

STM32F103读取PT100的ADC测温精度优化与实现 简介针对 STM32F103 与 PT100 温度测量场景这份压缩包以 ADC 电压采集为核心覆盖 PT100 在 0°C 时 100Ω 的基准特性、恒流源将阻值变化转换为电压再到 STM32 内置 ADC 采样与温度换算的完整处理链路。特别适合嵌入式初学者理解模拟前端、ADC 配置和分度表查算流程也可作为工业测温项目的基础模型。压缩包为 RAR 格式共 4 个文件包含 2 个 C 源文件与 2 个头文件分别承担 ADC 初始化与 PT100 温度计算整体仅 4KB结构清晰、便于裁剪。已有 5540 人学习下载说明该方案在常见 PT100 测量设计中具有一定参考价值。代码中对 Adc 模块的初始化流程、采样触发与中断处理给出了明确注释并基于 PT100 分度表实现了电压到温度的转换逻辑保留了标定与线性化处理的思路可直接移植帮助开发者快速搭建可用的温度测量原型并进一步优化精度。 前几天有个做温控设备的朋友问我用STM32F103的ADC直接读PT100为什么温度值总是跳来跳去隔着半米都能看出显示在抖。这个问题我太熟悉了。PT100先把温度变成电阻采样电路把电阻变成电压STM32F103的ADC再把电压变成数字最后软件把数字换算成温度——链路里任何一环处理不好最后表现出来就是精度翻车。这篇东西不打算讲太虚的概念就围绕STM32F103 PT100 ADC 电压转换温度这条主线把选型、采样电路、ADC配置、换算算法、噪声排查这几个环节挨个说清楚。适合刚接触ADC测温、或者做出来的东西精度始终不达标的朋友也适合打算量产、正在纠结成本与精度之间如何取舍的工程师。1. 为什么是PT100选型背后的温度测量逻辑1.1 从一次NTC翻车说起我最早做测温产品用的是NTC热敏电阻理由很朴素便宜电路简单一个电阻分压就完事。结果产品进入批量测试后问题来了——同一批传感器同一套标定参数换到下一批物料就不准了偏差能到2~3℃。后来一查NTC的B值离散度大而且长期稳定性一般库存放上半年阻值能漂出不少。换PT100之后这批麻烦少了很多。铂电阻的核心优势是材料特性稳定0℃时标称100Ω温度系数大约0.385Ω/℃重复性和互换性都挺好。对工业级温度测量这种需求来说PT100属于多花几块钱买省心的典型方案。STM32F103这类MCU本身没有模拟前端但配上合适的采样电路完全能把它读准。1.2 100 Ω 背后的线性度陷阱PT100虽然比NTC线性很多但并不是完全的线性电阻。它在0~100℃范围内平均温度系数约为0.385Ω/℃但实际阻值-温度曲线是略微弯曲的。IEC 60751标准里给的是Callendar-Van Dusen方程后文会详细说。很多新手会直接把当前电阻除以0.385得到温度这在窄范围比如20~30℃内误差不大一旦范围拉到-20~100℃误差能达到好几度。所以电压转换温度这步不能图省事用一阶线性公式硬套。简单说选PT100看中的是稳定性和可重复性但它也不是免校准的万能器件后端的换算算法和校准流程照样得认真做。2. 传感器到ADC采样电路才是精度的第一道分水岭2.1 二线制、三线制、四线制怎么选PT100接线方式直接决定测量误差来源这是很多人第一次做样机时忽略的点。二线制两根线既是激励线又是测量线导线电阻会直接叠加到PT100的阻值上。如果导线电阻是1Ω温度误差就有约2.6℃。样机用短线可能无所谓实际工程布线一长就露馅。三线制一根线走激励电流另外两根分别走测量回线和反馈线。因为测量回路中不流过激励电流所以导线电阻带来的压降可以被抵消掉一部分。工业现场普遍用这种接法性价比最高。四线制用独立的四根线激励和检测完全分开精度最高但成本和接线复杂。适合实验室级测量普通产品很少用。STM32F103的ADC读的是电压不是电阻所以电路的关键是让PT100的电阻变化尽可能无失真地变成地参考的电压信号。三线制是日常项目里平衡成本和精度的最优解。2.2 恒流源电路设计实例把PT100电阻变成电压有两种最常用的办法。一是电阻分压PT100串联一个精密电阻从中间取分压点。这电路简单但有两个毛病供电电压波动会直接影响输出电压串联电阻自身的温漂也会混入结果。二是恒流源激励让恒定电流流过PT100两端的电压就等于I × R电压和电阻严格成正比这个思路更干净。我习惯用1mA恒流源做激励。为什么是1mA因为PT100在0℃时是100Ω1mA下压降只有100mV后续放大电路容易处理电流再大比如5mA自热效应就会变得明显PT100自身发热会抬高测量值。一个简单实用的恒流源可以用运放搭建用TL431或者REF3030产生一个2.5V基准经过精密电阻转换为电流运放加三极管扩流后输出给PT100。大致的计算逻辑是基准电压2.5V取样电阻2.5kΩ基准端到运放反相输入端虚短三极管发射极电阻上的电流约为 2.5V / 2.5kΩ 1mA。这个电流流过PT1000℃时输出电压 1mA × 100Ω 100mV。100℃时PT100阻值约138.51Ω输出电压 138.51mV。这个100mV级别的信号如果直接进STM32F103的ADC12位分辨率满量程3.3V一个LSB约0.8mV。算下来0.8mV对应约2Ω多也就是温度分辨率将近5~6℃显然不够用。所以必须在ADC之前加一级放大把100~140mV的区间放大到接近ADC的满量程。2.3 ADC输入范围与参考电压匹配STM32F103的ADC是12位输入范围一般到VREF通常是3.3V。把PT100的电压放大到哪个范围决定了分辨率。我以前常用的做法是仪表放大器比如AD620或者国产的INA128把差分信号放大使0℃时输出约0.3V100℃时输出约2.5V这样整个动态范围覆盖了ADC比较好用的区间。如果你是分压法加运放跟随务必把公共端处理好不要让ADC输入引脚悬空也不要把信号直接拉到超出VREF的范围。ADC输入引脚电压超过VDDA或低于VSSA轻则读数错误重则损坏IO。小结一下采样电路的核心是恒流源激励 精密放大 匹配ADC量程这决定了系统精度的上限。而STM32F103的ADC配置决定的是能把这个模拟信号还原到什么程度。3. STM32F103的ADC采样配置、采样时间与软件滤波3.1 ADC基本配置与参考电压STM32F103的ADC是12位逐次逼近型时钟最高14MHz采样周期可配置。这里有两个容易踩的坑第一ADC时钟不要直接拿PCLK2不分频上去跑APB2时钟如果是72MHzADC分频器至少要6分频到12MHz稳定一点用8分频到9MHz太高会影响转换准确度。第二VREF引脚如果直接从3.3V供电取3.3V上的纹波就会直接进到测量结果里。要求高时用单独的基准电压芯片给VREF供电或者至少加LC滤波。我之前遇到过ADC全码跳动排查半天最后发现是DC-DC模块的开关纹波串到了VREF上。3.2 采样时间为什么不能一直用默认值ADC内部有个采样电容采样期间开关闭合外部信号源通过等效阻抗给这个电容充电。如果外部阻抗很大采样时间不够电容电压还没充到信号的实际值转换结果就会偏低。PT100配合1mA恒流源时输出阻抗不算太大但后面加了放大器和RC滤波后源阻抗可能到几十kΩ。此时建议把采样时间配置到最大档比如STM32F103支持的最高239.5周期如果ADC时钟9MHz一次采样时间约26.6μs。对温度测量这种慢速信号这点时间完全不影响实时性但能显著减少采样电容充电不足造成的读数误差。3.3 软件滤波滑动平均不能无脑用ADC读数跳动很多人第一反应是滤波。我一开始也直接上滑动平均结果发现偶尔一个大的毛刺会把平均值拉偏好多温度曲线出现尖刺。后来改成先做中位值剔除再做滑动平均连续采样5次去掉最大值和最小值剩下的3次取平均再对这个均值做宽度为10的滑动平均。这样既能压制随机噪声又能避免单一毛刺污染结果。代码实现也不复杂#define FILTER_LEN 10 uint16_t filter_buf[FILTER_LEN]; uint8_t filter_index 0; uint32_t filter_sum 0; uint16_t adc_filter(uint16_t adc_value) { filter_sum - filter_buf[filter_index]; filter_buf[filter_index] adc_value; filter_sum adc_value; filter_index (filter_index 1) % FILTER_LEN; return (uint16_t)(filter_sum / FILTER_LEN); }对于5取3中位均值可以单独写个小函数把5次ADC原始值排序后取中间三个平均。这比直接平均多不了几行代码滤波效果却好很多。3.4 用DMA省CPU温度采样没必要让CPU每轮询一次用ADC的多通道扫描加DMA是更合理的做法。配置ADC为连续转换模式开启DMA循环传输采到的数据自动落到内存数组里HAL_ADC_Start_DMA(hadc1, (uint32_t *)adc_buf, 4);这样每次转换完成后数据自动更新主循环只用去数组里取值做滤波CPU占用率几乎为零。实测在STM32F103上跑多个通道采样、LCD显示和通信协议一点压力都没有。4. 电压转温度查表、公式还是查表加插值4.1 先把ADC值还原成电阻值不管后面用什么算法第一步都是从ADC码值反推PT100的电阻值。假设放大电路输出函数是线性的Vout gain × (Rpt100 × I) offset那么反向计算就是float v_out (float)adc_value / 4095.0f * 3.3f; float r_pt100 (v_out - offset) / (gain * 0.001f);这里的gain和offset需要在装机后实测标定不能只看理论值。因为电阻容差、基准电压偏差、运放失调都会让真实增益和设计值有出入。4.2 Callendar-Van Dusen方程教科书级的精确解法IEC 60751标准给出的PT100阻值-温度关系比较复杂但工程上可以用简化的Callendar-Van Dusen方程。0℃以上时R(t) R0 × (1 A×t B×t²)其中R0100ΩA3.9083×10⁻³B-5.775×10⁻⁷。0℃以下时要多一项C×(t-100)×t³C-4.183×10⁻¹²。对大多数0~100℃的应用只用A和B两项就够。反过来由电阻求温度可以直接解一元二次方程float pt100_res_to_temp(float r) { const float R0 100.0f; const float A 3.9083e-3f; const float B -5.775e-7f; float delta, t1, t2; delta A * A - 4.0f * B * (1.0f - r / R0); if (delta 0.0f) return -40.0f; t1 (-A sqrtf(delta)) / (2.0f * B); t2 (-A - sqrtf(delta)) / (2.0f * B); return (t2 t1) ? t2 : t1; }这段代码在Cortex-M3上运行没压力算一次也就几十微秒完全可以对每帧数据实时计算。4.3 查表法适合资源紧张或追求固定耗时的场合查表法的思路是预先在代码里放一张电阻-温度对应表比如每5℃一个点运行时用二分查找找到区间再线性插值。好处是计算量固定、没有浮点运算也能做用整数定点缺点是表要占一些Flash。温度范围从0到200℃每5℃一个点才41个条目一张表没多大。typedef struct { uint16_t resistance_x10; /* 阻值×10避免浮点 */ int16_t temperature; /* 温度×10 */ } pt100_entry_t; static const pt100_entry_t pt100_table[] { { 1000, 0 }, /* 100.0Ω - 0.0℃ */ { 1019, 50 }, /* 101.9Ω - 5.0℃ */ { 1039, 100 }, /* 103.9Ω - 10.0℃ */ /* ... */ };线性插值处理一下查表法在常温段能轻松做到0.1℃级别的显示分辨率。注意表里的值必须是实测标定后的修正值否则表再精确也救不了前端电路的偏差。4.4 三种换算方式的实测对比拿同一个信号源在恒温槽里做对比我的测试结果大致是算法常温段误差高温段(200℃)误差额外开销一阶线性近似 0.385Ω/℃0.8~1.5℃4~5℃最低C-VD方程直接计算0.1~0.3℃0.3~0.5℃低5℃查表线性插值0.1~0.2℃0.3~0.6℃极低结论很直接如果你的产品只工作在20~30℃窄范围一阶近似还能凑合一旦范围拉宽要么用C-VD方程要么用查表插值。我更偏向查表插值因为计算时间固定而且校准的时候可以直接改表项。5. 实测排查从跳数到0.1℃精度的完整链路5.1 先怀疑电源再怀疑传感器ADC读数跳动最常见的不是软件问题而是电源问题。用示波器看VREF和VDDA如果上面有周期性的毛刺多半是DC-DC或数字电路串过来的。STM32F103的VDDA和VREF引脚一定要加去耦电容而且去耦电容要尽量靠近引脚引线越短越好。我踩过一个非常隐蔽的坑板子上的继电器每次切换ADC读数就跳几十个码。排查发现继电器线圈没有加续流二极管关断瞬间产生的反向电动势通过地线干扰了模拟部分。继电器的电源和模拟电源彻底分开走线问题才消失。5.2 自热效应与电流选择恒流源电流越大信噪比越高但PT100自身发热也越严重。PT100在空气中散热条件一般1mA电流下自热误差大约0.02~0.05℃5mA时可以到0.3℃以上。做高精度测量激励电流取1mA是很多厂商的默认选择做快速响应但精度要求不高时才考虑加大电流。另外PCB走线和传感器探头的散热条件也会影响自热传感器放进金属套管和直接暴露在空气中自热表现完全不同。这个问题正规厂家的PT100说明书里会标注热阻选型时留意一下。5.3 单点校准与两点校准硬件精度的最后一步是校准。量大的产品不可能逐台精密标定但至少要做两点校准冰水混合物标准大气压下0℃作为低温点沸水100℃或者用恒温槽作为高温点。采集实测ADC值后反推出真正增益和偏移存到Flash里。之后每次开机读Flash里的校准值参与电阻还原计算。如果现场只能提供一个稳定温度也可以用单点校准先把零点偏移校准掉增益用理论值。这样能显著改善零点不对的问题但对增益误差无能为力。void calibrate_two_point(float adc_low, float temp_low, float adc_high, float temp_high) { float r_low 100.0f 0.385f * temp_low; /* 近似 */ float r_high 100.0f 0.385f * temp_high; gain (adc_high - adc_low) / (r_high - r_low); offset adc_low - gain * r_low; }5.4 一块小PCB上的模拟设计细节采样电路和MCU在同一个小板子上时建议把模拟部分的地单独走线单点汇接到电源地。ADC采样脚附近不要走高频数字线尤其是STM32F103的PA1、PA2、PA3这类可以复用的模拟输入脚周边如果有PWM走线很可能引入串扰。模拟地和数字地之间我习惯用0Ω电阻连接位置在ADC引脚所在那一侧让模拟回流路径尽量短。电源方面如果板上只有3.3V一路用一颗磁珠或小电阻把模拟电源和数字电源隔开形成模拟VDD岛效果立竿见影。最后再分享一个我自己的习惯任何温度采集项目都会在代码里保留ADC原始值、电阻还原值、滤波后温度三个变量的调试输出。现场问题八成在模拟链路没有原始数据做参照软件调了半天也找不到病根。把这个调试通道留好比什么玄学调参都管用。本文还有配套的精品资源点击获取
返回列表