
做工业现场的测温板和做实验桌上的测温板完全不是一回事。实验板上元器件离得近电源干净信号线短随便一个ADC都能跑出不错的数据一旦进了空调机房或者工业机柜前面有变频器、接触器、通信电源测温线又要拉到十几米外全部问题都暴露出来。我上一套方案用的是SPI接口的高精度ADC当时觉得SPI很成熟结果加了隔离后布线麻烦、调试也不痛快换成UART接口的ADS122U04IPWR以后才体会到有时候接口选择比ADC精度本身更影响项目进度。配合PIC32MX795F512L这颗单片机这套组合在我的HVAC温度采集板和工业RTD采集模块上稳定跑了很久今天把完整的选型思路、硬件设计、驱动配置和换算算法一次说清楚。1. 为什么测温要24位ADC又为什么选了这颗UART型号1.1 温度传感器信号实在太弱常温下PT100的阻值是100Ω温度每升高1°C阻值只增加约0.385ΩK型热电偶在常温段每摄氏度只有约40µV输出到几百摄氏度时才到几毫伏到几十毫伏。这种信号直接用12位或者16位ADC去量化即使参考电压只有2.048V测热电偶也必须先放大几十倍而放大器本身的失调、温漂和噪声都会成为新的误差源。24位ADC解决的不只是分辨率问题更关键的是把可编程增益放大器PGA和高精度量化器做在同一个芯片里信号从传感器出来之后经过最短的信号链路完成放大和量化中间不经过分离元件误差来源大幅减少。实际使用中我们当然拿不到完整的24位有效分辨率但通过内部数字滤波在低数据速率下拿到18到20位的有效分辨率是完全可以实现的这正好是这类Δ-Σ ADC的拿手活。1.2 UART接口在工业现场的优势很多人选ADC只看位数和采样率忽略接口但接口在工业场景里真的很关键。SPI接口需要四根线每一根都要同步如果前端需要隔离每一根信号线就要一个隔离通道四个通道的成本、面积和故障率都上来了。UART接口是异步的ADC和MCU之间只需要TX和RX两根线隔离只用双通道数字隔离器就能搞定对PCB布局和装配都友好得多。ADS122U04IPWR把UART、24位精度、PGA、内部参考、双电流源全部集成起来正适合“要精度还要抗干扰”的场合。这颗料的封装是TSSOP-28型号里的IPWR后缀代表了工业和卷带封装。实际焊接调试时注意引脚间距较小手工焊接建议用拖焊配合助焊剂否则容易连锡。1.3 PIC32MX795F512L在这套系统里做什么做HVAC或工业节点时单片机一般还要承担Modbus、RS485、协议转换、状态灯、按键等功能。PIC32MX795F512L是100引脚封装的MIPS32 M4K内核单片机80MHz主频512KB Flash、128KB RAM外设非常丰富6路UART、4路SPI、5路I2C、CAN、USB、以太网MAC都有。这套方案里我用一路UART接ADS122U04另一路接RS485转Modbus RTU还留了一路给调试串口完全不冲突。选它还有一个很实际的原因Microchip的MPLAB X和PICKIT调试器普及度极高硬件工程师上手快固件调试时能省不少时间。相比其他品牌同等资源量级的单片机这颗料在温度采集这种中等性能需求场景下性价比和工具链成熟度都很有优势。2. RTD前端、热电偶输入与隔离布局的硬件细节2.1 RTD的4线和3线接法怎么选4线接法是在RTD两端各引出两根线两根作为激励电流通路两根作为电压检测通路。电压检测端接入ADC的差分输入ADC输入阻抗极高检测线上几乎没有电流所以检测线的导线电阻上不产生压降测到的就是RTD两端真实的电压。这种接法在激励线很长、线径又细的工业场合下精度是最高的。3线接法更经济现场的三线制传感器也最普及。利用ADS122U04的两个匹配IDAC一路电流源驱动RTD的一个引脚另一路电流源驱动另一条线路做补偿。理想情况下两根导线电阻一致差分输入上一条线的压降和另一条线的压降相互抵消只剩下RTD本身电压。当然这种补偿依赖IDAC的匹配度和导线一致性所以3线的精度天花板不如4线。以PT100、IDAC1mA、PGA16、内部参考2.048V为例算一笔账0°C时PT100上的电压100Ω × 1mA 100mVPGA16的满量程差分输入2.048V / 16 128mV0°C时的码值0x7FFFFF × 100 / 128 ≈ 13,107,200温度每变化1°C信号变化约0.385mV对应码值约50,400个在噪声理想情况下单个码位对应的温度小到可以忽略即便有效分辨率被噪声拉到18位依然能分辨0.001°C量级的温度变化。但要注意激励电流的选择1mA在100Ω上功耗只有0.1mW自热影响很小如果换PT10001mA就是1mW可能引入约0.1°C的自热误差所以PT1000建议用250µA激励。工业上常用范围就是250µA到1mA要在克服导线噪声和自热之间取平衡。2.2 热电偶输入与冷端补偿热电偶输出为差分电压且信号非常小需要比较高的PGA增益。K型热电偶全量程0到1250°C对应约0到50.6mVPGA32时满量程64mV能覆盖全范围如果只测0到350°C用PGA128也可以。我实际选了PGA32留够量程降低放大器饱和风险。冷端补偿CJC是热电偶测温绕不开的问题。热电偶输出的是热端和冷端的温差电势必须知道冷端温度才能得到绝对温度。ADS122U04内部有温度传感器可以读芯片温度作为冷端参考但芯片温度不等于接线端子温度除非PCB设计和探头端子离得非常近且做好热耦合。我后来在端子附近加了一个PT1000占用ADC一个输入通道把端子温度作为冷端温度参考。虽然多占一个通道但精度明显好于直接用芯片内部温度。热电偶通道的RC低通滤波也很有必要。热电偶内阻不大但引线长容易把现场的工频干扰和变频器谐波捡进来。我用的是100Ω串联电阻加1µF电容截止频率约1.6kHz如果信号变化更慢把截止频率放到几十赫兹数据会更干净。2.3 UART隔离、供电和PCB布局隔离必须在物理上做彻底。ADS122U04和传感器一起放在远端MCU在近端中间用双通道数字隔离器比如TI的ISO7721速率要能覆盖115200传播延迟尽量小。隔离两端要用两个独立的隔离电源否则隔离器两端的地还是通的隔离形同虚设。供电方面ADC的AVDD我用了5VDVDD用3.3VMCU侧也是3.3V电平直接匹配。模拟电源单独从LDO出后面串一个磁珠再并10µF和0.1µF电容。参考电压的去耦电容要尽可能贴近芯片引脚引线越短越好。PCB布局有几个实实在在的教训模拟输入线尽量短且等长底下铺完整地平面AGND和DGND在ADC下方单点连接不要做成大面积共地网络。第一次打板时我把数字UART走线从模拟输入下方穿过结果串扰很明显读数在小数点后第二位跳后来改走顶层另一侧才解决。提示热电偶的屏蔽层只能单端接地传感器端或控制端选一头接地千万不要两端都接大地否则地环路会把噪声加倍引进来。3. UART通信协议与配置代码3.1 UART协议要点ADS122U04的通信本质是UART上的寄存器读写。主机发写寄存器命令把配置块下发发读寄存器命令ADC回传当前寄存器值。启动转换后可以通过DRDY引脚或者查询方式得知数据就绪再发读取命令取24位转换结果。因为收发共用两条线要注意帧间隔和返回数据的时序不要读到上一帧的残留字节。我建议把DRDY引脚接到PIC32的外部中断引脚用下降沿触发中断读取。数据速率不高20SPS时中断负担很小但比轮询省心很多也不用担心读数据时正好碰上ADC正在更新。3.2 初始化流程与配置代码ADC上电之后不要急着配置先等内部参考和振荡器稳定。我的初始化逻辑是复位引脚拉低10ms再拉高等待50ms然后写配置寄存器组写完之后回读校验确保通信没问题。/* ADS122U04 UART 驱动骨架PIC32MX795F512L * 平台: MPLAB X XC32寄存器操作方式 * 实际寄存器字段请对照你所持手册的CNFGx位定义填写 */ void ADS_Init(void) { /* 1. 初始化MCU侧UART: 波特率115200, 8N1 */ U4BRG (GetPeripheralClock() / 2) / 115200 - 1; U4MODE 0x8000; /* ON1, PDSEL8N1, STSEL1bit */ U4STA 0x0400; /* UTXEN1, URXEN1 */ /* 2. 复位ADC并等待上电稳定 */ ADS_Pin_Reset_Low(); delay_ms(10); ADS_Pin_Reset_High(); delay_ms(50); /* 3. 写入配置寄存器组 */ static const uint8_t cfg[] { 0x00, /* 输入MUX、IDAC使能等 */ 0x00, /* PGA、数据速率 */ 0x00, /* 参考源、基准电压 */ 0x00, /* IDAC电流值、路由 */ 0x00, /* 温度/传感器/滤波 */ 0x00 /* 转换模式/其他 */ }; ADS_Write_Regs(0, cfg, sizeof(cfg)); /* 4. 回读校验不一致就报错 */ uint8_t rd[6]; ADS_Read_Regs(0, rd, sizeof(rd)); if (memcmp(cfg, rd, sizeof(cfg)) ! 0) { /* 通信异常处理 */ } } void ADS_Write_Regs(uint8_t addr, const uint8_t *buf, uint8_t len) { uint8_t cmd; cmd 0x40 | (addr 1); /* 写寄存器命令字细节见手册 */ Uart_Send(cmd, 1); Uart_Send(buf, len); } void ADS_Read_Regs(uint8_t addr, uint8_t *buf, uint8_t len) { uint8_t cmd[2]; cmd[0] 0x20 | (addr 1); /* 读寄存器命令字细节见手册 */ cmd[1] len - 1; Uart_Send(cmd, sizeof(cmd)); delay_us(50); Uart_Receive(buf, len); }这段代码里的命令字写法是示意不同版本的器件可能有差异但流程骨架可以复用。关键是配置完成后必须回读校验这一步能提前暴露接线错误和波特率不匹配的问题。3.3 启动转换和读取结果读取转换结果的核心是等待数据就绪。我用DRDY中断中断里发读取指令然后把返回的3个字节拼接成24位有符号数。volatile int32_t raw_result 0; void __attribute__((interrupt, no_auto_psv)) _EXTERNAL_3_ISR(void) { uint8_t rx[4]; uint8_t cmd READ_DATA_CMD; /* 读取转换结果命令字 */ Uart_Send(cmd, 1); Uart_Receive(rx, 4); /* 用rx[0]状态字节判断数据有效 */ if (rx[0] DATA_VALID_MASK) { raw_result (rx[1] 16) | (rx[2] 8) | rx[3]; if (raw_result 0x800000) { raw_result | 0xFF000000; /* 24位有符号扩展 */ } } ADS_DRDY_Clear(); }单次转换模式适合多通道轮询每切换一个通道就启动一次等DRDY后读数连续转换模式适合单通道高速采集但要注意读取时序防止读到正在更新的数据。测温是缓变信号我实际用20SPS内部数字滤波效果好数据量也小。100SPS甚至更高不是不能用只是噪声会明显变大除非信号本身响应快否则没必要。4. 从码值到摄氏度的换算算法4.1 RTD电阻与温度换算RTD通道的换算分两步先把码值还原成电阻再用电阻算温度。电阻公式如下R raw × VREF / (PGA × IIDAC × 0x7FFFFF)其中raw是24位有符号码值的整数部分VREF是实际参考电压IIDAC是实际激励电流。温度换算用Callendar-Van Dusen方程。0到850°C范围用二次式R(t) R0 × (1 A×t B×t²)A 3.9083e-3B -5.775e-7R0是0°C标称电阻。反解温度时用一元二次求根t (-A sqrt(A² - 4×B×(1 - R/R0))) / (2×B)负温度范围加入C项C -4.183e-12此时方程变高次用迭代法或者分段查表更实际。PIC32的数学库里有sqrt80MHz下调用一次很快每50ms算一次完全没有压力。4.2 热电偶查表与线性插值NIST的ITS-90热电偶多项式系数太多在MIPS M4K这种不带硬件浮点单元的单片机上每个样本硬算一遍不划算。我做了以5°C为步长的K型热电偶电压到温度查找表约250个点二分查找后线性插值。实测插值精度在0.1°C以内而5°C步长表只占不到2KB Flash非常适合单片机。冷端补偿的做法是先读冷端PT1000得到冷端温度T_cold用查找表把T_cold换算成对应热电势E_cold然后把ADC测到的热端电压加上E_cold最后用这个总电势去查表得到真实热端温度。注意极性方向和热电偶类型要匹配K型热电偶在正极接法下电压为正接反了补偿会反向叠加。4.3 滤波与性能平衡我的采集循环里加了两个滤波器一个是窗口长度8的滑动平均用于把ADC本身的噪声压下去一个是3点中值滤波专门对付接触器吸合时产生的尖峰干扰。中值滤波的代价是边缘会延迟一个样本对20SPS温度采集来说完全无感。PIC32MX795F512L没有硬件FPUfloat运算靠软件库但测试下来完成一套“电阻换算温度求根滤波”大概只用几百微秒50ms的采样周期里CPU占用非常低。如果以后要做到每通道100SPS以上、同时处理几十个通道可以把多项式换算改成定点查表但当前场景完全不需要。5. 校准、实测噪声和踩坑记录5.1 校准流程第一次上板后的校准步骤我固定成这样校零把ADC差分输入短接连续采集100个样本平均得到零点偏差码值。校增益用0.01%精度的标准电阻比如100Ω或1000Ω替换RTD同样平均得到实际增益系数。计算并保存R_corrected (R_measured - offset) × gain系数写入Flash末尾。热电偶通道用标准毫伏源灌入已知电压验证查表路径没问题。校准值写入后启动时读出来并做CRC校验。维护团队现场换探头后运行参数可以重新校准并覆盖存储不会出现换板丢数据的尴尬。5.2 实测噪声表现下面是我在一版布局比较规范的板卡上的实测数据参考条件是内置参考、模拟电源干净、输入短接或接标准电阻配置数据速率温度波动峰峰值评价PT100, PGA16, 250µA5 SPS小于0.005°C适合高精度校准PT100, PGA16, 250µA20 SPS约0.005°CHVAC默认档PT100, PGA16, 250µA100 SPS约0.015°C响应快噪声偏大K型热电偶, PGA3220 SPS约0.05°C受CJC和现场噪声影响这些数据跟PCB布局、电源质量关系很大自己打板时如果差个两三倍都很正常但趋势是一致的数据速率越低越干净PGA越高对噪声越敏感。5.3 踩过的几个坑第一个坑是参考电压去耦不良。现象是读数在19.0°C和19.3°C之间周期性抖动仔细排查发现和IDAC的开关同步——激励电流每次开启内部参考电压都会被拉低一下。原因是去耦电容离引脚太远地线回路太长。把1µF的C0G电容贴到基准引脚旁边模拟地和信号地分开走线抖动就消失了。第二个坑是看门狗复位后ADC寄存器失效。PIC32看门狗复位后MCU重新执行初始化但ADS122U04没有复位如果初始化代码里写了“配置过就跳过”ADC就留在错误状态。强制逻辑改成每次启动都无条件重新写一遍配置不管之前是不是配过这个问题从此没有再犯。第三个坑是UART波特率误差。早期用PIC32内部FRC时钟标称8MHz实际误差不小115200波特率下偶尔乱码表现为偶发的FFFF或者CRC错。换外部晶振后明显改善数字隔离器的传播延迟在高波特率下也会影响时序为了稳我最终把通信速率降到38400测温场景完全够用。第四个坑就是热电偶屏蔽层两端接地。屏蔽层在传感器端和控制端都接了大地结果地环路产生的噪声比不接屏蔽还大。改成传感器端单点接地后工频干扰立刻降了一个量级。这套方案稳定跑了大半年回头看的体会是测温产品做得好不好硬件基础和驱动配置各占一半24位ADC不是买回来就自动精确的供电、布局、校准任何一个环节偷懒误差都会回到你脸上。ADS122U04IPWR和PIC32MX795F512L的组合好处是思路清晰模拟前端芯片化和UART隔离把系统复杂度降下来剩下的精力可以集中在算法和通讯上。最后补一个小技巧批量校准时把每个通道的零点、增益和探头类型写在一个结构体里存到Flash尾部附带CRC16上电自检时如果校验不过就说明板卡被换过探头或者Flash有异常维护人员一眼就能定位问题。如果你也准备做类似的温度采集系统希望这些内容能帮你少走几趟弯路。