基于PJ85718DM与PIC18F86J15的嵌入式多点温度监测方案 做嵌入式温度监测这几年我遇到最多的需求其实不是“测不准”而是“测不全”。一台HVAC机组、一个电控柜往往既要看主控板附近的温度又要盯风管、回风口这些离主控好几米远的点。前阵子某项目做了一个嵌入式温度监测模块用的正是PJ85718DM这颗I2C数字温度传感器搭配PIC18F86J15做主控同时解决本地与远程温度采集的问题。这篇文章就把这个方案的完整思路、电路细节、固件框架和调试中踩过的坑都摊开来说适合正在做HVAC控制器、嵌入式测温模块、多点温度采集的工程师参考。1. 需求拆解为什么要分开监测“本地”与“远程”温度1.1 HVAC 机组的“本地”和“远程”到底指哪里很多人一看到“本地”和“远程温度”下意识以为一个指的是设备侧、一个指的是手机App远程查看。实际在嵌入式HVAC场景里这两个词指的是物理位置的差别。本地温度通常指主控板所在环境、机箱内部、回风口附件这些离MCU只有几厘米到几十厘米的位置。它反映的是设备自身的工作状态——比如主板是否过热、电源模块附近温度是否异常。远程温度则指风管深处、送风口、室外换热器、冷水管道表面这些需要拉线才能到达的位置。它反映的是空调系统服务的环境状态比如送风温度是否达标、盘管有没有冻结风险。两种温度用途完全不同。本地温度更多用于设备保护远程温度更多用于系统控制。如果把两者混在一个采集点做就会出现保护不及时或控制滞后的问题你把传感器放在室外机侧主板过热了根本看不到放在主板旁边送风温度又测不准压缩机频率调度就成了瞎猜。1.2 多点测温比单点测温多出来哪些价值单点测温的局限其实不是精度不够而是信息量不够。HVAC系统本质上是一个热力环路冷量、热量在管路里传递中间任何一个点温度异常都可能引发连锁问题。只有本地一个温度点你只能判断“设备这会儿热不热”根本没法判断“冷媒走到哪一段出问题了”。这个项目里一共布置了4个PJ85718DM温度传感器两个本地点主控板附近和电源模块附近、两个远程点送风管和回风管。采集数据后做三件事显示各点实时温度让现场调试人员直接看到温度分布。用送风温差控制风机转速和冷阀开度。用本地温度做设备过热保护温度超过阈值直接触发告警。这里最核心的价值是温差。回风温度减去送风温度得到的温差能直接反映空调负荷变化比单点绝对值稳定得多不受季节基准温度漂移影响。这是单点测温方案无论如何都做不到的。2. 器件选型逻辑PJ85718DM 与 PIC18F86J15 各司其职2.1 PJ85718DMI2C 数字温度传感器的工作定位PJ85718DM是一颗I2C接口的数字温度传感器主要参数定位非常贴合HVAC和嵌入式场景测温范围覆盖-55°C到125°C分辨率可以配置到12位对应0.0625°C的LSB。这个量程和分辨率对空调系统而言绰绰有余毕竟风管温度常规范围也就-20°C到80°C。它最实用的两个特性一个是地址可配置另一个是片上报警比较。地址可配置对多点方案至关重要。PJ85718DM的I2C地址由A0、A1、A2三个引脚电平决定最多可以在同一条I2C总线上挂8颗芯片地址范围通常是0x48到0x4F。这意味着我不需要为每个远程测温点拉独立的模拟线只需要一条双绞线总线就能把所有传感器串起来。片上报警比较则能减轻主控负担。芯片内置上限报警寄存器T_OS和下限报警寄存器T_HYST实测温度超限后ALERT引脚会主动拉低主控可以直接用外部中断响应不必毫秒级轮询温度寄存器做判断。这颗芯片定位很像经典的LM75/TMP275这一类I2C温度传感器寄存器的使用习惯也类似对用过I2C总线的人来说上手很快。2.2 PIC18F86J15做主控的取舍PIC18F86J15是Microchip的8位PIC18系列单片机80引脚TQFP封装3.3V供电。选它做主控并不是因为它性能有多强而是因为它把HVAC场景需要的资源几乎都配齐了两个MSSP硬件模块同时支持I2C和SPI一路I2C挂温度传感器总线另一路还能留给外部EEPROM或显示驱动。多路EUSART串口可以直接接RS-485收发器连上位机或触摸屏不用软件模拟串口。10位ADC通道足够富裕哪怕后续要加NTC模拟输入做冗余也不缺引脚。内部支持外部晶振配合PLL到40MHz工作在8位机里算中等偏上的算力。另外很重要的一点PIC18系列在工业环境下的稳定性比较可靠I2C模块的时序由硬件产生不占用CPU去翻转IO模拟时序。这在HVAC现场强电干扰环境下有实打实的优势软件模拟I2C一旦被中断卡顿时序很容易被拉长导致通信失败硬件MSSP不会出这种问题。2.3 为什么不用模拟 NTC 而用数字 I2C 传感器HVAC行业里大量方案还在用NTC热敏电阻有人质疑为什么绕一圈用I2C数字传感器。我的回答很简单因为要测远程点。NTC方案在本地测温没问题短距离走线干扰小只要一分压电阻和ADC引脚就能读数。但远程点一拉线就麻烦NTC电阻值本身会随线阻变化线缆长了几米就引入不可忽略的误差而且模拟信号抗干扰能力弱走线贴近压缩机、继电器这些强干扰源后ADC读数会抖动得很厉害。数字I2C传感器把模拟量到数字量的转换放到了传感器端总线上传输的是数字信号受线阻和共模干扰的影响小得多。只要I2C时序正确、地址不冲突、上拉电阻合理几米线缆内的读数一致性非常好。项目中远程点只这种需求下数字传感器几乎是唯一合理的选择。3. 硬件设计细节供电、总线拓扑与报警触发链路3.1 供电与电平转换问题PJ85718DM和PIC18F86J15的工作电压定位都是3.3V这给电路设计省了很多事。电源用一颗AMS1117-3.3LDO从24V/12V系统电源降压得到LDO前面加TVS管和共模电感防止压缩机启停时电源毛刺打进来。有一点必须提醒HVAC控制板很多外围器件是5V逻辑比如继电器驱动、LCD背光、老式按键板。如果板上同时存在5V和3.3V系统I2C总线千万别直接连通。PIC18F86J15和PJ85718DM都是3.3V器件挂到5V总线上轻则读取出错重则长期过压损坏芯片。我在这块板上的处理方式是I2C总线完全跑在3.3V域所有5V器件只接IO控制引脚用三极管或光耦隔离互不影响。如果你是现有5V系统改造需要让温度传感器跑在5V那I2C引脚必须加电平转换芯片或者至少用开漏结构配合合适的上拉电压让主控3.3V和传感器5V在总线上通过上拉电阻决定实际高电平。3.2 多传感器地址分配与总线接线4个PJ85718DM的地址分配在原理图上就要定好。A2、A1、A0三根引脚通过跳线电阻接到VDD或GND焊板上用0欧电阻选择高或低电平。我这里用了0x48、0x49、0x4A、0x4B四个地址分别对应本地主板、本地电源、远程送风、远程回风。地址跳线做成排针方便现场如果传感器坏了可以临时换地址顶上。总线接线采用了手拉手的菊花链式拓扑从主控板出发一根I2C线串过各个传感器。总线上拉电阻选了4.7kΩ这个值在3.3V供电、总线下挂了4颗芯片、线缆总长约3米的情况下工作稳定。如果远程线缆超过5米建议降到2.2kΩ增强驱动能力或者把速率降到100kHz以下跑。远程传感器的连接器我用了RJ45水晶头的壳里面只用了4根线VDD、GND、SCL、SDA。用RJ45纯属工程习惯好插拔、锁扣牢靠现场检修方便。但要注意RJ45线序必须定死并在外壳上标注不然现场的人随便接一根网线很容易把SDA和SCL搞反。3.3 报警输出如何接入主控中断PJ85718DM的ALERT引脚是开漏输出所以需要外接一个10kΩ上拉电阻到3.3V。平时高电平当温度超过上限寄存器或低于下限寄存器时拉低。硬件上我把四颗传感器的ALERT引脚分别接到了PIC18F86J15的四个外部中断引脚上用的中断引脚资源分别是INT0、INT1、INT2和某个Input Capture引脚。这里不建议把四个ALERT直接短接成一个中断信号虽然从省引脚的角度看很诱人但一旦告警发生你需要在中断里逐个I2C读寄存器才能知道是哪颗传感器报警排查起来非常麻烦。分离中断输入让中断服务程序直接根据中断标志位定位到报警源省很多事。另外ALERT引脚配一个0.1μF电容到地滤掉传感器附近干扰引发的毛刺误触发。在电控柜里接触器吸合瞬间的干扰能轻松让一根悬空的开漏线产生几十毫秒的电平抖动这个电容是必加的。4. 固件实现寄存器配置、轮询流程与阈值更新4.1 系统初始化顺序固件初始化有个顺序问题我前后调过好几次才稳定。推荐顺序是先初始化I2C硬件和GPIO再配置PJ85718DM寄存器最后开中断。void System_Init(void) { // 1. IO口初始化ALERT相关引脚设为输入 TRISAbits.RA0 1; // ALERT_1 外部中断输入 TRISAbits.RA1 1; // ALERT_2 TRISBbits.RB0 1; // ALERT_3 TRISBbits.RB1 1; // ALERT_4 // 2. 初始化I2C主模块100kHz32MHz时钟 SSP1CON1 0x08; // 使能I2C主模式 SSP1CON1bits.SSPM 0b1000; // I2C master mode, clock Fosc/(4*(SSPADD1)) SSP1ADD 79; // 32MHz / (4 * 100kHz) - 1 79 SSP1STATbits.SMP 1; SSP1CON1bits.SSPEN 1; // 3. 配置4个温度传感器 TempSensor_Init(0x48, ALERT1); TempSensor_Init(0x49, ALERT2); TempSensor_Init(0x4A, ALERT3); TempSensor_Init(0x4B, ALERT4); // 4. 开外部中断使能全局中断 INTCONbits.PEIE 1; INTCONbits.GIE 1; }初始化I2C时SSPADD的设置是很多人容易搞错的地方。PIC18的MSSP模块主模式下I2C时钟是系统时钟除以4再除以(SSPADD1)和常见的计算方式不太一样。我系统时钟外部晶振10MHz经PLL倍频到32MHz算下来SSPADD79得到约100kHz实测时序稳定。如果你改了晶振或倍频配置一定要重新算不要照搬例程里的数值。4.2 多点温度轮询代码框架PJ85718DM的温度值存放在两个8位寄存器里高字节是整数部分低字节的高4位是小数部分。读取顺序是先发地址字节再发寄存器指针0x00然后连续读2个字节。float TempSensor_ReadChip(BYTE i2c_addr) { BYTE hi 0, lo 0; int raw; // 发送起始、器件地址写、寄存器指针 IdleI2C1(); StartI2C1(); MasterWriteI2C1((i2c_addr 1) | 0); // 设备地址 写位 MasterWriteI2C1(0x00); // 指向温度寄存器 RestartI2C1(); // 重复起始 MasterWriteI2C1((i2c_addr 1) | 1); // 设备地址 读位 hi MasterReadI2C1(); // 读高字节 ACKDT 0; AckI2C1(); // 发送ACK lo MasterReadI2C1(); // 读低字节 NotAckI2C1(); // 最后一个字节发NACK StopI2C1(); raw (hi 8) | lo; // 12位分辨率符号扩展 if (raw 0x8000) raw | 0xF000; return (float)raw * 0.0625f; // LSB 0.0625°C }轮询周期我设在1秒。100kbps的I2C总线读4颗传感器总共也就要几十个字节的传输耗时在几毫秒级别1秒的周期对HVAC的热惯性来说绰绰有余。真正限制周期的不是I2C速度而是你后续怎么处理数据。如果你要用PID控制压缩机频率温度采样周期建议控制在0.5~2秒之间太快的轮询反而会让控制环路对噪声更敏感。4.3 本地远程数据融合与阈值管理本地和远程温度采集回来不是各自独立的在HVAC控制里经常要把它们组合成控制逻辑使用的量。这里给一个最常用的经验公式化处理方式typedef struct { float local_mainboard; float local_power; float remote_supply; float remote_return; } TempPoint; float GetSupplyAirDelta(TempPoint *t) { // 送风温差 回风温度 - 送风温度 return t-remote_return - t-remote_supply; }阈值管理上报警阈值不是一次性写死到PJ85718DM寄存器里的。启动时给一个保守默认值比如本地报警上限设为85°C远程上限设为60°C运行过程中根据季节或用户设定动态写入。因为PJ85718DM报警寄存器可以直接通过I2C修改所以我每隔5秒检查一次是否需要更新阈值。还有一点要注意PJ85718DM默认工作在比较模式下ALERT引脚在温度回落到滞后值以下之后会自动释放非常适合做设备保护。如果你想要锁存式告警触发后必须软件清除需要在配置寄存器里把中断模式打开。HVAC场景推荐比较模式因为现场经常出现瞬时过热如果锁存了必须断电重启才能清除太耽误事。5. HVAC 场景的特殊考量线缆衰减、干扰过滤与校准5.1 远程探头线缆长了之后会怎样HVAC现场的远程传感器线缆动辄三到五米有的老项目还从配电间拉到空调机房十几米都有。I2C在长线下有几个明显变化信号边沿变缓、振铃加重、反射干扰。经验范围是线缆长度超过3~4米时I2C速率降到100kHz以下超过10米直接降到50kHz或者改为I2C中继方案。现场实测下来3米双绞线在100kbps下波形还算干净SCL高电平上升沿大约在200ns左右能正常通信。但做过一个测试到6米的线同样的上拉电阻和速率开始出现随机通信失败看波形SCL在跳变沿有振铃SDA在数据翻转时偶发毛刺。把速率降到50kHz并且把上拉电阻改成2.2kΩ后恢复正常。所以说不要迷信“I2C只能跑短距离”这种结论。距离是速率、上拉强度、线缆类型三者的联合约束。工程上用好双绞线、降低速率、合理选上拉5米内完全能稳定跑。再远就该考虑用I2C总线缓冲器比如PCA9515这一类的总线中继芯片或者干脆换成RS-485远程采集方案。5.2 滑动均值与异常值剔除远程传感器在空调箱振动、风机变频器附近工作读到的原始温度值偶尔会有毛刺。毛刺来源一般是供电波动或总线干扰导致某次读到的LSB异常偏大。消除毛刺最有效的手段是滑动均值加异常值剔除。我用的窗口是5次滑动平均每次采集后更新#define FILTER_WINDOW 5 float TempFilter_Add(float new_value, float *buf, BYTE *idx) { float sum 0; BYTE i; buf[*idx] new_value; *idx (*idx 1) % FILTER_WINDOW; for (i 0; i FILTER_WINDOW; i) sum buf[i]; return sum / FILTER_WINDOW; }同时在进入滤波器之前先做物理合理性判断温度值小于-55°C或大于125°C直接丢弃超过上一次读数正负8°C的突变也丢弃。这个“突变丢弃”能挡住绝大多数总线错误读数。有一次在调试现场变频器一启动SDA线上就出现干扰导致某次读到的温度高字节从0x1D变成了0x5D直接跳变几十度就是靠突变判断拦下来的。5.3 两点校准与误差补偿PJ85718DM出厂精度在典型应用里够用但HVAC系统对远程温度控制要求稍微苛刻时还是做一次两点校准更稳。我用的办法很土但很有效冰水混合物和恒温水浴锅分别把传感器探头放进去读取芯片原始值和标准温度计读数然后按线性公式写入固件补偿。typedef struct { float offset; float gain; } CalibParam; float TempSensor_ApplyCalib(float raw, CalibParam *c) { // y (raw offset) * gain return (raw c-offset) * c-gain; }标定时拿到的原始值与参考值的差值以0°C和50°C两个点的误差算斜率修正系数。这颗芯片线性度本身不错两点校准后的误差基本能控制在±0.2°C以内。还要提一个细节传感器对环境温度变化的响应速度受探头封装影响很大远程点测温别指望它秒级跟上温度变化采样周期和校准只要关注稳态精度就够了动态响应快慢由探头结构和安装位置决定不是软件能解决的。6. 实测数据与踩坑复盘6.1 一组实测数据看稳定性和偏差项目调试后期我在现场连续跑了一整天记录了一组稳态数据对比读数与我们手持标准温度计的差值结果如下采集点平均读数标准温度计差值本地主板旁34.6°C34.5°C0.1°C本地电源模块41.2°C41.4°C-0.2°C远程送风管16.8°C16.7°C0.1°C远程回风管24.3°C24.5°C-0.2°C这个稳定性和偏差表现对HVAC控制来说已经足够。而且注意连续跑一天时间里PJ85718DM读到的数值波动范围在正负0.3°C以内完全没有出现长时间漂移。比较有意思的是送风和回风两个点成对使用回风温度24.3°C减送风温度16.8°C得到7.5°C的温差正好对应当时的空调负荷这个数据反馈到控制逻辑里比单独看任何一个绝对温度都更有意义。6.2 几个印象深刻的坑第一个坑是上拉电阻值选太大。最初选了10kΩ上拉本地点短距离通信完全正常一接上远程线缆就开始随机出错。用示波器看发现SDA上升沿快到1μsSCL高电平被拉得很软I2C主设备在快速翻转时就误判了。换成4.7kΩ之后远程就稳定了这个问题绝对值得排在实际拉线之前提前考虑。第二个坑是PIC18F86J15的MSSP模块寄存器初始化顺序。直接照抄某参考例程把SSPEN放到了配置模式之前导致I2C模块一直进不了主模式单步调试了半天。正确顺序是先配置模式位最后置SSPEN使能模块。第三个坑是ALERT引脚忘记配置为漏极开路。我最初以为ALERT是推挽输出用万用表量到低电平就以为正常。后来接上主控中断引脚后怎么都触发不了才意识到该芯片ALERT内部是开漏我没加上拉电阻时高电平根本出不来。这个问题代码上完全体现了但硬件上不加上拉是查不出来的。第四个坑关于远程传感器的接线极性。采购回来的RJ45成品线分直通和交叉两种现场工人随意拿了一根接上去SDA和SCL被内部调换了温度读数直接变成固定值0xFF。后来我干脆在连接器旁边标注了线序并把连接器键位做防呆才避免再犯。6.3 可以直接照抄的几条经验先给几条我这次项目做完之后觉得最值得固化的经验三点决定I2C远程通信稳定性上拉电阻、线缆长度、总线速率。三者要配套调整先短距离调通再加长线验证不要指望单独调一个参数解决所有问题。多点测温的报警源识别ALERT引脚分别接独立中断不要为省引脚而合并否则排查报警来源的时间会远大于省IO口节省的成本。温度采集周期1秒对HVAC足够滤波窗口5次滑动加突变剔除是低成本高收益的标配组合。数字温度传感器真的不适合用软件模拟I2C去读PIC18F86J15有硬件MSSP模块就优先用硬件模块省下来的CPU时间可以做控制算法。原理图阶段定好A0~A2地址跳线做成标准排针现场换传感器或扩展测点时非常灵活。做完整套方案后回到最初的需求看PJ85718DM加PIC18F86J15的组合确实把本地和远程温度监测做成了模块化、可扩展的系统。远程点没有用繁琐的模拟采集而是用一条数字总线串起了所有探头既降低了布线复杂度也让后续加测温点变得非常简单。对我个人来说这套方案最大的成就感还不只是温度测准了而是把原本需要一堆转换电路和调理电路的事情简化成了几根线和一个寄存器表。下次遇到类似需求我大概率会把这套硬件架构直接复用只改协议栈去适配不同的上位机。