基于PJ85718DM与STM32F405RG的远程温度监测方案设计与实现
1. 项目背景与核心需求拆解温度监测这件事听起来像是电子工程入门第一课的内容——接个传感器读个电压换算成温度完事。但真正落到工业级嵌入式和 HVAC暖通空调场景里事情远没有这么简单。我做过好几个类似的项目从冷库温度记录仪到楼宇空调分区控制每一次都会在“精度”“距离”“抗干扰”“多点组网”这几个维度上反复拉扯。这次要聊的方案核心是用 PJ85718DM 配合 STM32F405RG搭建一套能同时覆盖本地温度采集和远程温度监测的系统。先把这个标题拆开看。PJ85718DM 是一颗远程温度传感器芯片采用 SMBus/I2C 兼容接口内部集成了本地温度传感和远程二极管温度采集功能。所谓“远程”是指它可以外接一个二极管连接的三极管通常是 MMBT3904 这类小信号管把这个管子贴在需要测温的位置芯片本体放在方便布板的地方两者之间用走线连接。STM32F405RG 则是 ST 家的 Cortex-M4 主力型号168MHz 主频带 FPU1MB Flash192KB RAM外设资源丰富I2C 接口随便用。这两者搭在一起本质上就是“MCU 做主机 远程温度芯片做从机”的经典组合。那为什么偏偏选这两个器件我在实际选型时考虑过几个替代方案。如果用 DS18B20 这类数字温度传感器优点是单总线、便宜、防水封装成熟但缺点是每个传感器都需要单独走线多点测温时布线成本高而且单总线在长距离传输时对时序要求苛刻稍微有点线缆电容就容易读失败。如果用 NTC 热敏电阻加 ADC成本最低但需要做线性化校准精度受 ADC 参考电压和分压电阻精度影响很大批量生产时一致性不好保证。PJ85718DM 的优势在于它把本地和远程测温集成在一颗芯片里远程通道可以接一个三极管三极管本身成本极低而且可以贴在远离主控板的位置用普通铜线连接即可不需要额外的转换电路。STM32F405RG 的 I2C 外设支持 400kHz 甚至 1MHz 速率配合 PJ85718DM 的 SMBus 超时机制在 HVAC 这种电磁环境复杂的场合也能稳定通信。这个方案适合谁呢如果你正在做空调控制板、地暖分集水器温度采集、机房环境监控、冷库多点测温或者任何需要“板载温度 远端温度”同时监测的嵌入式项目这套组合都值得参考。哪怕你用的是别的 MCU只要带 I2C 主机功能PJ85718DM 的驱动逻辑也是通用的。下面我会从硬件设计、寄存器配置、固件实现、远程通道校准、常见问题排查几个层面把整个方案掰开揉碎讲清楚。2. 硬件设计与关键参数计算2.1 PJ85718DM 的引脚功能与外围电路PJ85718DM 通常采用 MSOP-8 或 SOP-8 封装引脚定义大致如下VCC、GND、SDA、SCL、ALERT、D、D-、以及一个地址选择引脚。VCC 供电范围 3.0V 到 5.5V和 STM32F405RG 的 3.3V 系统可以直接对接不需要电平转换。SDA 和 SCL 需要接上拉电阻典型值 4.7kΩ 到 10kΩ具体取决于总线电容和通信速率。我一般用 4.7kΩ400kHz 速率下实测波形上升沿在 300ns 左右足够干净。远程测温通道的核心是 D 和 D- 两个引脚。D 连接到三极管的基极和集电极把三极管接成二极管形式D- 连接到发射极。这里有个细节三极管必须选用低噪声、低漏电流的小信号管比如 MMBT3904 或者 2N3904。我试过用 S8050结果远程通道读数偏高 3 到 5 摄氏度后来查资料才发现是 S8050 的基极-发射极漏电流偏大导致芯片内部电流源产生的电压被拉偏。换回 MMBT3904 之后误差立刻降到 1 摄氏度以内。这个坑后面还会细说。ALERT 引脚是开漏输出可以配置成温度超限报警。在 HVAC 场景里这个引脚可以直接接到 STM32 的外部中断实现硬件级过温保护不需要 MCU 轮询。地址选择引脚通常有三态接 GND、接 VCC、悬空对应不同的 I2C 从机地址。这意味着同一条总线上最多可以挂三颗 PJ85718DM如果还不够就得用 I2C 多路复用器扩展。2.2 远程三极管的选型与走线要点远程测温的精度很大程度上取决于三极管本身和走线质量。先说三极管选型。理想情况下远程二极管连接的晶体管应该满足几个条件基极-发射极电压的温度系数稳定在 -2mV/°C 左右漏电流小封装热阻低。MMBT3904 是行业里用得最多的便宜、好买、参数一致性好。如果你需要更高精度可以考虑 MMBT3906 或者专门用于温度传感的二极管连接三极管但成本会上去。走线方面D 和 D- 最好走差分对尽量靠近远离高频开关节点和电源走线。我在一个空调控制板项目里最初把 D 和 D- 走在继电器驱动走线旁边结果远程温度读数每隔几秒就跳变一次幅度大概 2 到 3 摄氏度。后来把这两根线移到板子另一层并且包了地线屏蔽跳变立刻消失。如果三极管需要贴在离主控板较远的位置比如风管里或者水箱表面建议用双绞线连接每米线缆的电阻和电容都会影响信号质量但 PJ85718DM 的电流源驱动方式对线缆电阻不敏感主要影响来自线缆电容导致的信号边沿变缓。实测下来双绞线长度在 2 米以内400kHz 通信完全没问题超过 5 米建议把 I2C 速率降到 100kHz。2.3 STM32F405RG 的 I2C 外设配置STM32F405RG 的 I2C 外设支持标准模式100kHz、快速模式400kHz和快速模式1MHz。PJ85718DM 的 SMBus 超时是 35ms所以通信速率不能太低否则一次完整读取可能超时。我一般配置成 400kHz既保证速度又留足余量。I2C 的 GPIO 需要配置成开漏复用模式内部上拉可以不启用因为外部已经有上拉电阻了。时钟控制寄存器里的 CCR 值需要根据 APB1 总线频率计算。假设 APB1 是 42MHz目标速率 400kHzCCR 42MHz / (2 × 400kHz) 52.5取整为 52。实际配置时还要考虑上升时间TRISE 寄存器设置为 (1000ns / (1/42MHz)) 1 43。DMA 方式读取温度数据可以减轻 CPU 负担但 PJ85718DM 的寄存器不多一次读取也就几个字节用中断方式足够了。我通常用 HAL_I2C_Mem_Read 函数指定从机地址、寄存器地址、数据长度然后等待完成。注意 HAL 库的 I2C 函数在遇到总线错误时会返回 HAL_ERROR需要做超时重试。我在一个项目里遇到过从机被静电打挂的情况SDA 被拉低不放这时候需要手动发送 9 个时钟脉冲来解锁总线STM32 的 I2C 外设没有自动恢复功能得用 GPIO 模拟时钟来救场。3. 寄存器配置与温度数据换算3.1 本地温度通道的配置流程PJ85718DM 上电后默认处于待机模式需要先写配置寄存器才能启动转换。配置寄存器通常有两个Configuration Register 1 和 Configuration Register 2。具体位定义需要查数据手册但大致逻辑是设置转换速率比如 1 次/秒、4 次/秒、8 次/秒、设置本地和远程通道的使能位、设置 ALERT 引脚的触发条件。我一般把转换速率设成 4 次/秒对于 HVAC 这种温度变化缓慢的场景这个速率绰绰有余还能降低功耗。本地温度通道的读取很简单直接读 Local Temperature Register得到一个 16 位数据高 8 位是整数部分低 8 位是小数部分分辨率 0.0625°C。换算公式是温度 (高字节 × 256 低字节) / 256。注意这个寄存器是只读的读完之后自动清零下次转换完成后再更新。如果你连续读两次第二次读到的可能是旧数据或者 0所以最好在读取前检查状态寄存器的“转换完成”标志位。3.2 远程温度通道的校准与误差补偿远程通道的读取稍微复杂一些。除了 Remote Temperature Register 之外还有一个 Remote Temperature Offset Register用来补偿三极管个体差异和走线电阻带来的误差。理想情况下MMBT3904 在 25°C 时的 VBE 大约是 0.65V温度系数 -2mV/°C。但实际批次之间会有 ±5mV 的差异对应大约 ±2.5°C 的误差。所以批量生产时最好做一次单点校准把三极管放在已知温度环境里比如冰水混合物 0°C 或者恒温槽 25°C读取远程通道的原始值然后计算偏移量写入 Offset Register。Offset Register 的格式通常是 8 位有符号数每一位代表 0.0625°C范围 -128 到 127对应 -8°C 到 7.9375°C。如果误差超过这个范围说明三极管选型或者走线有问题需要先排查硬件。我在一个项目里遇到过远程读数比实际低 10°C 的情况查了半天发现是三极管焊反了基极和发射极对调导致芯片内部电流源无法正常驱动。所以焊接完成后一定要用万用表测一下三极管的 PN 结压降确认方向正确。3.3 温度数据的滤波与上报策略原始温度数据难免有噪声尤其是远程通道走线越长耦合的干扰越多。我通常会在固件里做两级滤波第一级是滑动平均取最近 8 次采样值求平均这样能平滑掉高频噪声第二级是一阶低通滤波系数取 0.1 到 0.2进一步抑制突变。但要注意滤波会引入滞后对于需要快速响应的过温保护场景ALERT 引脚应该直接使用原始数据不要经过软件滤波。上报策略取决于你的应用场景。如果是本地显示每秒更新一次就够了如果是上传到云端或者上位机可以每 10 秒或者 30 秒上报一次减少通信负担。我在一个楼宇空调项目里用 STM32 的 UART 转 485 总线每 5 秒轮询一次所有温度节点然后打包上传。轮询周期太短会导致总线负载高太长又会影响实时性5 秒是实测下来比较平衡的值。4. 固件实现与实操步骤4.1 初始化序列与寄存器写入固件启动后第一步是初始化 I2C 外设配置 GPIO 和时钟。然后发送 PJ85718DM 的从机地址检查 ACK 响应。如果 ACK 失败说明硬件连接有问题需要检查上拉电阻、电源和地。确认从机在线后写入配置寄存器。我一般按以下顺序操作写 Configuration Register 1设置转换速率、通道使能、ALERT 极性。写 Configuration Register 2设置 ALERT 阈值和故障队列。写 Remote Temperature Offset Register写入校准值。等待至少一个转换周期然后读取状态寄存器确认转换完成。这里有个细节PJ85718DM 的寄存器地址是 8 位的但 I2C 传输时寄存器地址后面跟的数据可能是 8 位或者 16 位。写配置寄存器通常是 8 位读温度寄存器是 16 位。用 HAL 库的时候HAL_I2C_Mem_Write 的 MemAddressSize 参数要设成 I2C_MEMADD_SIZE_8BIT数据长度根据寄存器类型决定。4.2 温度读取的完整代码实现下面是一段基于 HAL 库的读取函数我把它简化了一下去掉了错误处理方便看清核心逻辑#define PJ85718DM_ADDR 0x4C 1 // 假设地址选择引脚接 GND float read_local_temp(void) { uint8_t buf[2]; HAL_I2C_Mem_Read(hi2c1, PJ85718DM_ADDR, 0x00, I2C_MEMADD_SIZE_8BIT, buf, 2, 100); int16_t raw (buf[0] 8) | buf[1]; return raw / 256.0f; } float read_remote_temp(void) { uint8_t buf[2]; HAL_I2C_Mem_Read(hi2c1, PJ85718DM_ADDR, 0x01, I2C_MEMADD_SIZE_8BIT, buf, 2, 100); int16_t raw (buf[0] 8) | buf[1]; return raw / 256.0f; }注意远程温度寄存器的地址通常是 0x01本地是 0x00具体以数据手册为准。读取回来的 16 位数据高字节在前低字节在后直接拼起来除以 256 就是摄氏度。如果读到的值是 0x8000 或者 0xFFFF说明转换还没完成或者通信出错需要重试。4.3 多节点组网与地址分配如果一条 I2C 总线上挂多颗 PJ85718DM需要通过地址选择引脚设置不同的从机地址。通常三态引脚可以产生三个地址接 GND 是一个接 VCC 是另一个悬空是第三个。如果还需要更多节点就得用 I2C 多路复用器比如 TCA9548A它可以把一条总线扩展成 8 条每条挂一颗 PJ85718DM。我在一个冷库项目里用了 4 颗 PJ85718DM分别监测蒸发器出口、冷凝器入口、库内空气和库外环境通过 TCA9548A 切换通道STM32 只需要一个 I2C 外设就能搞定。组网时要注意总线电容。I2C 规范规定总线电容不能超过 400pF每颗 PJ85718DM 的引脚电容大约 10pF走线每厘米大约 1pF所以挂 4 颗芯片加上 20 厘米走线总电容大概 60pF完全没问题。但如果走线超过 1 米电容可能超过 200pF这时候需要降低通信速率或者使用 I2C 缓冲器。5. 常见问题与排查技巧实录5.1 远程温度读数异常的原因分析远程通道出问题是这个方案里最常见的坑。我整理了一个排查表按出现频率从高到低排列现象可能原因排查方法解决方案读数偏高 3-5°C三极管漏电流大换 MMBT3904 对比更换低漏电流三极管读数偏低 10°C 以上三极管焊反测 PN 结压降重新焊接读数跳变 ±2°C走线受干扰示波器看 D 波形双绞线屏蔽地读数固定 0x8000转换未完成查状态寄存器增加等待时间读数固定 0xFFFF通信失败查 ACK 和上拉检查硬件连接三极管漏电流这个问题特别隐蔽。MMBT3904 的 ICBO 典型值是 0.1nA而 S8050 可能达到 1μA差了四个数量级。PJ85718DM 内部电流源通常在 10μA 到 100μA 之间如果三极管漏电流达到 1μA就会在 D 和 D- 之间产生额外的电压降导致读数偏高。所以选型时一定要看数据手册里的漏电流参数不要随便拿手头的三极管凑合。5.2 I2C 通信失败的恢复策略I2C 总线被从机拉低是嵌入式开发里的经典问题。PJ85718DM 在受到静电或者电源波动时可能会进入异常状态SDA 一直保持低电平导致主机无法发起新的通信。STM32 的 I2C 外设没有自动恢复机制需要手动处理。我的做法是检测到 HAL_I2C_ERROR_TIMEOUT 或者 HAL_I2C_ERROR_BERR 之后先把 I2C 外设复位然后把 SCL 和 SDA 配置成普通 GPIO 开漏输出手动发送 9 个 SCL 脉冲每个脉冲后检查 SDA 是否释放。如果 9 个脉冲后 SDA 还是低说明从机彻底挂了需要断电重启。void i2c_bus_recovery(void) { GPIO_InitTypeDef gpio {0}; gpio.Pin GPIO_PIN_6 | GPIO_PIN_7; gpio.Mode GPIO_MODE_OUTPUT_OD; gpio.Pull GPIO_NOPULL; gpio.Speed GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, gpio); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET); for (int i 0; i 9; i) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET); HAL_Delay(1); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET); HAL_Delay(1); if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7) GPIO_PIN_SET) break; } // 重新初始化 I2C 外设 MX_I2C1_Init(); }这段代码我用了很多次救活过不少“假死”的从机。注意延时不能太短1ms 是保守值实际 100μs 也够但为了兼容不同从机建议留足余量。5.3 电源噪声对测温精度的影响HVAC 场景里继电器、接触器、变频器都是噪声源。PJ85718DM 的电源如果和这些负载共用一路温度读数会明显波动。我在一个项目里实测过继电器吸合瞬间本地温度读数跳变 1.5°C远程跳变 3°C。后来在 PJ85718DM 的 VCC 引脚旁边加了 100nF 和 10μF 的退耦电容并且用磁珠把数字电源和模拟电源隔开跳变降到 0.2°C 以内。如果条件允许最好给温度芯片单独一路 LDO 供电成本增加不多但效果立竿见影。另外STM32F405RG 的 ADC 参考电压如果和 I2C 电源共用也会互相干扰。虽然这个方案里温度数据是数字输出的不经过 ADC但如果你还用了 NTC 做辅助测温就要注意参考电压的稳定性。我一般会在软件里做电源电压监测如果 VDD 波动超过 5%就暂停温度采集等电源稳定后再继续。6. 实际应用中的经验总结与扩展思路6.1 校准周期的确定与批量生产建议远程温度通道的校准值不是一劳永逸的。三极管的老化、焊点应力、环境湿度变化都会导致 VBE 漂移。我在一个长期运行的项目里观察到运行一年后远程读数比初始校准值偏高了 0.8°C。所以如果对精度要求高建议每半年重新校准一次。批量生产时可以在产线上用恒温槽做单点校准把偏移值写入 STM32 的 Flash 或者 PJ85718DM 的 Offset Register。如果产线没有恒温槽也可以用两颗已知精度的参考温度计做对比校准虽然精度差一点但比不校准强得多。6.2 低功耗设计在电池供电场景下的取舍如果这个温度监测节点是电池供电的功耗就是关键。PJ85718DM 在待机模式下的电流大约 10μA转换时大约 300μASTM32F405RG 在睡眠模式下可以做到 2mA 左右。我的做法是让 STM32 每 10 秒唤醒一次启动 PJ85718DM 转换读取数据然后两者都进入低功耗模式。平均电流可以控制在 1mA 以内用 2000mAh 的电池能撑 80 天左右。如果不需要远程通道可以只使能本地通道功耗还能再降一半。6.3 从单点测温到分布式监测的扩展这套方案很容易扩展成分布式监测网络。每颗 PJ85718DM 可以带一个远程三极管STM32 通过 I2C 多路复用器管理多颗芯片再通过 485 或者无线模块把数据汇总到网关。我在一个农业大棚项目里用 8 颗 PJ85718DM 监测 8 个区域的温度STM32 通过 LoRa 模块上传到云端整个系统运行了两年多除了偶尔需要更换三极管大棚里湿度大焊点容易腐蚀没有出过大问题。如果要做冗余设计可以在每个测温点放两颗三极管接同一颗 PJ85718DM 的两个远程通道如果有的话或者接两颗芯片取平均值上报。最后分享一个小技巧PJ85718DM 的 ALERT 引脚可以配置成“温度超过阈值后保持报警直到主机读取寄存器才清除”。这个特性在过温保护里非常有用可以避免报警闪烁。配置的时候注意设置 Fault Queue 寄存器让连续几次超限才触发 ALERT防止误报。我一般设成连续 3 次超限才报警实测下来既能及时响应又不会被噪声干扰。