ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

STM32内置ADC读取PT100:高精度测温电路与软件实现全解析

STM32内置ADC读取PT100:高精度测温电路与软件实现全解析 简介针对STM32F103与PT100恒流测温的完整工程模板面向嵌入式入门开发者及需要实现高精度ADC温度采集的工程师。资源定位明确通过恒流源将PT100电阻变化转换为电压再由STM32F103内部ADC采样并完成数字量到温度值的换算解决工业测温中常见电压-温度转换问题。包体包含4个文件全部为C源文件与头文件如Adc.c/Adc.h负责ADC初始化与读取pt100.c/pt100.h负责PT100电阻-温度标定及线性插值计算结构精简可直接移植至实际项目。压缩包仅4KB代码量小、易于阅读和二次开发。已有5540人学习/下载说明该方案在社区中得到较多验证。代码提供完整工程结构和关键配置思路可帮助理解ADC单端模式、采样时间设置、DMA/中断处理方式以及通过查找表或公式实现温度转换的具体代码逻辑适合作为课程设计、产品原型或技术研究的参考。 做了这么多年嵌入式测温项目我慢慢发现一个规律选传感器的时候NTC便宜但一致性差DS18B20简单但量程和响应都受限真正在工业设备、工艺监控里用得最多的还是PT100。这几年我拿STM32F103直接接PT100做了不少测温方案从烘道温度到户外机柜内部温控用内置ADC配合桥式电路或者恒流源精度做到±0.5℃以内是完全可行的。这篇文章就把这套方案从头到尾拆开电路怎么搭、ADC怎么采、电压怎么换算成温度以及我踩过哪些坑。准备照着做的人不管是学生做毕设还是工程师做产品预研应该都能少走不少弯路。1. 方案选型先搞清楚PT100到底在测什么1.1 为什么工业测温绕不开PT100选测温方案时很多人第一反应是NTC热敏电阻便宜、灵敏度高一颗几分钱。但NTC的离散性太让人头疼了B值标称25℃下10kΩ实际上不同批次能差到5%以上批量生产时每个探头都得单独标定否则同一批设备显示的温度能差好几度。DS18B20这类数字传感器用起来确实省事单总线直接读温度但它的量程上限一般到125℃而且探头封装较大、热响应慢在很多工业管道表面和高温设备上根本没法用。PT100是铂电阻温度传感器0℃时阻值正好100Ω温度系数约0.385Ω/℃覆盖-200℃到850℃的宽量程。更关键的是它符合IEC 60751标准不同厂家生产的PT100在同样温度下阻值几乎一致互换性极好。这意味着你换一个探头不需要重新标定系统这是工业场景里非常重要的优势。PT100的缺点是输出的是电阻而不是电压MCU没法直接读。所以完整的链路是电阻→电压→ADC采样→软件换算→温度。前面两步靠硬件电路后面两步靠固件算法哪一环偷懒最后显示的温度都会给你颜色看。1.2 电阻怎么变成温度阻温关系与误差预算在搭电路之前先得把PT100的阻温关系吃透。IEC 60751标准把PT100的阻温特性用Callendar-Van Dusen方程描述0℃到850℃范围内是Rt R0 * (1 At Bt²)其中R0100ΩA3.9083e-3B-5.775e-7。在-200℃到0℃范围还要加上一个三次修正项C*(t-100)*t³C-4.183e-12。如果嫌公式麻烦记住两个关键数字就行0℃时100Ω平均温度系数约0.385Ω/℃。但要注意这个系数不是常数100℃时实际斜率已经降到约0.379Ω/℃所以在0-100℃量程内直接用线性公式T(Rt-100)/0.385最大误差会接近1℃要求不高时能接受想精确一点就得查表或者用公式。误差预算这件事我建议一开始就想清楚。一个典型的测温系统误差来源包括传感器本身的精度等级A级PT100误差±0.15℃B级±0.3℃、分压电阻的精度和温漂、基准电压的稳定性、ADC的量化误差和噪声、导线电阻引入的误差。如果你目标是±0.5℃以内那A级传感器加0.1%电阻加简单校准就能达到如果目标要做到±0.1℃坦白说STM32F103内置ADC加常规电路是比较吃力的得上24位Sigma-Delta ADC或者专用芯片。2. 硬件电路从电阻到ADC电压的关键几步2.1 分压方案最简单但要接受它的短板最简单粗暴的电路就是把PT100和一个精密电阻R1串联中间节点接ADC输入。分压公式是Vout Vref * Rt / (R1 Rt)反解出Rt R1 * Vout / (Vref - Vout)然后查表或者用公式算温度。R1的取值是个权衡。取太小流过PT100的电流大自热效应明显测量值会偏高取太大电压变化幅度小ADC分辨率不够。以3.3V供电、R11kΩ为例0℃时Rt100ΩVout≈0.300V100℃时Rt138.51ΩVout≈0.401V整个量程电压变化才101mV。STM32F103的ADC是12位满量程3.3V对应4096个码值1℃大约只有1.25个LSB勉强能分辨但跳动会比较大。所以我的结论是直接分压方案适合对精度要求不高、显示到0.1℃就够用的场景比如机柜温度监控、简单的环境温度采集。想做正经的工业温度采集还是得上桥式电路加运放。2.2 平衡电桥加运放把0.1℃从理论变成现实我实际项目里用得比较多的是平衡电桥加差分放大。电路结构是两条并联支路一条是精密电阻Rc取值100Ω等于PT100在0℃时的阻值与PT100串联另一条是两个等值电阻R3、R4串联。这样在0℃时两条支路中点电压相等差分输出为0温度升高时PT100阻值增大差分电压随之增大。以3.3V供电、Rc100Ω、R3R410kΩ为例0℃时A点电压1.65VB点电压1.65V差分0V100℃时A点电压为3.3*138.51/(100138.51)≈1.918VB点还是1.65V差分约0.268V。这个信号直接进ADC只有0.268V的摆动利用率还是不够所以后面要接一级差分放大把0-0.268V放大到0-2.7V左右增益大约10倍。这里有一个很重要的点Rc必须用低温漂、高精度的电阻我一般选0.1%精度、25ppm/℃温漂的金属膜电阻。R3和R4的精度影响的是电桥的共模电压对差分输出影响相对小一些但最好也别用普通5%的插件电阻选1%贴片电阻比较稳妥。运放选型上轨到轨输入输出的单电源运放是首选。LM358虽然便宜但输入共模范围接近正轨时性能会下降而且本身失调电压最大能达到7mV按10倍增益算就是70mV的输出误差对应温度误差接近0.3℃。我后来换成了SGM8521、MCP6002这类轨到轨运放失调电压在微伏级明显靠谱得多。2.3 三线制接法与PCB布局的几个细节很多人以为三线制就是“多接一根线”其实它真正解决的是导线电阻参与测量的误差。导线从PCB到PT100探头往往有几米甚至几十米铜导线电阻大约0.5Ω/10m以0.5mm²截面估算如果这条导线串在RT的测量回路里0.5Ω对应的温度误差就有1.3℃左右完全不可接受。三线制的思路是让两根导线分别承担激励电流的流入和流出第三根导线只做电压检测不流过电流或者流过极小电流这样导线电阻上的压降不会进入测量回路。实际接法上用恒流源激励PT100从PT100两端引出电压采样线采样线接到高输入阻抗的仪表放大器或运放同相端就能把导线电阻的影响压到非常小。我自己常用的简化方案是恒流源加运放跟随器用TL431做基准配合运放搭一个1mA恒流源PT100两端各引一根线再从PT100近端引第三根线接电压跟随器进ADC。这样即使导线长到五米十米误差也基本能控制在0.1℃以内。PCB布局上要记住三条模拟地和数字地单点连接ADC输入走线尽量短且远离PWM输出和开关电源走线基准电压和采样电阻附近要放去耦电容。ADC输入口加一个RC低通滤波100Ω串联100nF电容截止频率约16kHz对工频干扰和高频噪声都有明显的抑制作用。这些看似不起眼的细节往往决定了你最后显示的温度是稳定的18.5℃还是来回跳的17.8℃到19.2℃。3. ADC采样与软件实现把电压换算成温度3.1 STM32F103 ADC配置采样时间比你想的重要STM32F103的ADC是12位逐次逼近型内置ADC的输入等效模型是一个采样保持电容加一个开关。如果信号源阻抗太大ADC内部的采样电容在规定的采样时间内充不满转换结果就会偏低。PT100分压电路或者电桥电路的等效输出阻抗通常在几百欧姆到几千欧姆这时候采样时间必须配置得保守一些。我一般在HAL库中把采样时间设为55.5或71.5个ADC时钟周期而不是默认的1.5周期。ADC时钟配置为12MHz左右这样单次转换时间大约10-20微秒对于温度这种慢变信号完全够用换来的是采样值稳定很多。初始化代码大致这样static void MX_ADC1_Init(void) { ADC_ChannelConfTypeDef sConfig {0}; hadc1.Instance ADC1; hadc1.Init.ScanConvMode 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; HAL_ADC_Init(hadc1); sConfig.Channel ADC_CHANNEL_0; // PA0 sConfig.Rank 1; sConfig.SamplingTime ADC_SAMPLETIME_55CYCLES_5; HAL_ADC_ConfigChannel(hadc1, sConfig); }读取采样值并换算成实际电压的代码uint16_t adc_read_raw(void) { HAL_ADC_Start(hadc1); HAL_ADC_PollForConversion(hadc1, 10); return (uint16_t)HAL_ADC_GetValue(hadc1); } float adc_to_voltage(uint16_t raw) { return (float)raw * 3.3f / 4096.0f; }如果你用的是标准外设库逻辑也是一样的只是函数名换成ADC_RegularChannelConfig、ADC_SoftwareStartConvCmd这些。重要的是理解为什么要把采样时间拉长而不是死记某个参数。3.2 采样滤波别让数据显示跳来跳去ADC采样值跳动几乎是必然的电源纹波、工频干扰、热噪声都会叠加到信号上。如果直接把单次采样值拿去算温度显示屏上的数字会像股市行情一样来回跳。我的习惯是做一个8-16次的滑动平均滤波再配合一个简单的限幅判断防止偶发尖峰把均值拉偏。滑动平均的代码很简洁#define FILTER_N 16 uint32_t sliding_average_filter(uint32_t new_val) { static uint32_t buf[FILTER_N]; static uint8_t idx 0; uint32_t sum 0; uint8_t i; buf[idx] new_val; if (idx FILTER_N) { idx 0; } for (i 0; i FILTER_N; i) { sum buf[i]; } return sum / FILTER_N; }实际使用中滑动窗口越大越平滑但滞后也越大。测温场景下温度变化本身比较慢16次采样平均带来的滞后大概只有几十毫秒完全不影响响应。如果现场电磁干扰特别严重可以在滑动平均之前先做一次中值滤波把明显偏离的野值剔掉。我有个做电机控制柜测温的同事就是加了中值加滑动平均两级滤波采样值才从±10个LSB的跳动收敛到±2个LSB。3.3 电压转温度查表插值还是CVD公式这是整个方案的核心换算环节。拿到ADC电压后先根据电路结构反算出PT100的电阻值再转成温度。分压电路用Rt R1 * Vout / (Vref - Vout)电桥加放大电路则需要把电压换算回电桥差分电压再解出Rt。温度换算我推荐查表加线性插值而不是直接套简化公式。把IEC 60751分度表按10℃间隔存一个数组用线性插值补中间值误差可以控制在0.1℃以内。代码大概这样const float pt100_table[][2] { {-50, 80.31f}, {-40, 84.27f}, {-30, 88.22f}, {-20, 92.16f}, {-10, 96.09f}, {0, 100.00f}, {10, 103.90f}, {20, 107.79f}, {30, 111.67f}, {40, 115.54f}, {50, 119.40f}, {60, 123.24f}, {70, 127.08f}, {80, 130.90f}, {90, 134.71f}, {100, 138.51f} }; float resistance_to_temperature(float r) { uint8_t i; if (r pt100_table[0][1]) return pt100_table[0][0]; if (r pt100_table[15][1]) return pt100_table[15][0]; for (i 0; i 15; i) { if (r pt100_table[i][1] r pt100_table[i1][1]) { float t0 pt100_table[i][0]; float r0 pt100_table[i][1]; float t1 pt100_table[i1][0]; float r1 pt100_table[i1][1]; return t0 (r - r0) * (t1 - t0) / (r1 - r0); } } return pt100_table[15][0]; }如果不想维护那么大的表格也可以直接用CVD方程反解温度但需要二分法迭代代码量其实更大。查表法还有个额外好处改分度表就能支持PT1000或者其他铂电阻传感器通用性好很多。4. 校准、误差分析与常见问题实录4.1 两点校准流程与实测结果软件写得再好硬件元件也有离散性。3.3V的基准电压实际可能是3.28V0.1%的电阻实际也有偏差所以装机后必须校准。我最常用的方法是两点校准把探头放到冰水混合物中记录一个点0℃再放到沸水中记录一个点100℃或者用精密电阻箱模拟0℃和100℃对应的阻值。校准代码的思路是记录两个原始ADC值算出实际的“增益”和“偏移”然后在温度换算结果上做线性修正// 标定时记录两个点 // 0℃ 时原始电阻计算值 raw_0 // 100℃ 时原始电阻计算值 raw_100 float calibrated_temp(float temp_raw) { return (temp_raw - 0.0f) * (100.0f - 0.0f) / (raw_100 - raw_0) 0.0f; }我在室温环境下实际做过一组测试A级PT100、0.1%电桥电阻、SGM8521运放、12位ADC两点校准后在0到100℃范围内与标准水银温度计对比最大误差约±0.3℃大部分区间在±0.2℃以内。这个精度对于大多数工业监控场景已经够用了。4.2 常见问题速查表现象可能原因解决办法显示温度来回跳动超过±1℃采样时间太短、信号源阻抗过高、电源纹波大增大ADC采样时间加RC滤波强化模拟电源去耦整体温度比实际偏高激励电流过大导致自热、分压电阻偏小降低恒流源电流到1mA以内增大分压电阻必要时软件减去自热补偿长线连接时温度偏高二线制导线电阻串入测量回路改三线制接线加运放跟随器隔离测量点换一个PT100探头后读数偏差变大传感器精度等级低或接线接触不良使用A级PT100检查端子是否氧化、螺丝是否拧紧0℃附近读数非线性明显电桥电阻Rc取值漂移或运放饱和复查电桥元件测量各节点电压是否正常读数忽大忽小且无规律运放自激振荡、地线环路运放输出对地加100pF电容检查模拟地单点连接4.3 几个让我少走弯路的习惯第一所有关键节点的电压都要拿万用表实测不要只信理论计算。电桥两个支路的中间节点电压、运放输出端电压、ADC采样引脚的电压这四处数据一测问题基本就能定位是哪一级出的。第二做产品时要在固件里留一个“原始ADC值”的调试接口可以用串口打印或者Modbus寄存器暴露出来。现场出了问题先看原始码值是否正常马上就能分清是硬件问题还是软件换算问题不用抱着万用表跑来跑去。第三不要迷信“12位ADC”这个参数。STM32F103的12位ADC在实际布局条件下有效位数通常只有10到11位也就是大约2到4个LSB的噪声底。想提高精度优先优化硬件和滤波而不是单纯在软件里做复杂的修正算法。最后分享一个小经验我把这套测温逻辑封装成了一个独立模块输入是ADC原始值和电路类型参数输出是温度换项目时只需要改几个电阻值参数和分度表基本不用重写代码。后来那个模块陪我做了四五个测温项目每次都是标定一次就正常跑这大概是做嵌入式最舒服的体验了。本文还有配套的精品资源点击获取
返回列表