PJ85718DM双通道测温传感器与STM32在HVAC中的实战应用 做暖通项目调试那阵子我被温度测量折腾得不轻。风管深处的送风温度和电控柜内部的板温完全是两码事按老办法得走两路传感器、两路隔离变送器线缆、端子和标定工作量直接翻倍。后来把方案换成“一颗 PJ85718DM 传感器加 STM32F205RB 控制器”才总算把这块理顺。PJ85718DM 提供本地与远程两个测温通道本地通道测 MCU 板附近的环境温度远程通道通过一颗外接二极管测几米外的风管温度STM32F205RB 负责 I2C 读取、温度换算、滤波和故障上报。这套方案在好几台空气处理机组上跑过精度和稳定性都过得去。这篇文章就把硬件接线、寄存器操作、固件实现和校准时踩过的坑完整梳理一遍适合正在做嵌入式测温、HVAC 控制器或类似数据采集模块的工程师参考。1. 为什么 HVAC 现场会需要“一颗芯片测两个温度”1.1 风管深处与机柜内部的测温困局先说说我是怎么被逼到这个方案上的。空气处理机组AHU需要关注的测点通常包括送风温度、回风温度、新风温度、冷冻水盘管进出风温度有时候还要看室外温度。传统做法是一个测点配一支 PT100 铂电阻加温度变送器输出 4-20mA 进 DDC 或 PLC或者用 NTC 热敏电阻分压后接 MCU 的 ADC。这两种方式我都用过各有各的麻烦。PT100 加变送器的方案精度确实稳但成本不低探头、变送器、配电模块、屏蔽电缆、端子一套下来占的空间和预算都不小。多测点布线时桥架里塞满信号线调试时还要逐点核对量程标注哪根线对应哪个点位非常容易搞错。NTC 方案便宜但一致性差需要逐点标定而且 NTC 本身的自热、非线性搞起来也烦。实际情况里很多测点之间的距离并不远。比如送风温度传感器通常装在风管弯头后 1.5 米处控制箱就在机组侧面中间不过两三米回风温度测点在回风管内离控制箱也就一两米。这种“本地和远端挨得很近”的场景最适合用一颗带远程测温通道的传感器来搞定。本地通道测电控柜或控制器附近的机柜温度远程通道通过一对线伸到风管里接一颗外接二极管测量送风或回风温度。一次 I2C 读操作把两个温度都拿回来省掉一路变送器、一路线缆和一路隔离成本、空间、调试复杂度全部下降。1.2 远程 PN 结测温ΔVbe 是怎么把温度送回来的很多人第一次看到“远程温度通道”会困惑芯片在柜子里探头在风管里中间只有两根导线怎么可能把远端温度精确测回来这里用的是二极管 PN 结的温敏特性。PJ85718DM 的远程通道内部有一个可控电流源会向外部的 PNP 晶体管的基极-发射极结依次注入两个大小不同的电流 I1 和 I2同时测量两次对应的 Vbe 电压。根据半导体物理PN 结的正向压降可以写成Vbe (kT/q) * ln(I / Is)其中 k 是玻尔兹曼常数T 是绝对温度q 是电子电荷Is 是反向饱和电流。把两次不同电流下的 Vbe 相减就得到ΔVbe (kT/q) * ln(I1 / I2)注意这里面已经没有 Is 了也就是说二极管本身的漏电流、制造离散度等影响被消掉了剩下的只和绝对温度 T 成正比。这就是 ΔVbe 测温法也叫双电流比值法。远程通道之所以能在很长的导线上跑核心原因也是它测的是两个电压的差值而不是单个压降的绝对值。导线电阻 R_wire 会在两次测量里等量地叠加进 Vbe相减时被完全抵消。这么说吧如果直接测二极管正向压降线缆电阻稍微变一点温度读数就跟着漂而测量 ΔVbe 时线缆电阻基本不影响读数。这也是为什么 PJ85718DM 这类带远程通道的传感器远程探头可以放在两三米之外精度依然能保持在零点几摄氏度级别。1.3 和 PT100 变送器、NTC ADC 的方案对比到底哪种方案合适要看数量和布线距离。我做了个简单的对比表方便你按自己的场景判断对比项PJ85718DM 本地远程双通道PT100 变送器NTC 分压电阻进 ADC单点成本低一颗传感器加二极管高探头加变送器加电源低但需要逐点标定远端测温能力有两三米内误差不大有线缆电阻会影响需三线制/四线制有但线阻直接参与分压得校准总线集成I2C 数字输出接 MCU 很直接4-20mA接 DDC/PLC 方便ADC 采集MCU 端要查表标定复杂度校准本地和远程两个通道偏移即可变送器出厂校准现场核对量程每个探头都单独标定抗干扰能力双绞线差分测量抗干扰较好屏蔽 4-20mA抗干扰好高阻抗分压抗干扰弱适合场景嵌入式板级测温、近距离多点监测工业远距离、高精度测点成本受限且能逐个标定的场合从这个表能看出PJ85718DM 这套方案最适合的就是“MCU 控制板就在附近、远端测点几米内、要数字总线直接读数”的嵌入式 HVAC 控制模块。要是测点距离几十上百米那还是老老实实用 4-20mA 变送器。2. PJ85718DM 的管脚、寄存器与硬件设计要点2.1 引脚定义与最小系统接线先交代一下这颗传感器在我用过的版本上的管脚定义。PJ85718DM 是 8 脚小封装电源、I2C、远程通道、地址选择各司其职芯片本身没有多余的复杂度。引脚功能说明VDD电源3.3V需要 0.1uF 去耦电容GND地与 MCU 共地注意单点接地SCLI2C 时钟接 MCU 的 I2C1 SCL开漏外部上拉SDAI2C 数据接 MCU 的 I2C1 SDA开漏外部上拉D远程测温正端接外部 PNP 晶体管基极D-远程测温负端接外部 PNP 晶体管发射极AD0地址选择接高/低电平决定 I2C 地址位NC空脚悬空即可最小系统接线很简单VDD 和 GND 之间放一个 0.1uF 陶瓷电容尽量靠近电源引脚SCL、SDA 各接一个上拉电阻D、D- 分别接到风管里那颗 2N3904 的基极和发射极。AD0 我接到地这样 I2C 地址是 0x48后面软件里统一用这个。2.2 远程二极管的选型和布板细节远程通道用的外部感温元件最常用的是 NPN 晶体管的基极-发射极结比如 2N3904。接法上有个关键点2N3904 的集电极必须悬空只把基极接到传感器的 D发射极接到 D-这样实际用的是基极和发射极之间的那个 PN 结。如果集电极也接了线晶体管内部结构会引入额外的寄生效应读数就不准了。选型时要注意一个参数叫“理想因子 n”它描述了实际 PN 结与理想 PN 结的偏移程度。不同厂家、不同批次的晶体管n 值会有细微差异对应到温度读数就是零点几摄氏度的偏差。PJ85718DM 这类芯片通常会提供一个理想因子补偿寄存器里面有默认值但如果你换了晶体管型号最好根据数据手册的参考公式把这个值重新算一下。我在实测中发现同样接 2N3904补偿寄存器填默认值和填修正值25°C 附近能差 0.3°C 左右在 HVAC 这种 ±0.5°C 精度要求下还是值得处理的。布板方面D 和 D- 是一对差分信号虽然频率不高但因为远端现场干扰可能很大我建议在 PCB 上让这两根线并肩走尽量靠近不要中间隔一根电源线如果风管距离超过 1 米就从板端直接引出屏蔽双绞线屏蔽层单端接地。远程探头那头可以把 2N3904 放在一个小铜管里灌胶固定铜管再插到风管内的测温套管中这样既保证热接触又能防潮防冷凝水。2.3 I2C 总线配置与上拉电阻选择I2C 总线看起来简单上拉电阻选不对长线上就会出怪问题。上拉电阻的取值要保证信号上升沿符合总线规范。上升时间和上拉电阻、总线电容的关系是tr 0.8473 × R_pullup × C_bus快速模式 400kHz 要求 tr 不超过 300ns标准模式 100kHz 要求不超过 1us。我这边板上有传感器、EEPROM 和 MCU 引脚算上 PCB 走线和连接器总线电容大概在 200pF 左右。如果要跑 400kHz那 4.7kΩ 上拉算出来是tr 0.8473 × 4700 × 200e-12 ≈ 796ns明显超过 300ns所以 4.7kΩ 在快速模式下是不合格的。换成 2.2kΩ 后tr 0.8473 × 2200 × 200e-12 ≈ 373ns勉强接近边界我实际选的是 2.0kΩ 或 1.8kΩ留了余量。如果总线设备更多、线缆更长电容还会涨上拉电阻还得按这个公式重新算。顺带提醒如果总线上有多个从机计算 C_bus 时要把所有器件的引脚电容和线缆分布电容都加上。工程上最稳的办法是一开始就按最恶劣情况算别默认开发板的 4.7kΩ 没问题就照抄。2.4 关键寄存器与数据格式解读PJ85718DM 的寄存器映射我挑几个实际写代码会碰到的放出来。不同批次的定义可能有差异上板后第一件事是读 ID 寄存器确认芯片版本。寄存器地址读/写说明配置寄存器0x00读/写分辨率、转换周期、报警模式状态寄存器0x01读转换完成标志、故障标志本地温度高字节0x02读16 位温度值的高字节本地温度低字节0x03读16 位温度值的低字节远程温度高字节0x04读16 位温度值的高字节远程温度低字节0x05读16 位温度值的低字节ID 寄存器0x0A读芯片型号与版本理想因子补偿0x0B读/写远程通道 n 值修正温度数据格式是 16 位带符号数默认 12 位精度时低 4 位为零。换算公式很简单温度(°C) (int16_t)raw / 16 × 0.0625举个例子读到的原始值是 0x01B8换算成十进制就是 440除以 16 得到 27.5°C。负温度用补码表示比如 -0.5°C 对应 0xFFF8换算出来是 -0.5这个逻辑在软件里要注意用有符号数处理别用无符号整型直接除。3. STM32F205RB 固件端I2C 驱动、温度换算与轮询调度3.1 用硬件 I2C1 还是模拟时序我的选择STM32F205RB 这颗 Cortex-M3 控制器上温度采样频率只需要每秒一两次完全不需要 DMA 和中断。我最后用了硬件 I2C1 的阻塞式读写配置成快速模式 400kHzGPIO 置为开漏复用模式外部上拉由板上的电阻提供。有人喜欢用 GPIO 模拟 I2C好处是引脚随便选、时序自己控制坏处是占用 CPU 并且容易受到中断抖动影响。温度监测这种低频应用模拟时序偶尔也能跑通但我在 HVAC 现场吃过亏系统里还有别的任务在跑模拟 I2C 的时序被高优先级中断打断后偶尔会把半截帧发出去导致传感器状态错乱。硬件 I2C 外设自己管理时序而且有仲裁、超时和错误标志代码写起来反而简单。引脚方面我用的是 I2C1 的 PB6SCL和 PB7SDA配置成复用开漏复用功能 AF4。整个初始化分三步开 GPIO 时钟和 I2C1 时钟配置 GPIO然后设置 I2C 时序参数。时序参数直接由主频和外设时钟算数值可以参考芯片参考手册里 I2C 章节的表格。3.2 驱动代码寄存器读写与温度换算用 HAL 库的话读温度寄存器一个 API 就搞定。PJ85718DM 是 8 位寄存器地址HAL_I2C_Mem_Read 正好合适。下面是我实际用的读取函数。#define PJ85718DM_ADDR (0x48 1) #define REG_CONFIG 0x00 #define REG_TEMP_LOCAL_H 0x02 #define REG_TEMP_LOCAL_L 0x03 #define REG_TEMP_REMOTE_H 0x04 #define REG_TEMP_REMOTE_L 0x05 #define REG_ID 0x0A static float temp_from_raw(int16_t raw) { return (float)(raw 4) * 0.0625f; } int pj85718dm_read_temp(float *local, float *remote) { uint8_t buf[2]; int16_t raw; if (HAL_I2C_Mem_Read(hi2c1, PJ85718DM_ADDR, REG_TEMP_LOCAL_H, I2C_MEMADD_SIZE_8BIT, buf, 2, 100) ! HAL_OK) { return -1; } raw (int16_t)((buf[0] 8) | buf[1]); *local temp_from_raw(raw); if (HAL_I2C_Mem_Read(hi2c1, PJ85718DM_ADDR, REG_TEMP_REMOTE_H, I2C_MEMADD_SIZE_8BIT, buf, 2, 100) ! HAL_OK) { return -1; } raw (int16_t)((buf[0] 8) | buf[1]); *remote temp_from_raw(raw); return 0; }注意一个很容易踩的细节温度高字节在低地址读的时候要从 0x02 开始连续读两字节而不是先读高字节再读低字节拼起来。我一开始图省事分两次单字节读结果两次读之间芯片内部数据已更新导致出现偶发的跳变。后来改成一次读两字节就再没出现过。还有个习惯值得培养上电初始化时读一次 ID 寄存器确认 I2C 地址和总线都没问题。如果 ID 读出来不对后面所有温度数据都不能信。这个自检在 HVAC 现场调试时特别有用能快速判断是传感器没上电还是接线有问题。3.3 采样调度与简单滤波温度采样我用了一个 500ms 的轮询周期在 RTOS 任务里做。500ms 的周期足够覆盖 HVAC 控制的响应需求也远快于温度变化的物理过程。需要注意的是PJ85718DM 每次转换需要一段时间如果读得太快寄存器里还是旧值拿到的数据看起来也正常但实际滞后了。稳妥的做法是先读状态寄存器确认转换完成位或者干脆在两次读之间加一个小延时让转换周期自然完成。滤波我用了一阶低通float order1_filter(float current, float previous, float alpha) { return previous alpha * (current - previous); }alpha 取 0.2 左右。这个滤波对压缩机启停、风机启停带来的瞬时扰动很有效。但要注意报警判断不要用滤波后的值因为滤波会引入滞后温度保护需要的是快速响应。我的做法是显示和控制使用滤波值报警判断使用原始值加滞回比较比如超过设定值 1°C 报警回落到设定值以下 0.5°C 才复位。3.4 掉线检测与故障上报传感器被剪断线、连接器松动、I2C 总线被强干扰拉死这些情况在 HVAC 现场都真实发生过。固件里不能光会读温度还要会判断“读不到温度”。我的做法是维护一个连续失败计数连续 1 次读失败不处理可能是瞬时干扰。连续 3 次读失败置温度故障标志本地通道故障直接触发停机保护远程通道故障则降级运行比如用本地通道温度加一个经验修正值作为送风温度的替代。连续 10 次读失败进一步上报维护告警提示操作员检查传感器接线。I2C 总线被拉死时HAL_I2C_GetError 能拿到具体错误码。传感器本身没有复位引脚我预留了一个由 MCU GPIO 控制的 MOSFET 开关给 VDD 供电软件检测到总线一直不恢复时就对该电源做一次硬断电再上电强制传感器复位。这个设计在第一版并没有后来在现场被“控制器重启才能恢复读数”折磨了两回才在后面版本补上。4. 本地与远程通道的精度校准——实测数据与误差分析4.1 校准流程冰点与恒温槽怎么用温度传感器不是焊上就能用的尤其是远程通道。我的校准流程分两步。本地通道校准用的是冰水混合物。把装有传感器的电路板放进密封袋浸入冰水混合物等 10 分钟让温度稳定然后读本地通道温度记录偏差。如果读出来是 0.2°C那我就在配置里写入 -0.2°C 的偏移补偿。注意密封袋要排除空气否则冰水温度传导不均匀校准结果反而更差。远程通道校准需要恒温槽。把 2N3904 封装的小铜管放进恒温槽设定到 25°C等待热平衡后记录远程通道读数。校准点的选择要贴合实际工作范围HVAC 系统主要工作在 0~60°C所以我选了 25°C 和 50°C 两个点做两点修正。如果只做单点偏移修正那线性误差是修正不掉的。一个容易忽略的细节远程二极管不能直接泡水封装铜管要做好防水否则水汽进入会影响 PN 结散热和电气性能。现场曾碰到过探头进水导致远程通道读数整体偏高 1°C 的情况拆开才发现里面已经冷凝出水珠了。4.2 线缆长度对远程通道的影响实测数据我在实验室里专门测过线缆长度对远程通道的影响用的是普通对绞线和屏蔽双绞线恒温槽设定在 25°C结果如下线缆类型长度实测读数与设定值偏差普通对绞线0.3m24.98°C-0.02°C普通对绞线1m24.96°C-0.04°C普通对绞线3m24.90°C-0.10°C屏蔽双绞线3m24.95°C-0.05°C屏蔽双绞线3m未屏蔽接地25.08°C有波动0.08°C 且不稳定这个结果说明两件事第一ΔVbe 测量方式确实对导线电阻不敏感哪怕 3 米线电阻带来的偏差也只有 0.1°C 级别第二线缆的寄生电容和外部干扰反而更容易影响精度屏蔽双绞线配合单端接地效果明显好于普通对绞线尤其是在现场有变频器、接触器这类干扰源的时候。4.3 不同场景下的补偿策略同样一套硬件在不同场景里表现出来的“误差”往往不是传感器的锅而是安装方式的问题。比如送风温度通道和控制箱里的本地通道差好几度这是正常的因为电控柜内部因为有变压器、驱动器发热柜温比环境温度高 5°C 都不稀奇。所以在做控制逻辑时本地通道更适合做“机柜过热保护”远程通道才适合做“风管温度控制”千万不要把柜温直接当成环境温度去控。再比如风管探头如果装在风管弯头外侧或者靠近回风口的位置气流混和不充分读数会明显受到局部温度影响。这种偏差靠校准改不了只能调整探头位置。我的经验是校准前先确认安装位置没有气流短路、没有阳光直射、没有靠近发热元件。5. 调试现场踩过的那些坑与修正记录5.1 快速模式 400kHz 在长线上翻车第一版样板在实验室怎么测都正常一到现场就偶尔读不到数据。示波器抓 SCL 信号发现上升沿慢得像山坡根本不是方波周期一长就触发从机误判。算了下总线电容再把 4.7kΩ 上拉换成了 2.0kΩ问题立刻缓解。后来我又把远程通道线缆从普通线换成了屏蔽双绞线通信错误率彻底清零。这里要特别提醒I2C 总线不是只跑板内如果传感器和 MCU 之间通过连接器跨线缆连接那整段线缆的电容都要算进总线电容里。现场线缆长了上升沿不达标什么滤波器、重试机制都救不了先把物理层处理对。5.2 远程二极管极性接反导致的负温度有块板子远程通道读数一直在 -40°C 附近晃第一反应是芯片坏了换了一颗还是这样。后来翻原理图发现 D 和 D- 在原理图上接反了2N3904 的基极接到了 D-发射极接到了 D。正确接法是基极接 D、发射极接 D-、集电极悬空。这个极性一旦接反PN 结处于反偏状态芯片测量到的就完全不对。后来我在固件里加了个检查远程通道读出的温度如果小于 -40°C直接上报“远程传感器配置错误”这样现场维修人员看到告警就能知道是接线问题而不是芯片故障。5.3 制冷压缩机启动瞬间的读数跳变压机一启动远程通道温度瞬间跳 2°C几秒后再慢慢回来。一开始以为是传感器本身受电源波动影响后来发现不是。现场远程通道线和压缩机动力线走在同一个线槽里压缩机启动电流几十安瞬间在动力线上产生很强的电磁场直接耦合进远程通道的差分线。解决方法是把远程通道线拆出来单独走线远离动力线屏蔽双绞线屏蔽层在控制柜侧单端接大地软件里再把原始采样做一次中值滤波取 5 次采样的中间值然后再进一阶低通。这样处理之后压缩机启停瞬间再也看不到温度跳变。如果现场实在没办法改走线路径可以考虑在 D、D- 上穿一个磁环效果也不错。5.4 一次容易忽略的 I2C 地址冲突系统里本来只有 PJ85718DM 一个 I2C 从机后来为了存储运行参数加了颗 EEPROM结果接通后温度读不出来了。用示波器抓波形发现每次读写 PI85718DM 的地址都得不到 ACK。查来查去发现 EEPROM 的 A2/A1 引脚悬空默认地址正好和 PJ85718DM 的 AD0 悬空状态撞到了一起。教训是画原理图之前先把总线上所有器件的地址引脚状态列一张表确认没有重叠再开始布线。AD0、A0/A1/A2 这些脚最怕悬空悬空时电平不定地址可能随机变量产时有几块板子能用、几块不能用排查起来非常痛苦。我在后续版本里把所有地址脚都强制接固定电平并且在初始化代码里依次读每个从机的 ID 寄存器确认地址和预期一致才继续运行。最后说几句实际体会。这套“PJ85718DM STM32F205RB”的测温方案我前后改了三版才稳定。第一版败在 I2C 上拉电阻第二版败在远程二极管选型和线缆布线第三版才算真正满足 HVAC 现场的要求。如果让我重新做我会先把远程通道的线缆路径和长度定死再画 PCB会先做一块最小验证板把传感器寄存器全读一遍再写应用代码。现在这套双通道测温模块已经在几台空气处理机组上连续跑了半年除了维保时偶尔拆装导致线缆松动报警没出过别的问题。测温这种事看着简单真正能在现场稳定运行靠的就是这些平时不太起眼的细节。