基于STM32的PT100温度采集系统:程序、原理图与标定避坑
发布时间:2026/10/26 10:39:57 锦皓数字建站

简介面向嵌入式初学者与需要完成温度采集课程设计、毕设或工程原型的开发者这套资料围绕STM32单片机与PT100铂电阻构建完整测温方案涉及四线制接法、差分放大、ADC采样配置、R-T特性换算及原理图绘制并给出Keil工程源码与可烧录固件等配套内容。压缩包共277个文件约18.09MB以62个C源文件、52个头文件为主另有编译中间文件、17张调试截图、11份说明文本及PDF、Word文档、Keil工程文件与HEX固件便于按硬件、程序、文档三部分查阅。已有2099人学习下载说明该方案在同类课程设计中具有较高参考度。读者可据此理解PT100信号调理与STM32内部ADC采集的衔接方式参考查找表或多项式拟合完成温度计算并借助原理图、源码和说明文档快速搭建实验环境、排查采样与显示问题。1. 为什么 PT100 不能直接接 STM32 的 ADC0.385Ω/°C 背后的采集门槛有人把 PT100 两根线直接拧到 STM32 的 ADC 引脚上室温读数在 25°C 和 31°C 之间来回跳换一根线又偏了 2°C。这套「基于 STM32 单片机 PT100 铂电阻温度采集系统程序原理图全套资料」要解决的就是这个门槛PT100 在 0°C 只有 100Ω每升高 1°C 电阻只变约 0.385Ω直接分压后送进 12 位 ADC分辨率、线阻和噪声都会把温度吃掉。它适合做恒温箱、小型工业测温、实验数据采集的开发者尤其是手里有 STM32 板子、想把 PT100 从「能读数」做到「能验收」的人。资料把程序、原理图和全套资料放在一起重点不是炫技而是把激励、放大、采样、换算和标定串成一条可复现的链路。2. 硬件链路选型恒流源、差分放大与 12 位 ADC 的匹配PT100 前端不是「接个上拉电阻」就完事。先定量程和精度再选激励方式最后反推放大倍数和 ADC 码值范围。资料里的原理图如果采用分立方案重点看恒流源、差分放大和 ADC 输入这三段如果板上直接放了专用 RTD 前端芯片程序重点会变成 SPI 配置和故障位读取。2.1 三种前端方案怎么选电桥、恒流源和专用芯片常见方案就三类电阻电桥加差分放大、恒流源加仪表放大、专用 RTD 前端芯片。电桥成本低但输出非线性和共模电压都比较明显适合对精度要求不高的通断判断恒流源方案线性好配合三线制或四线制能把线阻影响压下去是分立电路里最常见的选择专用芯片把激励、放大、ADC 和断线检测集成到一起省模拟调试但成本高寄存器配置也要花时间。方案核心思路优点短板适用场景电桥 差分放大PT100 作为桥臂桥压差放大元件少成本低非线性、需要稳定桥压、共模高0~100°C、精度 1°C 左右恒流源 仪表放大1mA 恒流流过 PT100取差分电压线性好易做三线/四线需要匹配电阻和偏置模拟调试多工业测温、恒温控制专用 RTD 前端芯片内部完成激励和 ADC省事带故障检测成本高SPI 配置有门槛精度 0.1°C、小批量这套资料如果走的是分立链路我一般会先看恒流源是不是 1mA 左右。激励电流太小信号被运放失调吃掉太大PT100 自热又会引入慢漂移。1mA 下 0°C 的功耗只有 0.1mW100°C 时约 0.14mW自热通常可以接受。要是原理图上写着 5mA 甚至 10mA就要重新算自热误差尤其是探头封装散热差的时候。2.2 把 0.385mV/°C 放大到 ADC 能吃的范围PT100 的正温特性可以先用线性式估算R(T) ≈ 100 × (1 0.00385 × T)。按 -50~200°C 算电阻范围约 80.31~175.86Ω。选一个 100Ω 的基准电阻 Rref让同一个 1mA 电流流过 PT100 和 Rref取两者压差差分电压就是 I × (Rpt100 - Rref)范围约 -19.69~75.86mV。这个信号直接进 12 位 ADC 肯定不够看必须放大并加偏置。参数取值说明激励电流 I1mA自热小信号够用基准电阻 Rref100Ω0.01%低温漂对应 0°C 的 PT100差分电压范围-19.69~75.86mV按 -50~200°C 估算放大倍数 G20输出 -0.394~1.517V偏置 Vbias0.4V把负压抬到 ADC 正输入范围ADC 输入范围0.006~1.917V3.3V 参考下留足余量ADC 分辨率3.3V / 4095 ≈ 0.806mV12 位输入等效温度0.806mV / (0.385mV/°C × 20) ≈ 0.105°C单次采样理论值计算顺序不要乱先定量程再选激励电流接着选 Rref 和增益最后算偏置并校验 ADC 上下轨。上面这组参数里200°C 时输出约 1.917V离 3.3V 还有 1.38V 余量-50°C 时输出约 0.006V贴着 0V 但还没进死区。如果量程只要 0~150°C增益可以提到 25 左右如果坚持用 50 倍200°C 时输出会超过 3.3V高温段直接饱和。这个账不提前算后面调代码就是玄学。2.3 原理图落地时先检查哪几个节点拿到原理图不要先看单片机引脚分配先看模拟前端这几个节点。第一恒流源的负载范围要覆盖 PT100 的 80~176Ω 加上线阻断线时输出不能把运放顶到电源轨。第二差分放大的四个电阻或仪表放大器的增益电阻要匹配0.1% 起步否则共模抑制上不去。第三ADC 输入前要有 1kΩ 加 100nF 的 RC截止频率约 1.6kHz既能滤高频噪声又不会拖慢采样建立时间。第四模拟地和数字地要单点汇合继电器、显示屏、串口芯片的电流不要从采样地线上走。第五供电要干净ADC 参考最好用外部基准别直接拿单片机 VDDA 当基准屏幕一亮纹波就上来了。第六三线制不是接三根线就自动补偿需要两条匹配的电流路径或电桥结构如果只有一个恒流源三线制只能算部分补偿线阻还是会进结果。提示ADC 输入不要贴着 0V 和 3.3V 轨用留 50mV 以上余量否则运放输出饱和后软件滤波也救不回来。3. 程序框架拆解从 ADC 采样到 PT100 温度换算的代码落地程序不要写成「读一次 ADC 就显示」的循环。温度探头本身有热惯性但电源噪声和继电器动作是快的采样、滤波、换算、输出要分层。资料里的程序如果是 HAL 库风格常见结构是定时器触发 ADC、DMA 搬数、中值滤波加滑动平均、再走电阻和温度换算最后组帧上传。3.1 ADC 采样与滤波DMA、中值滤波和滑动平均先定采样率。温度显示刷新 2Hz 足够但 ADC 采样可以做到 100Hz用多余的采样点换稳定性。DMA 开双缓冲半满和全满中断各处理一半主循环只取滤波后的值。中值滤波取 5 点专门打掉继电器吸合那种单点尖峰滑动平均取 16 点把随机噪声压下去。#define ADC_N_MED 5 #define ADC_N_AVG 16 static uint16_t adc_med_buf[ADC_N_MED]; static uint16_t adc_avg_buf[ADC_N_AVG]; static uint8_t med_idx 0, avg_idx 0; /* 5 点中值滤波复制后插入排序取中间值 */ uint16_t median5(uint16_t *buf, uint16_t new_val) { uint16_t tmp[ADC_N_MED]; buf[med_idx] new_val; med_idx (med_idx 1) % ADC_N_MED; for (int i 0; i ADC_N_MED; i) tmp[i] buf[i]; for (int i 1; i ADC_N_MED; i) { uint16_t key tmp[i]; int j i - 1; while (j 0 tmp[j] key) { tmp[j 1] tmp[j]; j--; } tmp[j 1] key; } return tmp[ADC_N_MED / 2]; } /* 16 点滑动平均先填满再滚动 */ uint16_t moving_average16(uint16_t new_val) { static uint32_t sum 0; static uint8_t filled 0; sum - adc_avg_buf[avg_idx]; adc_avg_buf[avg_idx] new_val; sum new_val; avg_idx (avg_idx 1) % ADC_N_AVG; if (filled ADC_N_AVG) filled; return (uint16_t)(sum / filled); }这段代码里median5的窗口是 5 个采样点按 100Hz 算就是 50ms能压住窄脉冲但不会把真实温度变化抹平。moving_average16的窗口是 160ms输出更新率仍然是 100Hz但等效带宽降下来了。sum用 32 位16 个 12 位码值相加不会溢出。实际工程里可以把中值滤波放在 DMA 中断里做轻量处理滑动平均放主循环避免中断里做太多浮点运算。3.2 电压到电阻差分放大公式怎么写进代码ADC 码值先转电压再按差分放大关系反推 PT100 电阻。公式是 Vout Vbias G × I × (Rpt100 - Rref)反解得到 Rpt100 Rref (Vout - Vbias) / (G × I)。代码里把 VREF、G、I、Rref、Vbias 都做成宏或配置结构标定时只改参数不改公式。#define ADC_FULL_SCALE 4095.0f #define VREF_VOLT 3.300f #define GAIN 20.0f #define I_EXC_A 0.001f #define RREF_OHM 100.0f #define VBIAS_VOLT 0.400f float adc_to_voltage(uint16_t raw) { return (float)raw * VREF_VOLT / ADC_FULL_SCALE; } float voltage_to_resistance(float vout) { /* 先减偏置再除增益和激励电流最后加基准电阻 */ return RREF_OHM (vout - VBIAS_VOLT) / (GAIN * I_EXC_A); }ADC_FULL_SCALE用 4095 还是 4096 取决于标定方式12 位 ADC 常用 4095 做端点映射但最终以两点标定为准。VREF_VOLT不是随便填 3.3最好用万用表实测基准电压再写进参数。GAIN和I_EXC_A的误差会直接乘到电阻上所以这两个值要么用精密电阻算要么靠标定修正。VBIAS_VOLT是差分放大器输出的零点偏置单电源电路里通常由基准分压产生实测值比标称值可靠。如果原理图用的是专用 RTD 前端芯片这一节可以跳过程序直接读芯片的电阻寄存器但后面温度换算和标定思路仍然适用只是把「ADC 码值到电阻」换成「寄存器值到电阻」。3.3 电阻到温度Callendar-Van Dusen 正温公式与负温迭代PT100 的电阻温度关系不是一条直线。正温段用 Callendar-Van Dusen 方程C 项为 0负温段要把 C 项带上解析解不好直接写常用牛顿迭代。代码里先判断电阻是否大于等于 100Ω正温走二次方程负温走迭代迭代 4~5 次就够。#include math.h #define R0_OHM 100.0f #define CVD_A 3.9083e-3f #define CVD_B -5.775e-7f #define CVD_C -4.183e-12f float resistance_to_temp_c(float r) { if (r R0_OHM) { /* 正温R R0(1 A*T B*T^2)取正根 */ float disc CVD_A * CVD_A - 4.0f * CVD_B * (1.0f - r / R0_OHM); return (-CVD_A sqrtf(disc)) / (2.0f * CVD_B); } else { /* 负温牛顿迭代解 R R0[1 A*T B*T^2 C*(T-100)*T^3] */ float t (r / R0_OHM - 1.0f) / CVD_A; for (int i 0; i 5; i) { float t2 t * t; float t3 t2 * t; float f R0_OHM * (1.0f CVD_A * t CVD_B * t2 CVD_C * (t - 100.0f) * t3) - r; float df R0_OHM * (CVD_A 2.0f * CVD_B * t CVD_C * (4.0f * t3 - 300.0f * t2)); t - f / df; } return t; } }正温段的判别条件是r 100.0f对应 0°C 以上。disc是二次方程判别式正常参数下不会为负如果为负说明电阻值已经超出 PT100 合理范围程序要报故障而不是继续算。负温迭代的初值用线性式给收敛很快5 次迭代在 Cortex-M 上开销可以接受。系数 A、B、C 是 PT100 的标准系数不要随手改如果探头是 PT1000R0 和系数体系要整体换掉。3.4 串口帧与报警输出把温度变成可用的数据温度算出来只是内部变量要上传就得定帧格式。常见做法是帧头 0xAA 0x55、类型、4 字节浮点温度、2 字节 CRC小端发送。报警输出加回差比如上限 80°C 报警、降到 78°C 才解除避免继电器在阈值附近反复吸合。typedef struct { uint8_t head[2]; uint8_t type; float temp; uint16_t crc; } TempFrame; static uint16_t crc16_modbus(const uint8_t *data, uint16_t len) { uint16_t crc 0xFFFF; while (len--) { crc ^ *data; for (int i 0; i 8; i) crc (crc 1) ? (crc 1) ^ 0xA001 : (crc 1); } return crc; } void send_temp_frame(float temp) { TempFrame f; f.head[0] 0xAA; f.head[1] 0x55; f.type 0x01; f.temp temp; f.crc crc16_modbus((uint8_t *)f, sizeof(f) - 2); uart_send_bytes((uint8_t *)f, sizeof(f)); } /* 报警回差上限 80°C回差 2°C */ void alarm_task(float temp, uint8_t *alarm_on) { if (!(*alarm_on) temp 80.0f) *alarm_on 1; if ( (*alarm_on) temp 78.0f) *alarm_on 0; }帧结构里temp直接用 float调试方便但跨平台时要确认双方字节序。CRC 放在最后两字节接收端按同样结构校验。alarm_task只处理回差逻辑继电器驱动和硬件互锁要另做尤其是加热场景软件失效时不能只靠一个 GPIO 电平。串口上传周期建议 200~500ms太快会把显示和报警任务挤掉太慢又看不出阶跃响应。4. 标定与误差控制两点标定、线阻补偿和滤波参数怎么设PT100 采集系统装完板子不标定就敢写精度基本是给自己挖坑。标定不是把代码里的 100Ω 改成实测值就完事要把「ADC 码值到电阻」和「电阻到温度」分开看。前者靠两点标定锁增益和偏移后者靠标准系数和线制补偿。顺序反了后面调滤波只会越调越乱。4.1 两点标定用 100Ω 和 138.5Ω 把增益偏移锁死最稳的标定不是拿冰水和沸水而是用精密电阻箱替代 PT100。冰水受气压和冰水比例影响沸水受海拔影响实验室里看着是 0°C 和 100°C实际可能差零点几度。电阻箱直接给 100.00Ω 和 138.51Ω对应 0°C 和 100°C重复性好也不用等温度平衡。标定点电阻箱输出理论温度记录内容低点100.00Ω0°CADC 原始码值 20 次平均高点138.51Ω100°CADC 原始码值 20 次平均标定公式按电阻线性化写R k × raw b。低点 raw1 对应 100Ω高点 raw2 对应 138.51Ωk (138.51 - 100) / (raw2 - raw1)b 100 - k × raw1。把 k、b 写进 Flash上电先读标定参数读不到就用默认值并报未标定。typedef struct { float k; float b; uint32_t magic; } CalibParam; float raw_to_resistance(uint16_t raw, const CalibParam *c) { return c-k * (float)raw c-b; } void calib_two_point(uint16_t raw_at_100, uint16_t raw_at_13851, CalibParam *c) { c-k (138.51f - 100.0f) / ((float)raw_at_13851 - (float)raw_at_100); c-b 100.0f - c-k * (float)raw_at_100; c-magic 0x50433130; /* 标定参数有效标志 */ }这段代码只标定电阻链路温度换算仍然走标准公式。raw_at_100和raw_at_13851要先做中值加平均不能拿单次采样。magic用来判断 Flash 里是不是有效参数避免第一次上电读到全 0xFF 算出离谱的 k。标定后至少复测 50Ω、150Ω 两个中间点看非线性误差别只盯两个端点。4.2 三线制与四线制线阻到底吃掉了多少温度PT100 每 0.385Ω 对应 1°C0.1Ω 线阻就是约 0.26°C。两线制把两根引线电阻全算进探头电阻探头线越长、线越细误差越大。三线制用三条线两条电流路径匹配时可以把引线电阻抵消掉大部分但匹配不好仍会剩误差。四线制把电流回路和电压测量回路分开线阻基本不进结果是精度最高的接法。线制接线复杂度线阻影响适用两线制最低全部计入0.1Ω 约 0.26°C短距离、低精度三线制中等匹配后大部分抵消工业现场常见四线制最高基本消除高精度、实验室原理图如果是三线制要检查两条引线是不是接到匹配的电流源或差分输入端。只把第三根线接地不叫三线补偿。四线制则要确认激励电流从一对线走差分放大从另一对线取压ADC 前端的高阻抗不能把电流引到测量线上。探头屏蔽层单端接地别两头都接否则地环流会变成低频漂移。4.3 滤波与采样率显示 2Hz 但采样 100Hz 的参数搭配采样 100Hz、显示 2Hz 是个好搭配前端有足够点数做滤波人眼又不需要看 100Hz 的跳动。中值 5 点加滑动平均 16 点等效延迟大约 80~100ms对温度这种慢变量完全够。如果还嫌跳再串一个一阶 IIRalpha 取 0.05~0.1别一上来就 0.01否则恒温箱到了设定值还在慢慢爬。float iir_lowpass(float x, float *y, float alpha) { /* alpha 越小越平滑滞后越大0.1 对应约 10 个采样周期的时间常数 */ *y alpha * (x - *y); return *y; }alpha取 0.1 时按 100Hz 采样算时间常数约 0.1s90% 响应约 0.23s取 0.02 时时间常数约 0.5s响应明显变慢。恒温控制里滤波太狠会让 PID 以为温度没变化输出继续加等滤波值上来已经超调。我一般让显示滤波和控温滤波分开显示可以重一点控温用轻量中值加短平均。注意1mA 连续激励下自热很小但如果原理图把电流提到 5mAPT100 功耗约 2.5mW探头封装散热差时可能带来零点几度的自热漂移标定时要等热平衡。5. 避坑与排查PT100 采集翻车的 4 个现场记录PT100 前端的坑很少是单一原因往往是电源、地、线制和代码参数一起作用。下面这四类现象在调试现场出现频率最高按「现象 → 原因 → 解决」记比只看波形截图有用。5.1 读数跳变电源纹波和地线把 12 位 ADC 打回 8 位现象探头放在恒温槽里温度读数在 24.3~26.8°C 之间跳手碰板子或屏幕亮起时跳得更厉害万用表本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。