做过暖通空调控制柜和电力电子控制器的人应该都体会过“温度监测”这四个字背后的工作量。早几年我做一套嵌入式空气处理机组控制器光回风温度和板温就占了四根模拟线NTC 要分压、要对表、要每个批次做标定热电偶虽然耐温但毫伏级信号在电柜里一过就是一路地环路噪声。后来换方案把本地和远程温度整合到了一颗芯片上——标题里的 PJ85718DM 就是这颗 I2C 接口的双通道数字温度传感器主控用 PIC32MZ1024EFF144 这颗 200MHz 的 MIPS 内核 MCU。整套系统既测板卡自身温度也测远端管道、功率器件或机组关键部位一步解决。这篇文章把我在实际联机中整理的硬件接线、寄存器处理、滤波策略和踩坑记录完整写出来给正在做嵌入式设备热保护、HVAC 机组监控或者类似项目的人做个参考。1. 为什么要跟同一颗芯片较劲本地温度与远端温度的需求同构1.1 嵌入式和 HVAC 场景里的两个温度往往对应两种保护先说嵌入式场景。逆变器、充电桩、伺服驱动器这类设备有两类温度你绕不开一是 PCB 板卡本身的温度二是功率器件或者说热源核心的温度。板温低一点高一点可能只影响电路稳定性但 IGBT、MOSFET 这种功率级的结温一旦超标几秒钟内就可能炸管或者触发降额保护。以前很多板子把热敏电阻贴在散热器上线拉到 MCU 的 ADC每一条线都要单独处理标定还随批次波动。HVAC 场景其实也一样。机组内部的控制器板卡需要监控自身温度因为电控箱在夏天可能被太阳晒到 60°C另一方面风管、水管的介质温度、压缩机机壳温度又是工艺控制的关键参数通常装在离主控板几米甚至十几米远的地方。过去的做法是 PLC 加一堆模拟量模块一个测点一路模拟量输入硬件成本和调试成本都不小。这两类项目放到一起看需求结构完全同构一个近点一个远点近点要求反应快、拉偏保护及时远点要求精度稳、能扛环境干扰。既然这样把两个测点交给同一颗芯片、同一份寄存器、同一个 I2C 地址就比接两路 ADC 要清爽得多。PJ85718DM 这类器件正是这么设计的本地通道读封装附近温度远程通道通过一对 D/D- 引脚外接二极管结读的是远端那个结的温度。1.2 远程二极管测温的原理两路小电流算出 ΔVBE远程为什么用一个二极管就能测温本质上是利用了 PN 结正向压降和温度之间的关系。如果给一个二极管通恒定的正向电流VBE 会随温度升高而下降大约是 2mV/°C。可要真用“绝对 VBE”来测温度麻烦在于每个二极管的 VBE 离散性很大同一温度下不同批次能差几十毫伏换算成温度就是好几度。所以这类芯片不会傻傻地只测一个 VBE而是在两个不同电流下测两次取差值 ΔVBE VBE1 - VBE2。根据半导体物理ΔVBE 与温度近似成正比同时把饱和电流、反向漏电流这些共性项抵消掉了。再用第三个电流点做修正还能进一步把串联电阻、非理想因子的影响压下去。这就是为什么远程二极管通道能做到 ±1°C 甚至更好的精度而不需要用户自己去标定二极管参数。在接线上你可以直接用一颗贴片三极管当作感温头NPN 管的发射极接 D基极接 D-集电极悬空PNP 管同样也是发射极接 D、基极接 D-。曾经有一版我把极性接反读出来的温度直接往负方向飘了 30°C这个我们放到最后一节排查部分细说。1.3 为什么不继续用 NTC 或热电偶可能有朋友要问NTC 便宜量又足热电偶耐温范围广为什么非要换成二极管远程测温方案接线成本标定难度信号抗干扰适用距离NTC2 线/点需分压电阻每批次要做分压标定非线性电压信号长线易受压降影响板内或短距离热电偶2 线/点需冷端补偿冷端补偿模型复杂线材配套要求高毫伏级信号极易受电机、开关电源干扰现场仪表常用本地远程二极管传感器最多 4 线I2C电源远程 2 线数字输出无需分压表格仅需两点偏移校正差分方式测 ΔVBE抗共模干扰较强远程可拉数米至十几米我自己用的感受是换掉 NTC 之后最明显的收益是调试时间缩短。以前现场温度不准你根本说不清是探头问题、分压电阻问题还是接线松动问题现在数字量直接从 I2C 读出来温度异常时先怀疑电路板上的走线和接触问题范围小了很多。2. 硬件连接与总线设计PJ85718DM 与 PIC32MZ1024EFF144 配合的细节2.1 I2C 主机与供电地址怎么定PIC32MZ1024EFF144 是一颗资源很“富”的片子I2C 外设有好几个我这边用 I2C1 做主机接 PJ85718DM 的 SDA/SCL。供电上传感器和 MCU 都走同一路 3.3V传感器电源脚旁边放一颗 0.1uF 去耦电容这是最稳妥的起步配置。SDA、SCL 两根线需要上拉电阻典型值用 2.2kΩ 到 4.7kΩ 都行取决于总线上挂了几颗设备如果总线上就这一颗传感器4.7kΩ 足够总线长度不超过 20cm 时非常稳。地址引脚是容易忽略的地方。这类 I2C 温度传感器一般都有 A0/A1 两个地址选择脚接地和接电源有多种组合最后形成好几个可选 I2C 地址。我当时把两个地址脚都拉低7 位地址落在 0x4C如果你把其中一个接到 VCC地址就会变成 0x4D 之类。实践上建议做法是上电后先写一个 I2C 总线扫描程序把 0x00 到 0x7F 扫一遍看看传感器实际响应哪个地址再固定写进配置。不要凭记忆硬编地址我亲眼见过别人因为地址位没拉对读了一天全是 0xFF。ALERT/THERM 这类报警输出引脚在嵌入式板卡上值得接到 PIC32MZ 的某个 GPIO 中断上。它通常用开漏输出要加上拉温度超限时由传感器自己拉低主控即使正在忙其他事情也能立刻知道不用靠轮询。2.2 D/D- 的接法三极管当“感温头”远程通道的 D 和 D- 需要一个真正的二极管结。工程上最常见的做法是直接用一个小信号三极管的发射结因为三极管来源广、一致性比乱七八糟的稳压管好而且封装小方便贴在测温点上。NPN 型如 MMBT3904PNP 型如 MMBT3906都能用。接法记住一句话发射极进 D基极进 D-集电极悬空。这样组成的二极管结方向才能保证传感器在正偏状态下做电流切换。在 HVAC 现场我习惯把三极管焊在一小片覆铜板上外面套不锈钢套管再灌导热胶做成一枚“管道温度探头”。这样探头的热时间常数可控插到风管里也不怕凝露。嵌入式场景里可以直接把三极管贴在 IGBT 模块表面比如先涂导热硅脂垫一层绝缘片再把管体压紧读到的就是功率模块表面的实时温度比贴在旁边的 NTC 反应快不少。有一点要特别留意D/D- 这一对线走的是差分测温但传感器芯片本身对线间电容比较敏感。如果为了滤波在 D/D- 之间加了大电容比如 10nF 以上转换结果会出现明显滞后甚至偏差。我后续调试中用的做法是容值控制在 1nF 以内或者干脆只在对地各加一个 100pF 到 1nF 的小电容而不在线间跨接大电容。2.3 远程感温线的布线与保护远程二极管测温的原理决定了它对串联电阻、线间噪声有一定容忍度但这不意味着可以随便飞线。我实测过线径太细、距离超过 20 米、又靠近变频器输出线时读数跳动能达到 ±2°C 以上。最理想的布线形式是双绞线让 D 和 D- 受到的电磁干扰尽量共模化再靠传感器的差分测量抵消掉。在电路板上从 PIC32MZ1024EFF144 这侧看D/D- 的过孔和走线要远离开关电源的电感、MOSFET 栅极驱动走线特别是不要和 PWM 信号线长距离平行。如果空间允许在 D/D- 进传感器引脚前加一级 RC 低通例如串 100Ω对地各并 1nF既抑制噪声也不会明显影响响应速度。现场远距离应用时我会在探头端加一个小的 TVS 管防止雷击感应或机组启停时产生的浪涌损坏传感器内部电路。3. 固件实测寄存器读写、温度换算与远端二极管标定3.1 用 Harmony 配置 I2C 外设先扫地址固件这层我是基于 MPLAB Harmony v3 搭的。在图形配置界面里把 I2C1 设为 Master 模式7 位地址速率先跑 400kHz。如果你所在环境电磁干扰比较严重也可以先降到 100kHz反正温度数据量不大100kHz 也绰绰有余。I2C 时钟本身就来自外设时钟分频确认分频后的 SCL 频率不要超规格这是最基础的一步。配置完成后第一步先做 I2C 地址扫描。这个方法在调试初期特别有用能把总线问题、地址问题和接线问题快速分开。void i2c_scan(void) { for (uint8_t addr 0x08; addr 0x78; addr) { // 封装一个 I2C read 单字节并带 ACK 检测的函数 // 如果该地址有设备 ACK打印出来 if (i2c_probe(addr)) { // 记下实际地址 printf(I2C found: 0x%02X\n, addr); } } }我实际扫出来的地址就是 0x4C说明 A0/A1 都接地生效了。如果你扫不到任何地址优先检查 SDA/SCL 是不是接反了、上拉电阻焊没焊、电源给没给上而不是去怀疑寄存器配置。这一步排查顺序能帮你在前半小时解决 80% 的联机问题。3.2 读远程和本地温度寄存器换算的完整代码确认地址之后就要读温度数据了。以我手头这颗 PJ85718DM 的寄存器版式为例本地温度寄存器在 0x00远程温度寄存器在 0x01配置寄存器在 0x03。需要说明的是不同批次、不同封装的同类器件寄存器位定义可能会有细节差异移植代码时请务必以你自己拿到的数据手册为准。#include stdint.h #define ADDR_TEMP 0x4C #define REG_LOCAL_TEMP 0x00 #define REG_REMOTE_TEMP 0x01 #define REG_CONFIG 0x03 // 读取两个字节的温度寄存器 static uint16_t read_temp_reg(uint8_t reg) { uint8_t buf[2]; uint8_t reg_addr reg; // 这里调用你自己的 I2C 库函数 // 先发送器件地址写位发送寄存器地址 // 再发送器件地址读位连续读 2 字节。 i2c_write(ADDR_TEMP, reg_addr, 1); // 指定寄存器 i2c_read(ADDR_TEMP, buf, 2); // 连续读两字节 return (uint16_t)((buf[0] 8) | buf[1]); } float read_remote_temp_celsius(void) { uint16_t raw read_temp_reg(REG_REMOTE_TEMP); // 远程温度寄存器常见格式高字节 低字节的高 3 位 // 低 3 位是状态/保留位右移去掉。 raw 3; // 如果是 11 位有符号数位 10 是符号位手动扩展成 16 位有符号 int16_t signed_raw (int16_t)(raw 0x07FF); if (signed_raw 0x0400) { signed_raw | (int16_t)0xF800; } // LSB 0.125°C return (float)signed_raw * 0.125f; }本地温度读取流程完全一样只是把寄存器地址换成 0x00。可以顺带把本地和远程温度放在同一帧结构体里再连同时间戳一起交给上层逻辑处理避免出现“本地是上一秒读的、远程是这一秒读的”这种不一致在需要做温度差判断时会是个隐患。3.3 标定流程两点偏移校正与 β / 串联电阻补偿远程二极管通道出厂时是按理想的二极管模型校准的但实际用的三极管不可能跟理想模型完全一致。如果只要求 ±1~2°C 的监控精度其实可以忽略差异但如果你做的是精确控温比如恒温槽、实验室环境舱就需要做一次标定。我的标定流程很简单准备一个能控温的恒温槽或者一块带测温孔的铝块把高精度温度计和远程探头放在同一位置。分别在 25°C 和 45°C 两个温度点读一次芯片输出算出两个偏移量。float remote_apply_offset(int16_t raw_celsius) { // 25°C 处偏移 0.375°C45°C 处偏移 0.875°C // 根据两个标定点做线性插值 static const float ref[2] {25.0f, 45.0f}; static const float off[2] {0.375f, 0.875f}; float slope (off[1] - off[0]) / (ref[1] - ref[0]); return (float)raw_celsius off[0] slope * ((float)raw_celsius - ref[0]); }两点的偏移如果差不多说明主要是二极管离散性造成的固定偏差加一个常数就行。如果偏移量随温度明显变化就要怀疑是不是三极管的发射结串联电阻偏大或者 β 值偏低导致传感器内部电流比切换时出现了额外误差。这时优先换一颗来源可靠、一致性好一些的 MMBT3904 再试通常比调程序里的补偿系数更省事。提示标定完成之后把偏移量写进芯片自带的远程偏移寄存器可以做到“硬件级修正”即使主控程序重刷也不会丢。但很多这类寄存器的粒度是 0.125°C写入后记得回读确认。4. HVAC 与嵌入式两套数据滤波策略同一颗传感器不同脾气4.1 HVAC 追求稳定低通滤波和慢速率变化温度采样本身不难难的是怎么把数据交给控制逻辑。暖通空调这边风管里的温度变化本来就慢压缩机启停周期至少是以分钟计。如果直接把每一次 I2C 原始读数交给 PID哪怕只有 0.125°C 的量化噪声都可能让执行器频繁动作。所以我在 HVAC 应用里用的策略是低通滤波 慢周期采样。具体做法可以每 500ms 读一次数据喂给一阶低通float lowpass_filter(float previous, float current, float alpha) { return alpha * current (1.0f - alpha) * previous; }在风柜回风温度这种场景alpha 取 0.05~0.10 就行等效时间常数大约在 3~10 秒既能反映温度趋势又不会因为风机启停导致读数剧烈抖动。你可能会担心这样响应太慢但 HVAC 系统的被控对象本来就是一个大惯性系统几秒钟的滞后完全可接受。这里有一个细节滤波系数最好不要用一个常量写死而是根据温差动态调整。比如当温度超过设定值 3°C 以上时我会把 alpha 提高到 0.3让报警信号快速响应正常范围内又降回 0.05保持稳定。这样既不会误报也不会让真正的超温被滤波“吃掉”。4.2 嵌入式保护要快短窗口、异常跳变丢弃嵌入式设备的热保护跟 HVAC 完全是两码事。IGBT 在过载瞬间温度爬升非常快电源模块在短路时几毫秒内就可能超出安全温度滤波如果太重保护动作就会迟到。这一侧我用的策略是“短窗口滑动平均 跳变剔除”。比如每 10ms 读一次取最近 8 次数据做平均等效滞后大约 40ms 左右对过温保护来说足够。读数如果比上一拍突变了 8°C 以上大概率是干扰或者接线松动先丢弃这一拍再用上一次的值顶上。这里不能盲目相信单个数据因为远程二极管通道在受到强干扰时偶尔会冒出一个离群值直接把它当成真实温度去触发保护是很危险的事。static float temp_buf[8]; static uint8_t temp_idx; float embedded_temp_check(float current) { // 跳变剔除 if (fabsf(current - last_valid) 8.0f) { return last_valid; } temp_buf[temp_idx] current; if (temp_idx 8) temp_idx 0; float sum 0.0f; for (int i 0; i 8; i) sum temp_buf[i]; float avg sum / 8.0f; last_valid current; return avg; }两种场景放一起看思路完全不同HVAC 怕误动作所以把系统做“钝”嵌入式怕保护不及时所以把窗口做“锐”。同一个传感器、同一份原始数据最后呈现在不同系统里的行为差别很大。4.3 状态与告警处理ALERT 引脚怎么接进固件温度滤波只解决了数据好不好用的问题真正要落地到保护逻辑还需要把告警拉出来。PJ85718DM 这类器件一般都配了 ALERT 或者 THERM 引脚主机可以给它写上限、下限由传感器自己持续比较温度超限就拉低引脚。我在 PIC32MZ1024EFF144 这边的做法是把 ALERT 接到一个能用边沿中断的 GPIO 引脚下降沿触发中断。在中断里只做“置标志 记录发生时间”不进行复杂滤波计算主循环检测到标志后再进一次正常的温度读取流程确认是否真的超限。这个二次确认机制很关键能避免因为一次 I2C 毛刺就误触发保护。如果系统里有多路温度传感器ALERT 引脚可以都接到同一个 GPIO 上做成“线与”。哪一路超限都会拉低总线主控通过扫描不同的 I2C 地址去定位到底是哪个传感器报警这在多温区控制的 HVAC 机组里非常实用。5. 实测之后绕不开的几个坑远端感测噪声、错误接线与地线压差5.1 远程通道极性接反读数瞬间变成负数第一次调试时我随手拿了一颗贴片 NPN 管按“发射极接 D-、基极接 D”的老印象接上结果读出来的远程温度在 -20°C 左右而实际室温是 25°C。检查了半天才发现是极性接反了。正确接法是发射极接 D基极接 D-。如果你用的是 SOT-23 封装三极管管脚定义很紧凑建议每一批板子回来都先对照规格书确认丝印方向不要凭上一批的经验直接焊。这种错误在实验室里只是数据不对到了现场就很容易误判成传感器损坏。5.2 高速开关噪声让原始值乱跳从源头压而不是堆滤波还有一次我把 D/D- 走线从一块开关电源的电感底下穿过结果远程温度读数间歇性跳变跳变量大概 0.5~1°C用示波器看才发现线上叠加了一堆振铃。我一开始想在程序里加大滤波系数确实能压住但把真实的热响应也拖慢了。后来改成双绞线走线、让两根线贴着走、离开电感区域并在传感器端对地各加 1nF 电容问题基本消失。这里我想说的经验是滤波应该是最后一道保险而不是第一道防线。能从布局布线解决的问题就不要用软件滤波去扛否则温度数据“看起来平滑”实际物理位置的热变化却已经被掩盖了。5.3 现场地线压差导致整体偏移把远程线当成差分对看在 HVAC 现场最容易忽略的是地电位差。一套机组里变频器、压缩机、控制器各有各的接地点两个接地点之间可能有 0.1~0.3V 的直流压差。如果 D 和 D- 在地线上形成环路传感器测量的 ΔVBE 就会叠加一个共模误差读数出现整体偏移。解决思路是把 D/D- 当成一对真正的差分信号来布从探头到传感器尽量不经过其他设备的接地回路屏蔽层单端接地避免形成多点接地环路。如果实在绕不开就在传感器端对地加共模滤波。实测下来把线改成双绞并远离动力线后原本 1°C 多的偏差能降回到 0.2°C 以内。5.4 读出来全是 0x7FFF先从总线时序找原因最后说一个调试中最常见的“假故障”I2C 读回来的值不是 0xFF 就是 0x7FFF。一开始我也怀疑是传感器坏了换了一颗还是如此最后定位到是 SCL 频率配得太高加上飞线过长导致从机应答信号没有被主机正确采样。这类问题的排查顺序建议是先降速到 100kHz再拿示波器看 SCL/SDA 波形确认 ACK 位是否干净。如果降速后读数正常那就是高频振铃问题别急着换芯片。温度传感器对时序的要求并不苛刻但长线、跳线、手焊的杜邦线都会破坏信号完整性稳定优先再把速度提上去。最后分享一点经验整套系统调完我最深的体会是PJ85718DM 这类“本地远程”双通道传感器设计的真正价值不只是省一个 I2C 地址而是把热管理的核心问题——近点保护与远点监测——统一成同一套数据访问方式。PIC32MZ1024EFF144 的算力对这种应用来说绰绰有余真正决定项目成败的反而是布线和标定这些不起眼的细节。如果你手头的项目也要做嵌入式板温或者 HVAC 温度监控我建议先画一份 D/D- 的走线约束图再写代码等硬件稳定了固件这边基本就是读寄存器、标准化处理和滤波三件事。下一步我会把这套方案再接一路 Modbus 转出去让楼宇监控后台能直接读到每一个温区的实时数据这也算把“本地与远程”的最后一公里打通了。