半年前接手的那个冷站群控改造项目,让我对HVAC温度测量彻底改观了。现场要测冷冻水进出水温度、冷却水温度、风管露点温度,还要兼顾压缩机壳温和电机轴承温度,传感器分散在四层楼,原厂用的是PT100加模拟变送器,4-20mA拉回PLC。结果是线缆一长,变频器一开,温度在控制面板上跳舞,运维被折腾得够呛。那之后我重新搭了一套方案,核心器件就是标题里这两个:ADS122U04IPWR(TI的24位UART接口ADC)和STM32F413RH(ST的Cortex-M4F单片机),专攻工业和HVAC应用中的温度测量。
这篇文章不是芯片手册的复读,而是我把这个项目从选型、硬件设计、串口驱动到温度换算、现场调试,整个流程里值得抄作业的部分整理出来。适合正在做温度采集节点、楼宇自控、冷链监测、工业设备状态监控的人看,如果你只想快速知道“PT100接到哪儿、代码怎么写”,后两节可以直接拿去用。
1. 为什么这套方案先打动我的不是精度,而是串口
1.1 楼宇空调温度采集的现场困境
HVAC系统里,温度传感器和控制器之间动不动就隔着十几米甚至几十米线。传统做法是PT100变送器转换成4-20mA,这信号是模拟的,一路上要经过穿线管、桥架、变频器电缆沟,干扰全被捡回来了。更麻烦的是,一台冷水机组要测的点位动辄十几个,每个点位拉一根模拟线,施工成本和故障点都翻倍。
我之前还试过用SPI接口的ADC,比如ADS1256搭配F103。SPI在板内通信没问题,但一旦传感器线稍微长一点,时钟信号和片选信号的时序就很容易被干扰,飞线调试时特别痛苦。后来看到ADS122U04IPWR这个型号,第一反应是“ADC还带UART?”再一看手册,四通道、24位、内置PGA、内置精密基准、还带两个可编程恒流源IDAC,这基本就是为温度测量量身定做的。
1.2 24位、四通道、自带恒流源和基准的UART ADC
ADS122U04IPWR里后缀的“IPWR”,其实是封装和温度等级信息:I表示工业温度范围,PWR表示TSSOP-16封装、卷带包装。采购的时候如果只写ADS122U04,供应商可能给你工业级也可能给你商业级,别在这上面省事。
这个芯片最特别的地方,是把ADC和串口放在了一起。MCU只需要两根线(TX、RX)就能和它通信,不需要像SPI那样还得管时钟线和片选线。对于温度采集这种“传感器可能放到设备旁边、主控放在控制柜里”的场景,UART天生就比SPI适合。再往后如果你想把它变成RS-485总线,随便一级转换芯片就能搞定,线长能拉到几百米。
芯片内部集成了四通道输入多路复用器、增益1到128的可编程放大器、2.048V内部基准源、两个IDAC电流源,还有一个用于冷端补偿的内部温度传感器。换句话说,做PT100、PT1000、热电偶、NTC这几种最常见的温度传感器,外围基本不需要运放和基准芯片,一个ADC全包了。
1.3 谁适合抄这套方案?和常用替代方案的账本对比
先看一个替代方案对比,方便你判断自己是不是属于这套方案的受众:
| 方案 | 通道数 | 接口 | 外围复杂度 | 适合场景 |
|---|---|---|---|---|
| ADS122U04 + STM32F413 | 4入/片 | UART | 低,无需基准IC | 多点温度、分布式采集节点 |
| MAX31865 | 1路RTD | SPI | 很低 | 单点PT100/PT1000,PCB空间极小 |
| ADS1256 + 外部运放 | 8入 | SPI | 高,需自己搭恒流源 | 多通道通用数据采集板 |
| 4-20mA变送器 + PLC | 1路/变送器 | 模拟 | 较高,需屏蔽电缆 | 老系统改造,接口固定 |
如果你只是在PCB上测一路PT100,那MAX31865确实更省事。但一旦涉及多点、多类型传感器、需要把温度数据就地数字化再回传,ADS122U04这种UART接口的片子在工程上省下的时间,远比你多写几行代码的时间值钱。
STM32F413RH这边,核心是Cortex-M4F,带浮点运算和DSP指令,64引脚封装,多路串口带FIFO。有人会觉得测温度用8位单片机就够了,但后面我要在上面做多通道滤波、查表插值、PID控制,甚至顺带算个能效COP的时候,F413的浮点能力就体现出价值了。而且它的USART数量够多,我一个主控接了好几片ADS122U04,没有压力。
2. 从探头到ADC引脚的硬件设计,把噪声挡在进芯片之前
2.1 比例测量的核心原理:用一个公式吃掉恒流源温漂
温度测量最容易踩的坑,是直接用IDAC电流激励RTD,然后把电压送进ADC,再用代码里的“V=I×R”算电阻。问题在于,IDAC电流本身会随温度漂移,哪怕漂移0.1%,PT100在100℃时也能产生接近0.1℃的误差。
正确做法是比例测量。核心思想:让同一个电流源,既流过被测RTD,又流过一颗精密基准电阻RREF。然后把RREF两端电压当作ADC的参考电压,把RTD两端电压当作输入信号。这样ADC输出码值近似等于:
RTD阻值 ≈ RREF × (码值 / 2^23)
这个公式里根本没有电流I,也就是说,电流源漂移被彻底抵消了。这是整套方案最核心的一步,如果硬件上没按这个思路搭,后面软件再怎么写都白搭。
实际接线时,我把IDAC1输出先接到RREF,再从RREF串联到RTD,最后回到地。REFP和REFN引脚跨接在RREF上,AINP和AINN引脚跨接在RTD两端。RREF选精密薄膜电阻,温漂系数5ppm/℃起步,精度0.1%以上。
2.2 RTD的两种接法:四线做基准,三线干现场
RTD接法分为两线、三线和四线。两线在这里就不多说了,除非你的引线只有几厘米。工业HVAC现场,我推荐三线或四线。
四线是首选基准方案:一对引线走IDAC激励电流,另一对引线走电压检测,测量回路几乎没有电流流过,线阻的影响可以忽略。我在冷站主机上用的就是四线PT100,稳定性和精度都很满意。
三线是HVAC现场最常用的折中方案。三根线分别接在RTD两端和补偿端,利用差分输入扣除一副引线的电压降。它的前提是两根线阻尽量相等,所以现场布线时要求同一根电缆里的线径、长度一致。实测下来,三线接法配合比例测量,在50米电缆内把误差控制在0.1℃以内没有太大难度。
激励电流的选择也要讲究。PT100我用1mA,功耗约0.1mW,基本不产生自热误差。PT1000我会降到250µA或500µA,因为PT1000在几百欧到几千欧之间,同样电流下发热更明显,1mA能让它自热出0.1℃以上的偏差,这是很多初做温度采集的人最容易忽略的细节。
2.3 热电偶和NTC的处理:冷端补偿与高增益通道
如果只测RTD,这套方案其实只用了一半功力。ADS122U04的PGA最大增益128,就是给热电偶准备的。K型热电偶信号每摄氏度只有大约41µV,100℃温差不过是4mV量级,不开高增益直接没法用。
我的配置是:热电偶通道PGA设为128,参考源用内部2.048V基准,开启双极性测量。冷端补偿用ADC内部温度传感器,或者更稳妥的办法是在冷端附近贴一颗外部PT1000,两颗传感器读数做平均,可以减少冷端温度梯度造成的误差。内部温度传感器精度大约在±0.5℃,对大多数HVAC应用够用,但如果你追求整机误差小于±0.3℃,建议用外部PT1000做冷端参考。
NTC热敏电阻接入就更简单了。NTC在25℃时通常是10kΩ,阻值变化范围很大,用IDAC 250µA激励,配一个合适的分压网络,直接进ADC。线性化靠软件查表,硬件上不需要额外处理。
2.4 电源、保护与PCB布局的细节
这块我踩过不少坑,直接说结论。
第一,模拟电源和数字电源分开。ADS122U04的AVDD和DVDD我分别用两颗LDO供电,中间用磁珠隔离。如果板上空间紧张,至少也要让AVDD经过RC滤波,电容加大到10µF钽电容并100nF陶瓷电容。
第二,参考电压引脚必须加高质量旁路电容。REFP和REFN之间我放了C0G材质的100nF电容,另外加了一颗1µF电容。C0G的温漂比X7R小,参考电压的稳定性直接决定整机精度,这钱不能省。
第三,模拟输入加RC滤波。每个AIN引脚串一个1kΩ电阻,对地并联100nF电容,做成低通滤波器。这样能挡住从传感器线缆上进来的高频干扰,让Δ-Σ调制器工作在干净的信号上。RC截止频率大概1.6kHz,对温度信号来说绰绰有余。
第四,RTD引线从设备出来就是一根长天线,雷击感应和静电都可能从这根线进来。我在端子上加了双向TVS管,入门后先过TVS再过共模电感,最后才进RC滤波。别嫌冗余,现场一年里总有一两次感应雷让你明白这几十毫钱的价值。
第五,PCB布局时ADC尽量靠近端子,所有模拟走线都别跨过数字信号。串口TX、RX线在离开MCU后,我会各串一个22Ω电阻再走,这样既限制边沿速率,也能减小振铃对ADC的干扰。模拟地单点汇接到电源地,不要在ADC下方开数字地缝隙。
3. STM32F413与ADS122U04的串口握手,最容易栽在初始化顺序
3.1 先搞清楚ADS122U04的UART帧格式
ADS122U04的UART协议没有时钟线,靠起始位、数据位和停止位保证同步。波特率不是软件任意配的,芯片有专门的配置引脚,根据M0/M1的电平组合选择固定波特率,我板上用的是115200,8N1。
通信帧结构一般由起始字节、命令字段、寄存器地址、数据字段和可选CRC组成。写寄存器用WREG命令,读寄存器用RREG命令,读转换结果用RDATA命令。这里我不写具体十六进制码,因为不同批次和手册版本的命令表最好以你手里那本为准。我的习惯是封装成两个驱动函数:写寄存器和读寄存器,函数内部按手册帧格式拼字节,之后所有业务逻辑都建立在它们上面。
我建议你把CRC选项打开。HVAC现场有变频器,UART线上偶发一个错字节是常态,如果没有CRC,错字节会被当成合法命令执行,后果是ADC配置被改乱,温度读数直接跳飞。有CRC之后,错误帧会被丢弃,配合超时重发,系统稳定很多。
3.2 初始化顺序比想象中敏感
ADS122U04上电之后,不能立刻急着发配置命令。我遇到过一次:程序复位后马上写寄存器,结果寄存器根本没写进去,读回来的全是默认值,但单步调试的时候一切正常。后来用逻辑分析仪对比,发现是芯片内部振荡器还没稳定,UART模块没有进入就绪状态。
正确的初始化顺序应该是:
- RESET引脚拉低再拉高,给芯片一个明确复位;
- 等待至少10ms,让内部振荡器和参考源稳定;
- 如果芯片有唤醒/同步序列,先按手册发送同步字节,直到收到响应;
- 用WREG命令写入全部配置寄存器;
- 用RREG命令回读,逐字节比对,确认配置成功;
- 启动连续转换模式,等待DRDY信号或读取超时。
STM32侧的串口初始化和普通USART没有区别,用CubeMX生成就行。我贴一段初始化参考:
void MX_USART6_UART_Init(void) { huart6.Instance = USART6; huart6.Init.BaudRate = 115200; huart6.Init.WordLength = UART_WORDLENGTH_8B; huart6.Init.StopBits = UART_STOPBITS_1; huart6.Init.Parity = UART_PARITY_NONE; huart6.Init.Mode = UART_MODE_TX_RX; huart6.Init.HwFlowCtl = UART_HWCONTROL_NONE; if (HAL_UART_Init(&huart6) != HAL_OK) { Error_Handler(); } }初始化ADC的代码框架大概是这个样子,具体命令码务必对照手册:
void ads122u_init(void) { /* 1. 复位引脚 */ HAL_GPIO_WritePin(RESET_GPIO_Port, RESET_Pin, GPIO_PIN_RESET); HAL_Delay(1); HAL_GPIO_WritePin(RESET_GPIO_Port, RESET_Pin, GPIO_PIN_SET); HAL_Delay(10); /* 2. 发送同步/唤醒序列,直到收到响应 */ ads122u_sync(); /* 3. 写配置寄存器,具体寄存器数与手册一致 */ ads122u_write_reg(REG_CONFIG0, CONFIG0_VALUE); ads122u_write_reg(REG_CONFIG1, CONFIG1_VALUE); ads122u_write_reg(REG_CONFIG2, CONFIG2_VALUE); ads122u_write_reg(REG_CONFIG3, CONFIG3_VALUE); /* 4. 回读校验 */ if (ads122u_read_reg(REG_CONFIG0) != CONFIG0_VALUE) { /* 重新初始化或报警 */ } }这里有个小技巧:配置写完之后,把所有寄存器再读一遍比对,不要省。现场偶发干扰会破坏UART帧,如果没校验,你调试一整天都找不到温度漂移的原因。
3.3 读数、超时与异常重连
ADS122U04在连续转换模式下,每隔一个转换周期产生一个新数据。读取流程是MCU发RDATA命令,然后从串口收3个字节,拼成一个24位码值。注意两次读数之间要有间隔,别一口气狂发命令,否则读到的是同一个老数据,会误以为ADC没工作。
读取函数的参考写法:
uint32_t ads122u_read_adc(void) { uint8_t cmd = ADS122U_CMD_RDATA; // 以手册命令码为准 uint8_t buf[3] = {0}; uint32_t code = 0; HAL_UART_Transmit(&huart6, &cmd, 1, 10); HAL_UART_Receive(&huart6, buf, 3, 50); code = ((uint32_t)buf[0] << 16) | ((uint32_t)buf[1] << 8) | ((uint32_t)buf[2]); return code; }超时处理也重要。我用HAL_UART_Receive的最后一个参数设了50ms超时,如果读不到3个字节,说明芯片可能进入了错误状态。遇到这种情况,我的策略是连续错3次就重新走一遍完整初始化流程,并发出错误告警。实测下来,这个机制能让系统在无人干预的情况下自动恢复,HVAC项目尤其需要这种自愈能力。
4. 温度换算是精细活:RTD查表、热电偶冷端补偿与三点校准
4.1 RTD线性化:查表插值比纯公式更适合工程
从码值得到电阻之后,下一个关键步骤是电阻到温度的换算。PT100和PT1000的电阻-温度特性不是纯粹线性,工业上常用的数学模型是Callendar-Van Dusen方程,但直接解这个方程非常麻烦。
工程上最简单的做法是查表加线性插值。把EN 60751标准表按1℃步进存成数组,温度分辨率靠插值补出来。1℃步长的表足够让插值误差控制在0.01℃以内,完全满足HVAC需求。查表代码量小、执行快,关键是调试时能直观看出数据落在哪个区间,比玄学公式好排查得多。
如果你想用公式,也可以参考PT100的近似计算:
float pt100_res_to_temp(float R) { float t = (R / 100.0f - 1.0f) / 0.00385055f; for (int i = 0; i < 3; i++) { float err = 100.0f * (1.0f + 3.9083e-3f*t - 5.775e-7f*t*t) - R; float der = 100.0f * (3.9083e-3f - 2.0f * 5.775e-7f * t); t -= err / der; } return t; }这是我常用的牛顿迭代版,三次迭代就能收敛。注意这个公式只在0℃以上精度比较好,0℃以下要加上四次项,我的经验是直接用分段查表更省心。
4.2 热电偶冷端补偿的正确打开方式
热电偶测的是热端和冷端的温差电动势,所以冷端温度必须补偿,否则读出来的温度全是错的。具体流程三步走:
- 读冷端温度T_cold。我这里是ADS122U04内部温度传感器,读出来是摄氏温度;
- 根据热电偶分度表,查出T_cold对应的热电动势E_cold;
- 把ADC读到的热电偶电压V_therm加上E_cold,得到总电动势E_total;用E_total反查分度表,得到热端真实温度T_hot。
举个例子,K型热电偶冷端25℃,此时测得热端输出3.075mV。如果直接按3.075mV反查表,会得到大约75℃,而实际热端是100℃。正确做法是查表得到25℃对应电动势约1.000mV,加到3.075mV上得到4.075mV左右,再反查表,就能得到接近100℃的结果。这个加电动势的步骤千万别漏。
我在软件里把K型、J型、T型热电偶的分度表都做成了常量数组,配合PGA增益和参考电压反算成电压,再进入补偿流程。整个模块化之后,换传感器类型就只改一个通道配置。
4.3 校准操作与误差分配
再好的芯片也有偏移和增益误差。我的校准流程用冰水槽和干井炉分别做零点和满量程点:
- 把PT100探头放入冰水混合物,等待温度稳定,记录ADC换算后的读数T0;
- 把探头放入100℃干井炉,等待稳定,记录读数T100;
- 按线性修正公式算出增益系数和偏移量: T_actual = (T_raw - offset) / gain
- 把gain和offset写进MCU的Flash,作为校准参数。
我还会加一个第三点校验,比如50℃恒温槽,确认线性修正后中间点的误差是否在0.1℃以内。如果中间点偏差大,通常不是校准问题,而是探头本身不合格或者接触热阻太大,需要检查安装方式。
校准后,我在实验室里用四线PT100做基准,整机误差在-20℃到100℃范围内能做到±0.1℃以内,这对HVAC领域而言已经非常宽裕了。
5. 实验室和HVAC现场实测,以及我踩过的三个坑
5.1 实验室里的精度表现
先放一组我在恒温槽里的实测数据,探头是四线PT100,配置PGA=1、IDAC=1mA、20SPS、32次移动平均:
| 恒温槽设定温度(℃) | 方案读数(℃) | 与设定差值(℃) |
|---|---|---|
| 0 | 0.02 | +0.02 |
| 30 | 29.98 | -0.02 |
| 50 | 50.04 | +0.04 |
| 70 | 70.01 | +0.01 |
| 100 | 99.97 | -0.03 |
这个结果在HVAC场景里算是相当稳的。不过要提醒一句,实验室里干净、无干扰、恒温,现场情况会复杂得多。
5.2 现场干扰下的实测差异
我把这套方案放到冷站项目的现场,旁边就是变频器和冷冻水泵。对比原来的4-20mA模拟变送器方案,最直观的感受是温度曲线从“毛刺”变成了“平线”。
原方案在变频器满载运行时,温度显示波动大约±0.6℃;换成ADS122U04就地数字化之后,一个小时的温度记录曲线标准差只有0.03℃左右,肉眼几乎看不出波动。原因不复杂:ADC直接放在传感器旁边,模拟信号只有几厘米长的走线,数字信号再通过长线传给主控,中间就算有干扰也很难改数据,大不了被CRC丢掉重传。
另外,ADS122U04这种Δ-Σ ADC的内部数字滤波器对工频及其倍频有一定抑制,配合前端RC滤波和TVS,现场电磁环境基本构不成威胁。
5.3 三个坑,一个比一个隐蔽
先讲通信卡死的坑。现象是设备运行几天后,温度读数变得很长一段时间不更新,重启后又正常。排查链路是这样的:先软件打LOG,发现MCU发配置命令后ADC没有任何响应;再量电压,供电正常;最后用逻辑分析仪抓TX/RX波形,发现TX正常、RX完全静默。深入查下去,是PCB上RESET引脚走线紧挨着一根外设电源线,上电瞬间和外部干扰时被耦合拉低,芯片反复复位。解决办法很简单:RESET引脚加一个10kΩ上拉到VDD,并且板子上把走线挪远一点。
第二个坑是自热误差。现场有两根探头,一只PT100一只PT1000,贴在同一根管子上,读数却差0.15℃。我一开始以为是探头标定问题,后来把PT1000的激励电流从1mA改成250µA,温差立即消失。原因就是PT1000在1mA下电阻功耗太大,自热把探头局部温度抬高了。这种事在实验室里很难暴露,因为探头悬空散热好,一旦贴到管道或埋墙里,自热效应就明显了。
第三个坑是模拟输入引脚漏电。有一批次样板在高温高湿环境测试,0℃点总是漂移到0.15℃以上,而且数值慢慢爬。排查到最后,是PCB清洗不彻底,残留助焊剂在潮湿环境下在两条相邻走线之间形成了微弱的漏电路径,相当于给ADC输入并联了一个可变电阻。解决方式是生产时加强清洗工序,板子完成后涂三防漆,尤其覆盖模拟输入区域。这问题在HVAC的潮湿机房特别容易重演,别忽略。
6. 直接能抄作业的寄存器配置与采集代码
6.1 寄存器配置速查表
下面这张表是我在PT100三线制场景下常用的配置建议,具体寄存器地址和字段定义请打开对应手册对照,但配置思路是通用的:
| 配置项 | 建议值 | 理由 |
|---|---|---|
| 输入MUX | AIN0/AIN1 | 通道选择,按布局定 |
| PGA增益 | 1(RTD)/ 128(热电偶) | RTD信号幅值足够,热电偶需要放大 |
| IDAC1输出 | 1mA(PT100)/ 250µA(PT1000) | 兼顾信噪比与自热限制 |
| IDAC2 | 关闭或用于三线补偿 | 视接线方式决定 |
| 参考源 | 外部RREF | 比例测量,抵消电流温漂 |
| 数据速率 | 20SPS | 温度是慢信号,速率低噪声小 |
| 内部温度传感器 | 开启 | 热电偶冷端补偿使用 |
| CRC | 开启 | 现场干扰下保证通信可靠 |
三线PT100时,我会用两个IDAC分别驱动RTD两端,利用差分输入扣除引线电阻。这个配置在寄存器里对应IDAC1和IDAC2的分配,现场按手册设一次就固定了。
6.2 温度采集主循环代码
主循环里做的事情很简单:按固定间隔读ADC码值,转电阻,转温度,做滤波,然后送显示或上传。核心代码大概是这样:
uint32_t code = ads122u_read_adc(); float ratio = (float)code / 8388608.0f; // 除以2^23,得到比例 float r_rtd = ratio * R_REF; // R_REF是外部精密电阻 float temp = pt100_res_to_temp(r_rtd); // 查表/公式换算温度 temp = moving_average(temp); // 滑动平均滤波滤波我用的是16点滑动平均,对温度和输出频率都合适。注意滑动平均的缓冲区是全局的,别在中断里和主循环同时访问,否则会出现抖动。
如果你需要长时间稳定记录,还可以做一阶低通滤波:
float filtered = filtered + alpha * (raw - filtered);alpha取0.2左右,既跟得上温度变化,又足够平滑。
6.3 还能怎么扩展:从RS-485到多点温度场
这套架构最方便的地方在于天然适合分布式测温。一个STM32F413RH有多个UART接口,每个UART接一片ADS122U04,一个主控就能带几个采集节点。如果控制柜和传感器距离超过几十米,把MCU这边的UART转成RS-485,节点之间走Modbus协议,现场布线和调试都极其舒服。
F413的FPU在这里也派上了用场。我把多个通道的温度数据都做了线性化修正,还顺手算了冷站当前COP(能效比),纯粹是CPU大材小用。如果以后想加PID控制、温度趋势预测,甚至做个小型的FFT看压缩机振动信号,这颗芯片的资源都还宽裕。
同一个前端硬件,我还做成了多传感器兼容模式:通过检测接入电阻范围自动判断是PT100、PT1000还是NTC,然后切换到对应的激励电流和查表逻辑。HVAC项目后期运维最怕传感器型号混用,这个自动识别功能帮我省了不止一次现场返工。
最后分享一个小细节,也是我踩过几次坑之后养成的习惯:RTD引线的屏蔽层,我坚持在ADC这一侧单端接地,另一端悬空。两侧都接地看起来更“稳妥”,实际上会在屏蔽层里形成地环路电流,反而把工频干扰引到模拟地上。单端接地之后,长线传感器在变频器环境下才真正安静下来。如果你做温度采集时遇到莫名其妙的50Hz噪声,先查一下屏蔽层接地方式。