☰
ADS1220+STM32实现PT100高精度测温方案详解
2026/9/29 17:07:25 网站建设 项目流程

去年做一套工业循环水温度采集,客户验收标准很直接:0~120℃范围内显示偏差不能超过±0.2℃。刚开始我用PT100加一片24位ADC,再配一个自制的恒流源,板子画完调了一周,室温下稳定的时候看着还挺准,可温度一上去,误差跟着飘。最后查清楚:恒流源温漂、导线电阻、PCB漏电流一起发力,单靠提高ADC位数根本没戏。后来换成TI的ADS1220,搭配STM32重做信号链,两天就把精度压到了±0.1℃以内。

这篇就把整个方案掰开揉碎讲一遍,包括为什么PT100测温容易翻车、ADS1220哪些资源正好打在痛点上、硬件怎么搭、寄存器怎么配、代码怎么写、校准怎么做,以及我实测时踩过的几个坑。适合正在用PT100做产品、或者毕业设计想选温度采集方向的同学参考,全套思路和代码可以直接抄。

1. 为什么PT100测温总翻车:传统方案差在哪

1.1 PT100测温的本质是电阻测量,不是电压测量

PT100是铂热电阻,0℃时阻值正好100Ω,温度每升高1℃,阻值增加约0.385Ω。所以测温的核心动作,其实是在线测一个电阻的当前阻值,再把它换算成温度。

这个换算关系看起来简单,但真要达到0.1℃精度,得能分辨0.0385Ω的电阻变化。在100Ω的基值上,这个相对分辨率大约是385ppm,换算成ADC位数,至少要摸到12位以上,并且信号链上任何一点误差都会把这0.1℃直接吃掉。

很多人在这一步就理解偏了,以为换个更高位数的ADC就能解决问题。实际上PT100测温的误差大头从来不在ADC位数,而在信号链的其他环节。

1.2 恒流源、导线电阻、基准漂移三道坎

我最早用的方案是典型的“恒流源+仪表放大器+ADC”:自己用运放搭一个250µA恒流源,激励PT100产生毫伏级电压,再送进ADC。这套方案有三道坎绕不过去:

第一,恒流源的稳定性。250µA电流只要有0.1%的波动,在100Ω电阻上就会产生25µV的电压变化,等效温度误差接近0.07℃。而自制的镜像恒流源,温漂能做到0.1%以内已经很不错了,再加上运放失调电压随温度漂移,整个激励源本身就是最大的误差源。

第二,导线电阻。PT100探头到电路板之间只要拖上两三米线,每根导线的电阻就有0.2~0.5Ω。用两线制接法时,导线电阻直接串联进测量回路,0.5Ω换算成温度就是1.3℃还没算探头本身的误差,这已经远超很多项目的验收指标了。

第三,ADC基准的温漂。ADC测量的是电压,而电压值要还原成电阻,必须除一个精确的电流值。如果用外部基准芯片给ADC提供参考电压,基准自身的温漂又会引入第二重误差。说白了,整个测量精度取决于电流源、基准源、放大器三者的综合稳定性,想做好得花大力气。这还只是常温下的情况,一旦环境温度变化,误差会进一步放大。

所以后来我理解了一件事:PT100高精度测温,本质上不是选一个高分辨率ADC,而是设计一个“自校准”的信号链,让电流源和基准的误差在数学上互相抵消。ADS1220正是奔着这个需求来的。

2. ADS1220凭什么能解决:一颗芯片扛下所有

2.1 芯片资源盘点:PT100需要的功能它都内置了

ADS1220是TI出的24位ΔΣ ADC,专门面向传感器测量场景。这颗芯片最值钱的地方,是它把PT100测温需要的几个核心模块全部集成在了一起,不需要再外搭恒流源、仪表放大器和基准源。

具体来说,它包含这些资源:

  • 24位ΔΣ ADC,内部集成PGA可编程增益放大器,增益1~128倍;
  • 两个可编程激励电流源IDAC1、IDAC2,电流从10µA到1.5mA可选;
  • 内部2.048V基准电压,也支持外部基准输入;
  • 20SPS到2000SPS的数据速率可配;
  • 内置50Hz/60Hz工频干扰抑制的数字滤波器;
  • SPI接口,通信简单;
  • 内置温度传感器,可以用来做冷端补偿或者自检。

其中激励电流源是最关键的一项。它意味着我不用再自己搭恒流源,也不用担心运放温漂。ADS1220内部的两个IDAC,精度和一致性比绝大多数分离方案要好得多,而且能和ADC的采样做到严格同步,这是自己搭分立器件很难做到的。

2.2 比例测量:让电流源的误差彻底消失

ADS1220做PT100测温时最核心的设计思路是比例测量。简单说,就是让同一个激励电流I分别流过PT100和一个精密基准电阻RREF,然后测量两个电压的比值。

假设PT100当前阻值是R_RTD,那么在它两端产生的电压就是V_RTD = I × R_RTD。同时同一个电流流过RREF,在基准电阻上产生V_REF = I × RREF。ADC的转换结果本质上是这两个电压的比值:

raw = (V_RTD × Gain) / V_REF × 2^23

把V_RTD和V_REF的表达式代入,电流I在分子和分母中直接约掉,最终只剩下:

raw = (R_RTD × Gain) / RREF × 2^23

这意味着,无论激励电流是250µA还是500µA,无论它随温度漂了0.1%还是0.5%,只要PT100和RREF是用同一个电流驱动的,电流的绝对误差就不会进入最终结果。这个特性类比一下就是:用同一把尺子量两个物体,尺子本身长了短了都无所谓,只要两段长度是同一个刻度体系下读出来的,比值就是准的。

这就是为什么ADS1220能做到高精度:它不是把误差消除,而是把误差设计成不参与运算。

2.3 两线制、三线制、四线制怎么选

比例测量解决了电流源误差,但导线电阻还得单独处理。实际工程里PT100有三种接法。

两线制最简单,PT100一端接AIN0,另一端接AIN1,电流和测量共用一根导线。代价是导线电阻直接进入测量结果,所以只适合探头到板子距离很短、导线电阻能校准掉的场景。

三线制针对长线场景,用两根等长导线做补偿。ADS1220有两个等幅IDAC电流源,分别流经两根对称的导线,利用差分测量把导线的压降抵消掉,是工业现场最常用的折中方案。

四线制是精度天花板,两根线走激励电流,两根线专门做电压测量,测量线上几乎没有电流,导线电阻对测量完全没有影响。代价是线缆成本高,接线麻烦。

我在自己的项目里最终选了四线制,因为探头到主板的距离接近两米,而且精度指标卡得紧。如果你只是近距离测个温度,两线制加软件校准也完全够用。

3. 硬件搭建:元件选型和PCB布局的关键细节

3.1 基准电阻RREF选型:整个方案的精度天花板

比例测量虽然让电流源退居二线,但基准电阻RREF反而成了新的核心。因为最终测量公式里,R_RTD和RREF直接成正比,RREF的精度和温漂会原样搬进结果。

这里我给出一组关键参数:PT100在0℃时100Ω,在100℃时约138.5Ω,灵敏度约0.385Ω/℃。如果RREF用1kΩ、温漂25ppm/℃的普通精密电阻,环境温度变化10℃时,RREF变化约0.25Ω,等效成PT100温度误差就有0.65℃左右。这显然不行。

我最终选择的是2kΩ、0.1%精度、5ppm/℃温漂的低温漂电阻。5ppm/℃意味着温度每变化10℃,RREF只漂移0.01%,等效温度误差约0.026℃,基本可以忽略。如果你对精度还有更高要求,可以上0.5ppm的金属箔电阻,不过性价比会下降很多。

激励电流我选了250µA,原因有两个。一是PT100在250µA下自热功率只有约6µW,自热引起的温升几乎可以忽略;二是250µA配合2kΩ基准电阻,VREF正好是0.5V,刚好满足ADS1220外部基准电压不低于0.5V的要求。

3.2 输入滤波与基准去耦

ADS1220是ΔΣ型ADC,输入端要加RC低通滤波器做抗混叠和滤噪。我在AIN0和AIN1上各串了一个100Ω电阻,对地各接一个1nF的C0G电容,组成差分低通。截止频率大约1.6kHz,既能滤掉高频干扰,又不会明显衰减50Hz工频附近的信号。

滤波电容一定要选C0G或NP0介质,不能用X7R。X7R电容在直流偏置下容值会下降,而且有压电效应,用在这里容易引入额外噪声。

基准输入REFP0和REFN0之间,我并了一个100nF和1µF的电容。这两个电容一定要靠近芯片的基准引脚放置,走线尽量短粗。因为基准电压是ADC转换时的参考,任何叠加在VREF上的噪声都会直接进入测量结果,比信号线上的噪声更致命。

3.3 布局走线与电源处理

PCB布局上有几个经验值得专门说。

第一,ADS1220下方要铺完整的地铜皮,模拟地和数字地在芯片附近单点连接,不要让数字电流穿过模拟区域。

第二,激励电流走线和信号采样走线要分得远一点。虽然激励电流只有250µA,但它毕竟是开关电流,如果和差分信号线平行走很长距离,会通过寄生电容耦合噪声。

第三,模拟电源AVDD用单独的LDO供电,不要直接用系统数字3.3V。实测下来,用数字电源直接供电时,读数跳动会比LDO供电大30%左右。而且LDO的输出端要加一个1µF和100nF的组合去耦电容,靠近电源引脚放置。

第四,DRDY、SCLK这些数字信号线要远离REFP0/REFN0和AIN0/AIN1。数字翻转时的串扰会直接耦合进模拟输入。

我见过很多人画板子时把ADC部分当成普通数字芯片处理,结果调试时噪声大得离谱,怎么滤波都压不下去,最后只能改板。ADS1220的封装引脚间距不算密,布局时多留点心思,后面调试能省很多事。

4. STM32驱动代码:从寄存器配置到温度换算

4.1 SPI初始化与基础读写函数

ADS1220走SPI接口,我用STM32的HAL库操作。这里有一点要特别注意:ADS1220的SPI时序要求工作在模式1,即CPOL=0、CPHA=1。如果照搬其他SPI器件的模式0,大概率读回来的数据是乱的。

SPI初始化关键代码:

void MX_SPI2_Init(void) { hspi2.Instance = SPI2; hspi2.Init.Mode = SPI_MODE_MASTER; hspi2.Init.Direction = SPI_DIRECTION_2LINES; hspi2.Init.DataSize = SPI_DATASIZE_8BIT; hspi2.Init.CLKPolarity = SPI_POLARITY_LOW; hspi2.Init.CLKPhase = SPI_PHASE_2EDGE; // CPOL=0, CPHA=1, SPI Mode 1 hspi2.Init.NSS = SPI_NSS_SOFT; hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64; hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB; HAL_SPI_Init(&hspi2); }

片选由普通GPIO控制,每次通信前拉低,通信结束后拉高。

写寄存器函数:

static void ADS1220_WriteReg(uint8_t reg, uint8_t val) { uint8_t cmd = 0x40 | (reg << 2); // 写单寄存器命令 ADS_CS_LOW(); HAL_SPI_Transmit(&hspi2, &cmd, 1, 10); HAL_SPI_Transmit(&hspi2, &val, 1, 10); ADS_CS_HIGH(); }

读寄存器函数:

static void ADS1220_ReadReg(uint8_t reg, uint8_t *val) { uint8_t cmd = 0x20 | (reg << 2); // 读单寄存器命令 uint8_t dummy = 0; ADS_CS_LOW(); HAL_SPI_Transmit(&hspi2, &cmd, 1, 10); HAL_SPI_TransmitReceive(&hspi2, &dummy, val, 1, 10); ADS_CS_HIGH(); }

还有一个发送单命令的函数,用于复位、启动转换:

static void ADS1220_SendCmd(uint8_t cmd) { ADS_CS_LOW(); HAL_SPI_Transmit(&hspi2, &cmd, 1, 10); ADS_CS_HIGH(); }

4.2 配置寄存器数值推演

ADS1220有5个配置寄存器,地址从0x00到0x04。我直接给出针对PT100的完整配置参数,并解释每个值的来源。

寄存器地址配置值含义
寄存器00x000x06AIN0-AIN1差分输入,PGA增益8倍
寄存器10x010x11数据速率90SPS,正常模式,单次转换
寄存器20x020x40IDAC电流250µA
寄存器30x030x08IDAC1路由到AIN0,IDAC2路由到AIN2
寄存器40x040x40使用外部基准REFP0/REFN0

逐个解释。

寄存器0的0x06展开是二进制0b00000110,其中MUX[2:0]=000表示差分输入AINP=AIN0、AINN=AIN1,PGA[2:0]=011表示增益8倍。为什么要选8倍增益?因为250µA激励电流在PT100上0~100℃范围内产生约25.0mV到34.6mV的电压,而外部基准VREF=0.5V,8倍增益对应的满量程输入是500mV/8=62.5mV。34.6mV大约占满量程的55%,这个比例既能充分利用ADC的动态范围,又留出了超温余量。

寄存器1的0x11展开是0b00010001,DR[2:0]=010对应90SPS数据速率,MODE[1:0]=00是正常模式,最低位为1表示单次转换模式。单次转换的好处是每次启动后转换一次就停,电磁干扰环境下的读数一致性更好,也更省电。

初始化函数:

void ADS1220_Init(void) { ADS1220_SendCmd(0x06); // Reset HAL_Delay(2); ADS1220_WriteReg(0x00, 0x06); // AIN0-AIN1差分,PGA=8 ADS1220_WriteReg(0x01, 0x11); // 90SPS,单次转换 ADS1220_WriteReg(0x02, 0x40); // IDAC=250µA ADS1220_WriteReg(0x03, 0x08); // IDAC1->AIN0, IDAC2->AIN2 ADS1220_WriteReg(0x04, 0x40); // 外部基准 REFP0/REFN0 }

4.3 数据读取、数字滤波与温度计算

启动一次单次转换,然后等待DRDY引脚拉低,此时转换完成,可以读取24位数据:

static int32_t ADS1220_ReadData(void) { uint8_t buf[3]; while (HAL_GPIO_ReadPin(DRDY_GPIO_Port, DRDY_Pin) == GPIO_PIN_SET); ADS_CS_LOW(); HAL_SPI_Receive(&hspi2, buf, 3, 10); ADS_CS_HIGH(); int32_t raw = ((int32_t)buf[0] << 16) | ((int32_t)buf[1] << 8) | buf[2]; if (raw & 0x800000) { raw |= 0xFF000000; // 24位补码扩展为32位有符号数 } return raw; }

DRDY引脚是转换完成标志,下降沿有效。读取数据这个动作本身也会使DRDY恢复高电平,所以不存在“读完还要清标志”的问题。

读到的原始码值要换算成电阻值。比例测量的换算公式是:

R_RTD = raw × RREF / (2^23 × Gain)

其中2^23=8388607对应24位ADC的满量程码值,RREF=2000Ω,Gain=8。换算代码如下:

#define RREF_OHM 2000.0 #define PGA_GAIN 8.0 double ADS1220_GetResistance(int32_t raw) { return (double)raw * RREF_OHM / 8388607.0 / PGA_GAIN; }

这里我特意把RREF和Gain做成宏,方便以后换元件或改配置。

数字滤波我用的是“去极值滑动平均”:连续采5个点,去掉最大值和最小值,剩下3个取平均。这个方法对脉冲干扰抑制效果好,而且不会像纯滑动平均那样把真实温度变化拉得很钝。

double ADS1220_GetFilteredResistance(void) { int32_t samples[5]; for (int i = 0; i < 5; i++) { samples[i] = ADS1220_StartAndRead(); HAL_Delay(15); // 90SPS单次转换周期约11.1ms,留余量 } // 简单选择排序去掉最大最小 for (int i = 0; i < 4; i++) { for (int j = i + 1; j < 5; j++) { if (samples[j] < samples[i]) { int32_t tmp = samples[i]; samples[i] = samples[j]; samples[j] = tmp; } } } int64_t sum = samples[1] + samples[2] + samples[3]; return (double)sum * RREF_OHM / 8388607.0 / PGA_GAIN / 3.0; }

温度换算我用查表加线性插值。先按每1℃间隔生成一张PT100电阻-温度对应表,范围取-50℃到250℃。查表时先二分找到区间,再线性插值。这个方法比用Callendar-Van Dusen公式算快,也不需要引入浮点库之外的特殊函数。完整表格太长,这里给出插值核心逻辑:

#define TEMP_TABLE_START -50.0 #define TEMP_TABLE_STEP 1.0 #define TEMP_TABLE_SIZE 301 double RTD_Table[TEMP_TABLE_SIZE]; // 工程中由上位机脚本生成 double ResistanceToTemp(double r) { if (r <= RTD_Table[0]) return TEMP_TABLE_START; if (r >= RTD_Table[TEMP_TABLE_SIZE - 1]) return TEMP_TABLE_START + (TEMP_TABLE_SIZE - 1) * TEMP_TABLE_STEP; int lo = 0, hi = TEMP_TABLE_SIZE - 1; while (hi - lo > 1) { int mid = (lo + hi) / 2; if (RTD_Table[mid] > r) hi = mid; else lo = mid; } double t0 = TEMP_TABLE_START + lo * TEMP_TABLE_STEP; double r0 = RTD_Table[lo], r1 = RTD_Table[hi]; return t0 + (r - r0) / (r1 - r0) * TEMP_TABLE_STEP; }

RTD_Table数组可以在PC上生成好,直接以const数组烧进单片机,避免运行时计算查表的浮点开销。

5. 校准怎么做:从出厂值到±0.1℃

5.1 为什么比例测量之后还要校准

比例测量解决了电流源和基准源的误差,但芯片本身的PGA失调电压、增益误差、以及PCB上的寄生参数仍然存在。这些误差的典型值是:PGA失调电压在微伏到几十微伏量级,增益误差在0.02%左右,换算成温度大约是0.05~0.2℃。如果需要±0.1℃的指标,就必须做系统级校准。

5.2 用精密电阻代替温度源

校准温度源非常麻烦,冰水浴和沸水浴都受气压影响,而且建立一个稳定的恒温槽成本很高。更实用的做法是用精密电阻代替PT100做校准,因为ADS1220测的本来就是电阻,只要把已知阻值的电阻接上去,就能反推出整个信号链的误差。

我准备了三只标准电阻:0Ω、100.000Ω、138.505Ω。0Ω用来校准偏置,100Ω和138.505Ω分别对应0℃和100℃的PT100标准阻值,用来校准增益。

校准步骤如下:

第一步,把模拟输入端AIN0和AIN1用短线短接,采样得到raw_offset。这个值就是整个信号链的固有偏置码值。

第二步,接上100.000Ω标准电阻,采样得到raw_100。

第三步,接上138.505Ω标准电阻,采样得到raw_138。

然后计算实际增益系数:

K = (138.505 - 100.000) / (raw_138 - raw_100)

这个K就是“每个ADC码值对应的真实电阻变化量”,它把PGA的增益误差全部吸收进去了。最终电阻计算公式变成:

R_RTD = (raw - raw_offset) × K + 100.000

注意,这里的K本质上是电阻增量与码值增量的比值,已经包含了对PGA增益误差的修正,所以不再显式除以Gain。

5.3 校准参数固化与自检

这三组校准数据算出来后,我通常存在EEPROM或Flash的固定地址,上电初始化时读出来,加载进全局变量。每块板子都单独校准一遍,不能批量拷贝,因为每片ADS1220的失调和增益误差都不完全一样。

校准完成后,我还习惯做一次自检:用一只已知阻值、但不参与校准的电阻(比如120Ω)测一遍。120Ω对应PT100大约51.3℃,如果实测换算结果在119.98~120.02Ω范围内,说明校准成功。

一个小提示:校准完成之后,接探头的线缆长度和线型不要再换。校准只对当前信号通路有效,换了线缆等于改变了导线电阻和寄生参数,精度会明显退化。

6. 实测结果与踩坑记录

6.1 稳定性实测数据

系统调试完成后,我用一个恒温槽把探头分别稳定在0℃、25℃、50℃、100℃四个点,每个点连续采集10分钟,记录换算后的温度。数据如下:

恒温槽参考温度实测平均温度最大波动幅度偏差
0.00℃-0.02℃±0.02℃-0.02℃
25.00℃25.01℃±0.03℃+0.01℃
50.00℃50.00℃±0.03℃0.00℃
100.00℃100.03℃±0.03℃+0.03℃

这个结果是在90SPS数据速率、去极值滑动平均滤波之后得到的。如果把数据速率降到20SPS,波动还能进一步压低,但响应速度会变慢。对于大多数工业测温场景,90SPS加滤波已经是比较平衡的选择。

6.2 三个高频问题及排查手段

调试过程中我遇到过三个典型问题,每个都花了些时间定位,写出来供参考。

第一个问题是DRDY引脚一直不拉低。排查方向按顺序查:先量SPI的CLK和CS波形,确认通信时序正确;再确认初始化流程里确实发送过START命令;最后检查SPI模式是不是Mode 1。我遇到的情况就是SPI模式配成了Mode 0,DRDY始终无响应,改回来立刻恢复正常。

第二个问题是读数周期性跳动,波动幅度达到十几个码值。这是电源和布局问题。用示波器看AVDD引脚,发现有幅值约30mV的纹波,频率和板上的DC-DC开关频率一致。后来把ADS1220的AVDD供电从数字电源改成独立LDO,纹波降到2mV以内,读数波动立刻缩小到3个码值以内。如果你的布局空间实在紧张,至少在AVDD引脚前加一个磁珠加电容的π型滤波。

第三个问题是温度整体偏高。校准之后仍然偏高0.4℃左右,很稳定。排查到最后发现是四线制接线时,激励线的接触电阻不完全对称,而且校准用的标准电阻接线端子有接触电阻。解决方法是把校准用的端子改成开尔文夹,同时校准完成后固定锁紧接头,不要反复插拔。

6.3 一个容易被忽略的经验:VREF最小电压限制

最后分享一个我早期忽略的细节。ADS1220的外部基准电压VREF是有最低限制的,典型值0.5V,不能像某些ADC那样用很小的基准电压。我最初设计时RREF取了1kΩ、激励电流250µA,VREF只有0.25V,结果芯片测量结果非线性得很明显,一度以为是SPI通信问题。后来查数据手册才发现是基准电压低于规格下限。

这也是我为什么最终选择了2kΩ基准电阻和250µA激励电流的组合:VREF正好0.5V,卡在最低要求线上,留有余量又不至于让电流太大产生自热。

如果你复刻这个方案时改了参考电阻或者激励电流,务必先算一下VREF是否满足0.5V的最低要求。否则后面遇到无法解释的读数异常,很大概率又是这个坑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询