
做温度采集最怕的不是传感器贵而是数据看起来有小数点、实际连0.5℃都对不上。前一阵子项目里需要检测一路温度目标定在0.1℃级别我先试了DS18B20分辨率0.0625℃看着还行但出厂校准的绝对精度和长期一致性都不太能打后来换成ADS1110PT1000的组合啃完硬件电路、I2C时序和标定方法之后读数总算稳住了。这篇就按我实际搭建的流程完整走一遍从方案选型、硬件设计、I2C读写、温度换算到标定避坑都放出来适合手里有ADS1110和PT1000、想自己搭高分辨率测温板的同学参考。1. 方案选型这套组合到底牛在哪1.1 PT1000传感器为什么值得选温度传感器能选的很多但要做到0.1℃级别第一关就是传感器本身的重复性和稳定性。NTC热敏电阻便宜、灵敏度高一颗几毛钱可它的阻值温度曲线每家都不一样互换性差放着放着自己还会漂DS18B20适合“大概准”出厂精度大概±0.5℃分辨率虽然能到0.0625℃但芯片自己发热和内部校准精度摆在那里想靠它卡0.1℃比较勉强。PT1000属于铂电阻温度传感器核心是铂的电阻温度特性材料本身稳定、曲线有国际标准IEC 60751不同厂家做出来的传感器一致性远好于NTC。它和常见的PT100比优势也明显同样是1mA激励电流PT100一个摄氏度只变约0.39ΩPT1000变约3.9Ω输出信号大了十倍。用PT100还要担心导线电阻引入的误差因为100Ω基底阻抗太低PT1000阻抗高普通短引线的影响基本可以忽略电路上也更省事。我实际用下来PT1000的缺点主要是贵一点而且对高精度测量来说激励电流不能太大否则自热效应会自己把自己测高。后面电路设计里会专门处理这个问题。1.2 ADS1110这颗ADC好在哪ADS1110是TI的一颗16位delta-sigma ADCI2C接口内置2.048V参考电压内部有1/2/4/8倍可编程增益输出速率可以选15/30/60/240SPS封装很小单路差分输入。对单点测温来说这配置刚好够用而且I2C总线只需要两根线和MCU对接非常方便。有人会问ADS1115不香吗ADS1115四通道、可编程地址、16位功能更多价格也不贵。但如果只测一路温度ADS1110体积更小外围更少I2C时序逻辑也更简单。这篇以ADS1110为例调试方法换到ADS1115同样适用区别主要是寄存器定义和地址位不一样。这颗ADC最值钱的地方是16位输出和内置参考。在PGA1时最低位LSB对应62.5μV理论上能分辨很小的电压变化。不过要注意16位是“理论分辨率”实际噪声和稳定性要靠电路和软件共同保证不是插上电就自动16位干净数据。1.3 0.1℃对应的物理量变化想做出0.1℃精度先要清楚0.1℃在电学上到底是多少。PT1000在0℃附近阻值约1000Ω温度系数约3.9083Ω/℃。也就是说0.1℃对应约0.39Ω的变化。如果采用后面推荐的2.5V参考电压、1kΩ精密电阻和PT1000分压的电路在0℃时PT1000两端电压为1.25VADC原始码约为20000。此时温度每变化0.1℃电压大约变化244μV折合ADC码值约4个LSB。这个数据说明两件事一是ADS1110默认配置下能覆盖这个量程二是想稳定分辨0.1℃软件里必须做滤波和多次平均否则噪声会把这些码值吃掉。2. 硬件电路和精度预算2.1 电路结构与接线推荐电路采用“精密基准激励电阻分压”的方式。PT1000放在下桥臂上桥臂用一颗1kΩ精密电阻激励电压来自LM4040-2.5基准而不是直接拿单片机3.3V供电这样电源波动不会直接变成测量误差。接线关系可以按下面这张表来理解3.3V/5V -- R1(470Ω/1.5kΩ) -- LM4040-2.5阴极(输出2.5V) LM4040-2.5阳极 -- GND 2.5V节点 -- RB(1kΩ 0.1%) -- PT1000上端 PT1000下端 -- GND PT1000上端 -- ADS1110 IN GND -- ADS1110 IN- 3.3V -- ADS1110 VDD GND -- ADS1110 GND ADS1110 SCL -- MCU SCL ADS1110 SDA -- MCU SDA ADDR引脚 -- GND SCL/SDA各接一颗4.7kΩ上拉到3.3VR1的选择和供电电压有关用3.3V供电时选470Ω左右用5V供电时选1.5kΩ左右目的是在给分压电路供电的同时让LM4040还有足够的阴极工作电流。LM4040是并联型基准方向上别搞反有字那一面输出接2.5V节点没字那一面接地反了输出只剩二极管压降读数会整体偏低。我还在IN对地并联了一颗0.1μF电容对抑制空间耦合进来的工频干扰很有帮助。这个电容放在ADC输入端相当于给传感器电压做了低通滤波不会改变直流分压结果。2.2 关键器件选型原则电阻分压方案里RB是误差核心。我选的是1kΩ、0.1%、25ppm/℃的金属膜电阻。如果预算允许升级到0.01%效果更好但0.1%也够用因为后面标定环节能用标准电阻把比例误差消掉前提是这颗电阻温漂小。PT1000传感器建议选Class A或1/3DIN等级。Class A在0℃附近的出厂偏差约±0.15℃说实话光靠传感器本身出厂精度卡0.1℃是勉强的所以要做标定。传感器引脚尽量短如果引线很长要考虑线阻或者用四线制接法。LM4040-2.5的选择要点是初始精度0.1%、温漂50ppm以下。它的输出端并一颗0.1μF陶瓷电容放在靠近基准引脚的位置能让高频噪声更干净。2.3 精度误差预算把误差来源列出来做方案时才不会只看“16位ADC”几个字就以为万事大吉。下面是我在项目里估过的一张误差表误差来源典型量级影响对策PT1000出厂偏差(Class A)0.15℃0℃绝对温度偏选更好等级或标定RB电阻0.1%约0.3℃阻值比例偏改用0.01%或标定LM4040初始偏差0.1%约0.5℃整体比例偏用比值法标定抵消ADS1110增益误差0.05%左右整体比例偏标定时一起抵消自热效应通常零点零几度读数偏高降低激励电流、良好热接触噪声和干扰1~2个LSB读数跳动软件滤波、输入并联电容这里有个关键认知所谓0.1℃精度不是把所有器件买回来插上就自动达到而是“传感器激励ADC标定滤波”这套系统的综合结果。想做绝对温度标定步骤躲不开。3. ADS1110的I2C读写与配置3.1 地址怎么定ADS1110的7位I2C地址由ADDR引脚的状态决定。把ADDR接地是最常见的用法地址是0x48把ADDR接到VDD、SDA、SCL会得到另外几个地址。我一开始图省事让ADDR悬空结果总线扫描时地址飘忽一会儿0x48一会儿0x49后来直接接GND就稳定了。如果只想快速跑通记住默认地址0x48就行。以后想在一条I2C总线上挂多颗ADS1110再去看数据手册里的地址表把ADDR接不同位置即可。地址不够用的话还可以用TCA9548A这类I2C多路切换器扩展总线。3.2 读转换结果的完整流程ADS1110是连续转换模式主机不需要每次读之前写寄存器地址直接发起读操作从机就会连续送出3个字节转换结果高字节、转换结果低字节、配置寄存器字节。把前两个字节拼成有符号16位整数就是当前ADC原始码。Arduino下面这段代码可以直接用#include Wire.h #define ADS1110_ADDR 0x48 int16_t readADS1110Raw() { Wire.requestFrom((int)ADS1110_ADDR, 3); while (Wire.available() 3) { delay(1); } uint8_t high Wire.read(); uint8_t low Wire.read(); uint8_t config Wire.read(); // 顺手读回配置方便确认 return (int16_t)((high 8) | low); } void setup() { Wire.begin(); Serial.begin(115200); } void loop() { int16_t raw readADS1110Raw(); // PGA1时LSB62.5uV double voltage raw * 0.0000625; Serial.print(raw); Serial.print(raw); Serial.print( voltage); Serial.println(voltage, 6); delay(500); }注意拼接时一定要转成int16_t直接拿int接容易出现符号扩展问题。读数在0~2.048V范围内时raw是正数不需要操心负电压但代码习惯上还是用有符号类型接以后真遇到负输入也不会懵。3.3 配置寄存器修改默认配置下PGA1、数据速率15SPS正好适合我们这个电路。15SPS虽然慢但噪声低温度本来就是慢变量用不着高速采样。如果之后想改增益或速率需要往ADS1110写一个配置字节。写入方式是一帧I2C传输直接写一个字节void writeADS1110Config(uint8_t cfg) { Wire.beginTransmission(ADS1110_ADDR); Wire.write(cfg); uint8_t err Wire.endTransmission(); if (err ! 0) { Serial.print(config write error: ); Serial.println(err); } }常见配置字节整理如下PGA和速率按位拼起来就行配置字节PGA数据速率0x001倍15SPS0x041倍30SPS0x081倍60SPS0x0C1倍240SPS0x202倍15SPS0x404倍15SPS0x608倍15SPS写配置之前建议先把当前配置字节读回来看一眼确认默认值然后再只改需要的位。我踩过一次坑直接把整颗芯片的配置覆盖掉忘记保留其他位结果PGA和速率都被改乱输出数据直接飞了。3.4 开漏输出与上拉电阻的底层逻辑很多人学I2C时最困惑的就是“为什么一定要上拉电阻”。I2C的SDA和SCL是开漏结构设备只能把线拉低不能主动把线推高。没人拉的时候线上电平靠上拉电阻拉到高电平。这就好比赛跑比赛时每台设备只能按下“暂停”按钮让跑道低下去松开按钮后必须有个弹簧把按钮弹回高位这个弹簧就是上拉电阻。这样的好处是多个设备可以并联在同一条线上实现“线与”逻辑任意一个设备拉低整条线就是低电平不会出现两个设备同时一边输出高一边输出低导致短路同时不同电压域的设备也更容易配合只要上拉电阻接到合适的电平。上拉电阻不能随便选。阻值太小设备拉低时电流太大输出低电平可能不够低从机就可能读不到“0”阻值太大和总线寄生电容组成的RC充电时间太长上升沿太慢高速通信时就容易误码。我常用的经验值是400kHz速率用2.2kΩ100kHz速率用4.7kΩ。短距离、设备少可以用10kΩ但出现通信不稳定就换小一点长线或者设备多也别小于2.2kΩ否则低电平可能不合格。4. I2C调试心得从扫描异常到波形确认4.1 上电先看静态电平I2C调试的第一步不是写代码而是拿万用表量静态电平。先给整个板子上电量SCL和SDA对GND电压。正常情况下两根线都应该被上拉到接近3.3V。如果哪根线是0V说明总线被某个设备拉死了或者上拉电阻没焊、焊错、没接电源。这时候先别急着刷固件先把硬件问题找出来。还有一种情况是SDA和SCL装反了量到的电平看起来没问题但怎么扫描都扫不到设备。我最初就干过这事把两颗4.7kΩ上拉都接对了但SDA和SCL接到MCU时交叉了扫描结果全是空。后来用逻辑分析仪一看波形才发现地址位时序完全对不上。4.2 用I2C Scanner找地址Arduino官方社区流传的I2C Scanner代码很好用几行就能扫出总线上所有设备的7位地址。我第一次焊完板子先跑扫描程序看到0x48出现在串口输出的那一刻心里就踏实了一半。#include Wire.h void setup() { Wire.begin(); Serial.begin(115200); Serial.println(I2C Scanner start); } void loop() { byte error, address; int nDevices 0; for (address 1; address 127; address) { Wire.beginTransmission(address); error Wire.endTransmission(); if (error 0) { Serial.print(Found I2C device at 0x); if (address 16) Serial.print(0); Serial.println(address, HEX); nDevices; } } if (nDevices 0) { Serial.println(No I2C device found); } delay(1000); }如果扫描结果不稳定一会儿能找到一会儿找不到优先怀疑电源接触、地址脚悬空、上拉电阻阻值不合适这三类问题。不要急着换芯片先查这几样。4.3 逻辑分析仪怎么看I2C正经调I2C逻辑分析仪比示波器还顺手。把逻辑分析仪的地接板子GND一个通道夹SDA一个通道夹SCL采样率调到1MHz以上。400kHz总线建议用4MHz采样率否则上升沿细节看不清。很多逻辑分析仪软件自带I2C解码器解码后能看到Start、地址字节、ACK/NAK、数据字节、Stop一眼就能定位问题在哪。看波形时我最关注三点起始条件是否正确地址字节后的ACK位是不是低电平数据字节位宽是否一致、有没有毛刺。如果地址有ACK但数据是乱的多半是上拉太弱导致上升沿太慢或者总线走线太长。如果一直没ACK优先检查地址算没算错别忘了I2C地址是7位发送时要左移一位拼上读写位。4.4 三个典型的翻车现场调试过程中我遇到过三个非常有代表性的问题写在这里供大家对照。第一个是总线扫描不到设备量SCL却只有1.2V。查下来是上拉电阻焊到了5V而ADS1110和MCU都是3.3V系统把引脚硬生生拉到了危险电平。改成上拉到3.3V后问题立刻消失。I2C上拉电平必须和所有设备的IO电平兼容。第二个是设备能找到但读数据偶尔跳变。逻辑分析仪看波形发现SDA上升沿像梯田一样慢原因是我在一条总线上挂了好几个设备总线电容变大还用10kΩ上拉。把上拉换成2.2kΩ后上升沿干净了读数也稳定了。这就是“上拉电阻小了不通信”的反问不是越小越好而是要和总线电容匹配。第三个是ADDR脚悬空导致的地址漂移。我最初为了省事让ADDR悬空扫描时发现0x48和0x49交替出现。这种玄学问题最浪费时间查到数据手册才明白ADDR不能悬空。老老实实把ADDR接地地址固定0x48之后再没犯过。5. 温度换算、标定和噪声抑制5.1 电阻转温度的计算ADS1110读出来的是电压电压要换算成PT1000的阻值。在分压电路里PT1000的阻值Rpt和分压电压Vpt的关系是Rpt RB * Vpt / (Vref - Vpt)其中RB是上桥臂精密电阻Vref是激励基准电压。得到阻值后再用IEC 60751标准公式把阻值换成温度。0℃以上可以只用二次多项式R(T) R0 * (1 AT BT²)其中R01000ΩA3.9083e-3B-5.775e-7。反过来求温度就是解一元二次方程代码实现如下double resistanceToTemp(double R) { const double R0 1000.0; const double A 3.9083e-3; const double B -5.775e-7; double q R0 * R0 * A * A - 4 * R0 * B * (R0 - R); if (q 0) q 0; double T (-R0 * A sqrt(q)) / (2 * R0 * B); return T; }这个公式在0℃到100℃范围内足够用实测误差远小于0.1℃。如果项目要测零下温度公式里还要加一个三次项建议直接用查表法或者官方标准算法别自己手推。5.2 标定方法标准电阻法和冰水法想要0.1℃级别的绝对温度标定是必须做的。我用的最简单可靠的方法是标准电阻比值法。具体流程是准备一颗1kΩ、0.01%的精密电阻断电后把PT1000拆下来用这颗标准电阻接到PT1000的位置上电读取ADC码记为Ncal再换回PT1000读取ADC码记为Nsen。如果标准电阻数值正好等于RB那么PT1000阻值可以按下式算Rpt RB * ρ / (2 - ρ)其中ρNsen/Ncal。这个比值法的好处是ADC参考电压误差、增益误差、基准电压初始偏差都会被约掉。基准漂移只要在测量过程中变化不大就不会影响结果。RB的温漂还在所以这颗电阻尽量选低温漂金属膜电阻。如果懒得拆传感器也可以用冰水混合物定0℃。把碎冰和冰水混合在一个保温杯里传感器插进去等十分钟左右读数稳定后作为0℃校准点。冰水法对绝对精度帮助有限胜在方便适合快速验证系统工作正常。想卡0.1℃还是标准电阻法更靠谱。5.3 软件滤波与过采样15SPS的原始数据直接显示跳动可能有1~2个LSB换算成温度就是0.03~0.05℃。想稳定到0.01℃最简单的办法是滑动平均。温度是慢变量我一般取16次平均值输出频率降到约每秒1次但噪声能压到很低的水平。如果现场有脉冲干扰先做中值滤波再去平均更稳。取5个原始值排序后丢掉最大最小再用中间三个求平均。这个组合对付电机启停、继电器吸合带来的毛刺很有效。注意采样和处理不要用阻塞式delay让I2C读取和滤波逻辑分离后面接显示屏或上位机时不至于卡顿。另外每次上电后前5~10个ADC样本建议直接丢弃。ADS1110刚上电时内部基准和PGA还没完全稳定读出来的数据会缓慢飘动等它自己稳下来再进入正常处理流程。5.4 实测数据和效果评估我用这套电路在实验室环境下做了简单对比。用精密电阻箱模拟PT1000阻值和理论温度对照得到下面这组参考数据设定温度理论阻值分压电压理论ADC码0.0℃1000.00Ω1.2500V2000025.0℃1097.35Ω1.3080V2092850.0℃1193.97Ω1.3605V21767100.0℃1385.06Ω1.4518V23229实际接上冰水混合物测试温度稳定在0.00℃到0.03℃之间用标准电阻替代传感器测试重复性在±0.02℃以内。这个水平说明“0.1℃精度”是搭得出来的前提是标定和滤波做到位。6. 常见问题速查表6.1 故障现象与排查把常见问题整理成速查表调试时候对着查能省不少时间。现象可能原因排查方法扫描不到任何I2C设备电源没通、上拉没接、SDA/SCL接反万用表量VDD、SCL/SDA静态电平扫描到设备但数据全0xFF总线数据线虚焊或地址看错逻辑分析仪抓波形看ACK读数跳动大上拉电阻不合适、走线太长、电源噪声换2.2kΩ上拉、加去耦电容、软件滤波温度整体偏高传感器自热、激励电流偏大降低激励电流、做良好热接触温度整体偏低基准接反、参考电压不对检查LM4040方向、量基准输出读回数据偶尔漂移ADDR悬空、总线电容过大ADDR接地缩短走线6.2 几个我踩过的大坑提醒最后把几个最容易忽略的细节单独拿出来说。LM4040的方向千万别接反有字那面是输出端接错后基准电压会变成二极管压降整个分压比例全错测出来温度整体偏低而且怎么标定都救不回来。ADDR脚一定不要悬空。ADS1110的地址是靠ADDR电位决定的悬空会让芯片内部读到一个不稳定电平地址在0x48和0x49之间跳程序里写死0x48就偶尔读不到。接一根线到GND就能彻底解决。上拉电阻不是越大越好。低速短距离10kΩ没问题但总线一长、设备一多10kΩ的上升沿会慢到让从机认不出数据。如果出现“上拉电阻小了不通信”这种反向问题多半是阻值太小导致低电平不达标先换回2.2kΩ或4.7kΩ再用逻辑分析仪看波形确认。我个人实际调下来的体会是I2C一旦不顺先量电平、抓波形再改代码。一次完整的I2C抓包也就十分钟比起反复烧固件猜问题这十分钟最值钱。这套ADS1110PT1000的测温模块我后来直接固定成了通用模板换传感器、改量程都很快希望这篇也能帮你少走几段弯路。