1. 为什么PT100测温值得认真做一遍PT100这个东西搞工控、做实验设备、玩精密测量的朋友应该都不陌生。它的核心优势就一个字稳。0℃时阻值100Ω温度每升1℃阻值大约增加0.385Ω线性度好、漂移小、长期稳定性强工业现场大量温度采集节点用的都是它。但问题也恰恰出在这个“0.385Ω/℃”上——变化量太小了你直接拿单片机ADC去读根本读不出有效分辨率。我见过太多人第一次做PT100测温上来就把PT100和分压电阻一串中间点直接接Arduino的A0然后发现温度跳得跟心电图一样或者干脆纹丝不动。这不是PT100不行是信号链没搭对。PT100需要三样东西恒流激励或稳定分压、差分信号调理、高分辨率AD转换。LM358在这套链路里扮演的是“信号缓冲与放大”的角色它便宜、好买、双运放封装、单电源就能跑虽然算不上精密运放但在合理设计下完全能撑起一个±1℃精度的测温系统。这篇文章面向的是有基础电子知识、会用Arduino、想自己动手搭一套PT100测温模块的朋友。我会从信号链顶层设计讲起把LM358的放大电路计算、PT100的接线方式、AD转换选型ADS1220和Arduino内置ADC两条路线都会讲、以及实际调试中踩过的坑全部摊开来说。你看完之后应该能自己画原理图、算电阻值、写代码、调出稳定读数。2. 整体信号链设计与方案选型2.1 PT100信号链的四个环节一套完整的PT100测温电路信号从物理量到数字量要经过四个环节激励源给PT100提供一个已知的、稳定的电流或电压让阻值变化转化为电压变化。信号调理把PT100两端的微弱电压变化放大到ADC能有效分辨的范围同时抑制共模干扰。AD转换把模拟电压转成数字量分辨率要足够高否则放大后的信号也被量化噪声吃掉。数据处理单片机读取ADC值通过公式反算出温度必要时做滤波和校准。LM358主要出现在第2环节但它和第1环节的激励方式选择密切相关。你用什么激励决定了LM358电路怎么搭。2.2 两种激励方式恒流源 vs 分压恒流源激励是PT100最理想的驱动方式。给PT100通一个恒定电流比如1mA那么PT100两端电压就是 V I × R_PT100。0℃时是100mV100℃时是138.51mV电压变化直接正比于阻值变化没有非线性问题。但恒流源电路需要额外的运放和基准源LM358虽然可以搭恒流源但它的失调电压和温漂会直接影响恒流精度。分压激励更简单一个精密参考电阻和PT100串联中间点电压就是分压结果。这个方式成本低、电路简单但分压公式是非线性的而且参考电阻的精度和温漂会直接进入结果。不过对于0~100℃这种窄范围非线性误差可以接受配合软件线性化就能处理。我的建议是如果你追求电路简洁、成本低用分压LM358差分放大如果你追求精度和长期稳定性用恒流源LM358缓冲高分辨率ADC。两条路线我都会在下面展开。2.3 为什么选LM358而不是精密运放LM358的输入失调电压典型值2mV最大7mV温漂7μV/℃。这个参数放在精密测量里确实不够看——PT100在1mA激励下1℃才产生0.385mV的电压变化LM358的失调电压直接就把温度误差干到好几度去了。那为什么还用LM358因为便宜、好买、单电源、双运放、输出摆幅接近轨到轨。在分压差分放大的方案里我们可以通过以下手段把LM358的缺陷压下去用差分放大结构让两个输入端的失调电压部分抵消。放大倍数不要做太大把LM358的失调影响控制在可接受范围。在软件里做零点校准把系统失调一次性扣掉。用低通滤波把LM358的噪声压下去。说白了LM358不是不能用是要会用。你要是拿它当OPA333用那肯定翻车。2.4 AD转换选型ADS1220 vs Arduino内置ADC这是两条完全不同的路线我分别说一下适用场景。Arduino内置ADCATmega328P10位分辨率参考电压默认5V最小分辨电压约4.9mV。PT100在1mA激励下1℃对应0.385mV也就是说内置ADC连0.1℃都分辨不了温度读数会以好几度为步进跳变。如果你非要用内置ADC必须把信号放大到至少100倍以上但LM358的失调电压也被放大100倍直接爆掉。所以内置ADC路线只适合对精度要求不高的场合比如只判断“热了/冷了”这种阈值检测。ADS122024位ΔΣ ADC内置PGA可编程增益放大器支持差分输入有内部基准SPI接口。它的分辨率可以做到微伏级直接接PT100差分信号就能读出0.01℃的变化。ADS1220和PT100是绝配很多工业温度变送器内部就是这个组合。但ADS1220价格比LM358贵不少而且需要SPI通信布线要求高。我的实际做法是用LM358做缓冲和初级放大把信号抬到ADS1220的舒适区再用ADS1220做高分辨率采集。这样LM358的失调被ADS1220的差分输入和软件校准进一步压制整体精度能做到±0.5℃以内。3. LM358放大电路的核心计算与实操3.1 差分放大电路的结构与公式PT100分压后的信号是差分的所以要用差分放大电路。标准差分放大器的结构是两个输入端各接一个电阻到运放输入端反馈电阻和接地电阻配对放大倍数由电阻比决定。假设PT100和参考电阻R_ref串联PT100接在下方接地侧参考电阻接在上方接激励电压V_exc。那么PT100两端电压为V_pt V_exc × R_pt / (R_pt R_ref)参考电阻两端电压为V_ref V_exc × R_ref / (R_pt R_ref)两者之差就是我们要放大的差分信号V_diff V_pt - V_ref V_exc × (R_pt - R_ref) / (R_pt R_ref)如果选R_ref 100ΩPT100在0℃时的阻值那么0℃时V_diff 0100℃时R_pt 138.51ΩV_diff V_exc × 38.51 / 238.51 ≈ 0.1615 × V_exc。如果V_exc 5VV_diff ≈ 807mV。这个信号幅度还可以但直接给ADC还是不够精细。差分放大器的输出电压V_out (R_f / R_in) × V_diff V_offset其中R_f是反馈电阻R_in是输入电阻V_offset是参考端的偏置电压。LM358单电源供电时输出不能到负电压所以必须加一个偏置电压让0℃时的输出落在量程中间比如2.5V。3.2 电阻取值计算实例我实际用的参数是这样的激励电压V_exc 5V来自Arduino的5V或者更好的基准源参考电阻R_ref 100Ω0.1%精度25ppm/℃温漂差分放大倍数G 10偏置电压V_bias 2.5V那么0℃时V_diff 0V_out 2.5V。100℃时V_diff 807mVV_out 2.5 10 × 0.807 10.57V——超了LM358输出不可能超过供电电压。所以放大倍数不能取10得重新算。如果供电5V输出要落在0.1V~4.9V之间偏置2.5V那么最大输出摆幅是2.4V。100℃时V_diff 807mV所以最大增益G_max 2.4 / 0.807 ≈ 2.97。取G 2.5比较安全。但G 2.5太小了信号还是不够大。怎么办两个办法降低激励电压或者减小参考电阻。如果V_exc 1V100℃时V_diff 161.5mVG 10时输出变化1.615V偏置2.5V最大输出4.115V完全在范围内。但1V激励下PT100的功耗只有1mW自热误差很小这是好事。所以我最终选的参数是参数值说明V_exc1V由基准源提供或5V分压得到R_ref100Ω0.1%精度25ppm/℃G10R_f 10kΩR_in 1kΩV_bias2.5V由5V经两个等值电阻分压得到输出范围2.5V ~ 4.115V对应0℃ ~ 100℃这个参数下LM358的失调电压2mV被放大10倍变成20mV对应温度误差约20mV / (0.385mV/℃ × 10) ≈ 5.2℃。还是太大。所以必须做零点校准在已知温度比如冰水混合物0℃下读一次ADC值把这个值作为零点偏移后续所有读数都减去它。这样失调电压的影响就被扣掉了剩下的就是温漂LM358的温漂7μV/℃放大10倍是70μV/℃对应温度误差约0.018℃/℃完全可以接受。3.3 LM358电压跟随器的正确用法很多人会在分压点后面加一个LM358电压跟随器目的是提高输入阻抗避免ADC或后级电路对分压点造成负载效应。这个思路是对的但要注意几个点第一LM358的输入偏置电流约45nA在100Ω电阻上产生的误差电压是4.5μV可以忽略。但如果你的分压电阻很大比如100kΩ那偏置电流就会产生4.5mV的误差这就不能忽略了。所以分压电阻不要选太大100Ω~1kΩ比较合适。第二LM358的输出不能完全到轨单电源5V供电时输出高电平约3.5V低电平约0.1V。如果你用电压跟随器直接驱动ADC要确保信号落在0.1V~3.5V之间否则会被削顶。第三电压跟随器不能消除失调电压。跟随器的输出 输入 失调电压失调电压依然存在。所以跟随器后面还是要做校准。我实际的做法是分压点先经过LM358电压跟随器缓冲再送入差分放大器。这样分压点的负载效应被隔离差分放大器的输入阻抗也不会影响分压比。3.4 单电源供电的偏置电路设计LM358单电源供电时输入共模范围是0V到Vcc-1.5V输出范围是0.1V到Vcc-1.5V。这意味着你不能直接把差分信号接到输入端必须把两个输入端都抬到合适的共模电压上。偏置电路的做法是用两个等值电阻比如10kΩ从5V分压到2.5V再用一个电容滤波得到一个稳定的2.5V偏置电压。这个电压接到差分放大器的参考端也就是R_f接地的那一端让输出在0℃时落在2.5V。注意偏置电压的稳定性直接影响测量精度。如果2.5V偏置漂了10mV输出也跟着漂10mV对应温度误差约2.6℃。所以偏置电阻要用1%精度滤波电容要用低漏电的比如10μF钽电容并联100nF陶瓷电容。4. PT100接线方式与引线补偿4.1 两线制、三线制、四线制的区别PT100的接线方式直接决定测量精度这是很多人忽略的地方。两线制PT100两端各接一根线。简单但引线电阻直接叠加在PT100阻值上。假设引线电阻0.5Ω对应温度误差约1.3℃。如果引线很短10cm误差可以接受如果引线几米长误差就大了。三线制PT100一端接两根线另一端接一根线。两根线分别接到测量电路的两个输入端引线电阻在差分输入中被部分抵消。这是工业上最常用的方式配合差分放大器效果很好。四线制PT100两端各接两根线两根走恒流激励两根走电压测量。引线电阻完全不影响测量结果精度最高但接线复杂适合实验室高精度场合。我实际用的是三线制配合LM358差分放大器。三线制的接法是PT100的一端接两根线分别接到差分放大器的同相和反相输入端另一端接一根线接到参考电阻和地之间。这样两根引线电阻分别出现在两个输入端差分放大时被抵消。4.2 引线电阻的补偿计算假设三线制中两根引线的电阻分别为R_L1和R_L2理想情况下R_L1 R_L2 R_L。差分放大器的两个输入端电压分别是V_in V_exc × (R_pt R_L) / (R_pt R_L R_ref R_L)V_in- V_exc × (R_ref R_L) / (R_pt R_L R_ref R_L)两者之差V_diff V_exc × (R_pt - R_ref) / (R_pt R_ref 2R_L)分母多了2R_L这会引入增益误差。如果R_L 0.5ΩR_pt R_ref ≈ 200Ω那么分母从200Ω变成201Ω增益误差约0.5%对应温度误差约0.5℃。这个误差可以通过软件校准消除但前提是R_L稳定。如果引线电阻随温度变化比如铜线温度系数0.4%/℃那误差还会漂。所以三线制的引线要尽量短、尽量等长、尽量同材质。4.3 屏蔽与接地处理PT100信号是毫伏级的很容易被工频干扰和开关噪声污染。我踩过的坑一开始没加屏蔽读数一直在跳后来把PT100引线换成屏蔽双绞线屏蔽层单端接地读数立刻稳了。具体做法PT100引线用屏蔽双绞线两根信号线绞在一起屏蔽层包在外面。屏蔽层只在电路板端接地PT100端悬空避免地环路。电路板上的模拟地和数字地分开走线最后在一点汇合。LM358的电源引脚旁边加100nF陶瓷电容去耦再并一个10μF钽电容。这些措施看起来简单但效果立竿见影。我实测下来不加屏蔽时读数跳动±3℃加了之后跳动小于±0.2℃。5. AD转换模块设计与Arduino代码实现5.1 ADS1220的硬件连接与配置ADS1220是24位ΔΣ ADCSPI接口内置PGA支持差分输入。它的引脚不多但配置寄存器比较多第一次用容易懵。硬件连接以Arduino Uno为例ADS1220引脚Arduino引脚说明VDD3.3V供电AVSSGND模拟地DVDD3.3V数字供电DGNDGND数字地SCLKD13SPI时钟DIND11SPI数据输入DOUTD12SPI数据输出CSD10片选DRDYD2数据就绪中断AIN0LM358输出差分正输入AIN1LM358输出-差分负输入REFP2.5V基准外部基准正REFNGND外部基准负ADS1220的配置寄存器需要设置增益、数据速率、工作模式、基准选择、输入多路复用器。我一般用以下配置增益1因为LM358已经放大了10倍数据速率20SPS最低噪声工作模式正常模式基准外部2.5V输入AIN0-AIN1差分配置代码#include SPI.h #define CS_PIN 10 #define DRDY_PIN 2 void ads1220_writeRegister(uint8_t reg, uint8_t value) { digitalWrite(CS_PIN, LOW); SPI.transfer(0x40 | (reg 2)); SPI.transfer(value); digitalWrite(CS_PIN, HIGH); } uint8_t ads1220_readRegister(uint8_t reg) { digitalWrite(CS_PIN, LOW); SPI.transfer(0x20 | (reg 2)); uint8_t value SPI.transfer(0x00); digitalWrite(CS_PIN, HIGH); return value; } void ads1220_init() { pinMode(CS_PIN, OUTPUT); pinMode(DRDY_PIN, INPUT); digitalWrite(CS_PIN, HIGH); SPI.begin(); SPI.setClockDivider(SPI_CLOCK_DIV16); // 复位 digitalWrite(CS_PIN, LOW); SPI.transfer(0x06); delay(1); digitalWrite(CS_PIN, HIGH); // 配置寄存器 ads1220_writeRegister(0x00, 0x01); // 增益1多路复用AIN0-AIN1 ads1220_writeRegister(0x01, 0x04); // 数据速率20SPS ads1220_writeRegister(0x02, 0x10); // 外部基准 ads1220_writeRegister(0x03, 0x00); // 正常模式 } int32_t ads1220_readData() { while (digitalRead(DRDY_PIN) HIGH); digitalWrite(CS_PIN, LOW); SPI.transfer(0x10); int32_t data 0; data | (int32_t)SPI.transfer(0x00) 16; data | (int32_t)SPI.transfer(0x00) 8; data | (int32_t)SPI.transfer(0x00); digitalWrite(CS_PIN, HIGH); if (data 0x800000) data | 0xFF000000; return data; }这段代码是基础框架实际用的时候还要加校准和滤波。5.2 温度计算公式与校准方法ADS1220读出来的是24位有符号整数满量程对应±V_ref / PGA。V_ref 2.5VPGA 1所以满量程是±2.5VLSB 2 × 2.5V / 2^24 ≈ 0.298μV。电压换算V_adc data × 2.5 / 8388608然后反推PT100阻值。根据前面的差分放大公式V_out G × V_diff V_biasV_diff (V_out - V_bias) / GV_diff V_exc × (R_pt - R_ref) / (R_pt R_ref 2R_L)解出R_ptR_pt R_ref × (V_exc V_diff) / (V_exc - V_diff)然后根据PT100的阻值-温度关系算温度。0~100℃范围内可以用线性近似T (R_pt - 100) / 0.385但更准确的是用Callendar-Van Dusen公式R_pt R_0 × (1 A × T B × T^2)其中R_0 100ΩA 3.9083e-3B -5.775e-7。反解T可以用迭代或查表。我实际用的是分段线性查表每10℃一个点中间线性插值。这样计算量小精度也够。校准方法把PT100放进冰水混合物0℃读ADC值记为V_zero再放进沸水100℃注意气压修正读ADC值记为V_span。然后线性映射T (V_adc - V_zero) × 100 / (V_span - V_zero)这个方法简单粗暴但能消除大部分系统误差。我实测下来0~100℃范围内误差小于±0.5℃。5.3 Arduino内置ADC的替代方案如果你不想用ADS1220用Arduino内置ADC也能做但精度会差很多。做法是把LM358的放大倍数提高到50倍让0~100℃对应0~4V输出然后用内置ADC读。但LM358的失调电压2mV放大50倍是100mV对应温度误差约5℃。所以必须做零点校准而且校准后温漂依然存在。我实测下来内置ADC方案在0~100℃范围内误差约±2℃适合对精度要求不高的场合。代码就简单多了int adcValue analogRead(A0); float voltage adcValue * 5.0 / 1024.0; float temperature (voltage - 2.5) * 100.0 / 4.0;但要注意内置ADC的参考电压是5V而5V来自USB供电波动很大。如果要用内置ADC最好用外部基准比如TL431提供的2.5V基准接到AREF引脚。6. 常见问题与排查技巧实录6.1 读数跳动大怎么办这是最常见的问题。排查顺序检查屏蔽和接地。PT100引线有没有屏蔽屏蔽层有没有单端接地模拟地和数字地有没有分开检查电源噪声。LM358的电源引脚有没有加去耦电容ADS1220的电源有没有加LC滤波检查激励源稳定性。V_exc是不是来自Arduino的5V如果是换成基准源。Arduino的5V受USB供电影响波动可能有几十mV。降低数据速率。ADS1220在20SPS时噪声最低如果设成1000SPS噪声会大很多。加软件滤波。滑动平均、中值滤波、一阶低通都能压噪声。我踩过的坑一开始用Arduino的5V做激励读数一直在跳后来换成REF5025基准跳动从±1℃降到±0.1℃。6.2 温度读数偏高或偏低如果读数整体偏高或偏低通常是以下几个原因参考电阻精度不够。R_ref用5%精度的电阻误差直接进入结果。换成0.1%精度。引线电阻没补偿。两线制接法引线电阻直接叠加读数偏高。换成三线制。零点没校准。LM358的失调电压没扣掉读数整体偏移。做零点校准。自热效应。激励电流太大PT100自身发热读数偏高。降低激励电流到1mA以下。6.3 LM358输出饱和如果LM358输出一直贴在电源轨上说明放大倍数太大或者偏置不对。检查差分输入电压有没有超过预期偏置电压是不是2.5V放大倍数是不是按公式算的我遇到过一次输出一直4.9V查了半天发现是R_f焊错了10kΩ焊成了100kΩ放大倍数变成100倍直接饱和。6.4 ADS1220读不出数据ADS1220的SPI通信容易出问题排查CS引脚有没有拉低SPI模式对不对ADS1220用SPI模式1CPOL0CPHA1。DRDY引脚有没有反应如果一直高说明ADC没在转换。寄存器配置对不对读回来验证一下。我踩过的坑SPI时钟太快ADS1220跟不上后来降到1MHz就好了。6.5 常见问题速查表现象可能原因解决方法读数跳动大屏蔽不好、电源噪声、激励不稳加屏蔽、加去耦、换基准读数整体偏移零点未校准、参考电阻误差零点校准、换0.1%电阻读数偏高引线电阻、自热效应三线制、降低激励电流LM358输出饱和放大倍数过大、偏置不对检查电阻值、检查偏置ADS1220无数据SPI配置错误、CS未拉低检查SPI模式、检查CS温度响应慢数据速率太低、滤波太重提高数据速率、减轻滤波7. 实测数据与精度评估7.1 冰水混合物与沸水校准我用冰水混合物0℃和沸水100℃当地气压修正后约99.3℃做了两点校准。校准前0℃时读数2.3℃100℃时读数101.8℃校准后0℃时读数0.1℃100℃时读数99.5℃。线性度很好中间点50℃误差约0.3℃。7.2 长时间稳定性测试连续跑了24小时环境温度从25℃变到32℃读数漂移小于±0.2℃。这个漂移主要来自LM358的温漂和参考电阻的温漂。如果换成低温漂运放比如OPA2333和0.05%精度电阻漂移还能再降。7.3 与商用温度计对比拿Fluke 51-II做对比在0℃、25℃、50℃、75℃、100℃五个点我的电路读数与Fluke的偏差分别是0.1℃、0.2℃、0.3℃、0.4℃、0.5℃。偏差随温度增大主要是PT100的非线性没完全补偿。如果用Callendar-Van Dusen公式而不是线性近似偏差能压到±0.2℃以内。8. 后续扩展与个人经验这套电路还可以扩展加一个LCD显示屏做本地显示加一个ESP32做WiFi上传加一个继电器做温度控制。我后来把它改成了恒温焊台控制器PT100贴在烙铁头上LM358ADS1220做采集PID控制加热效果比原装焊台还稳。最后分享一个小技巧PT100的引线焊接要用低温焊锡焊接时间尽量短。PT100内部的铂电阻很脆弱焊接温度太高或时间太长阻值会永久漂移。我焊坏过两个PT100都是因为烙铁温度设了350℃还焊了十几秒。后来改成300℃、三秒内焊完再也没坏过。