搞嵌入式的都知道测温度这件事看着简单可真放到 HVAC暖通空调控制系统里情况就完全变了控制板自身发热要管风管里的送风温度要管回风温度要管表冷器盘管表面温度也要管。不同位置、不同用途的温度对应的处理逻辑完全不同——有的用来闭环调速有的用来做防冻保护有的只用来判断设备会不会过热。标题里的 PJ85718DM 配 PIC18F86J16就是一套非常典型的低成本测温与控制组合前者把本地和远程两路温度测量做进同一颗芯片后者负责读数、滤波、校准、上报并把温度换算成风机和压缩机的动作。这篇文章就按实际做项目的顺序把硬件怎么接、固件怎么写、标定怎么做、控制怎么闭环以及我最常遇到的坑一次讲透。想把这套方案用在空调箱控制器、变频风机、冷链监控或者嵌入式设备过热保护上的朋友可以直接照着走。1. 为什么HVAC系统要分开测“本地温度”和“远程温度”1.1 两种温度各有各的用途我先说一个很多人一开始没想明白的点HVAC 系统里的“本地温度”和“远程温度”根本就是两个用途完全不同的信号不能混着用。本地温度指的是传感器芯片所在地——也就是主控板所在位置的温度。嵌入式控制板的发热大户是 MCU、功率管、继电器和电源模块这些器件长期工作在高温下寿命和可靠性都会明显下降。所以本地温度通常承担两个角色一是给主控板做自保护比如温度超过 85°C 就降频、降低 PWM 占空比、甚至直接停机二是给风机调速提供一个参考让机柜内部保持合理的散热风量。远程温度则是真正代表“被控对象”的温度。做法是在传感器芯片外部接一颗二极管连接的小三极管把这个三极管通过双绞线送到几米甚至十几米外的风管、表冷器翅片或者室外阴凉处。因为远端只有一颗无源三极管没有芯片、没有电源、没有复杂电路所以环境再恶劣也不怕高温、高湿、灰尘、冷凝水都不会直接打在控制器上。很多人以为远程测温只是“把探头放远一点”其实它真正的价值是让所有有源电路都留在安全的控制柜里而把最脆弱、最需要靠近被控对象的探头做成廉价可更换的无源器件。这样维护成本低可靠性也高。1.2 单芯片双通道比堆传感器划算得多如果你只想测一个点随便一颗数字温度传感器都能搞定。但 HVAC 系统通常至少需要 3~4 个温度点这时方案选择就很关键。最笨的办法是每个测温点放一颗数字温度传感器比如常见的贴片温度芯片每颗都要占 I2C 地址、要配去耦电容、要占 PCB 面积而且每个点都要从控制板拉一条电源线过去。远端一旦进水短路可能把整条 I2C 总线都拖死。用 PJ85718DM 这类本地远程双通道芯片就简单得多主控板上只放一颗芯片需要测的远端位置各接一个三极管。价格上相当于用一颗芯片的钱换掉多个独立传感器PCB 面积也省下不少。我做过一个空调箱控制器原来板子上挤了 4 颗温度传感器改用双通道方案后板面清爽了很多BOM 成本也降了一截。这里我用一张表总结两种方案的差异方便你选型时直接参考方案每点成本PCB 占用远端失效风险每点放独立数字温度传感器高芯片电容布线大高有源电路暴露在远端本地远程双通道芯片低芯片三极管小低远端只有无源三极管1.3 远程测温的原理为什么不是热敏电阻聊到这里你得先搞清楚远程温度到底是怎么测出来的否则后面接线、标定很容易瞎猜。PJ85718DM 这类芯片的远程测温通道测量对象根本不是热敏电阻而是“二极管连接”的三极管 PN 结。芯片内部会先后给这个 PN 结注入两档不同的电流 I1 和 I2然后分别测出两次的管压降 V1 和 V2。根据半导体物理V1 和 V2 的差值和温度有近似理想的线性关系ΔV V1 - V2 (k·T/q) · ln(I1/I2)这里 k 是玻尔兹曼常数q 是电子电荷ln(I1/I2) 是两档电流比的自然对数。这个式子里绝对管压降、反向饱和电流这些受工艺影响很大的项都被消掉了所以用 ΔV 推算温度精度可以做到很高。这也解释了为什么远端要专门用“把基极和集电极短接的三极管”而不是随便拿个热敏电阻串上去。热敏电阻是阻值随温度变化工作原理完全不同芯片根本不认。我在现场见过好几次有人把热敏电阻接到远程通道上读数乱跳还以为芯片坏了。2. 硬件连接关键点PJ85718DM与PIC18F86J16的引脚级对接2.1 供电与电平3.3V 系统就是省事PJ85718DM 这类数字测温芯片通常的工作电压是 3V~3.6VPIC18F86J16 的 J 系列同样是 3.3V 供电的主控两个器件逻辑电平天然匹配。这意味着 SCL、SDA、ALERT 这些信号线可以直接连不需要任何电平转换芯片。我做项目时给传感器供电用的是和 MCU 同一路 3.3V但传感器电源脚旁边一定放两颗电容一颗 100nF 的陶瓷电容负责高频去耦一颗 1uF 的钽电容或者多层陶瓷电容负责中低频稳定。电容位置尽量贴着 VDD 引脚不然高速 I2C 通信时电源噪声容易串进测量结果。有一点必须提醒J 系列 PIC18F86J16 不是 5V 器件设计时千万别顺手给它供 5V也不要让 5V 信号直接怼进它的引脚。如果你的系统里还有其他 5V 器件务必检查信号线上有没有电平冲突。2.2 引脚对接表PIC18F86J16 有多个 MSSP 串行模块可用我这里用 MSSP2 举例。具体用哪一组引脚以你手里的 TQFP 封装引脚图为准但接法思路是一样的。信号PJ85718DMPIC18F86J16说明VDDVDD3.3V 电源100nF 1uF 去耦GNDGNDGND单点接地避免地环路SCLSCLMSSP2 SCL 引脚接 4.7kΩ 上拉到 3.3VSDASDAMSSP2 SDA 引脚接 4.7kΩ 上拉到 3.3VA0/A1/A2地址选择GND 或 VDD决定 I2C 从机地址ALERT告警输出RB0外部中断开漏输出需外部上拉D / D-远程二极管正负不接 MCU双绞线接远端三极管上拉电阻的取值我一般用 4.7kΩI2C 速率跑 100kHz 或 400kHz 都稳定。如果总线上挂了多颗器件上拉电阻可能要调到 2.2kΩ具体看总线电容最好用示波器看过波形再定。2.3 远程二极管的接线规范别把它当普通信号线远程测温看起来只是接一个小三极管但这里恰恰是故障率最高的地方。接法上有几条硬规矩第一三极管必须是“二极管连接”NPN 管的基极和集电极短接在一起短接点接到 D发射极接到 D-。接反了或者漏接了读数会偏得离谱。第二D 和 D- 必须用双绞线或者紧贴在一起的平行走线不能一根线走很远、另一根线绕个大圈回来。因为 ΔV 测量对毫伏级噪声敏感两根线如果不对称耦合进来的差模噪声会直接叠加到信号上。第三远端三极管旁边并联一颗 100pF~1nF 的小电容滤掉高频干扰。风机变频器、压缩机启动瞬间都是很强的干扰源不加这颗电容读取值时不时会跳一下。第四测温距离超过 3 米时建议用双绞屏蔽线屏蔽层在控制板侧单端接地千万不要两端都接地。两端接地容易形成地环路反而把噪声引进来。3. 固件流程拆解I2C读取、数值滤波与Modbus上报3.1 初始化与寄存器布局固件侧的第一步是把 PIC18F86J16 的 MSSP 配置成 I2C 主模式。PJ85718DM 的默认 I2C 从机地址常见是 0x487 位地址实际地址由 A0/A1/A2 引脚的电平决定。我习惯在初始化代码里把这个地址定义成宏方便以后一板多机时改。这类双通道测温芯片的寄存器布局大同小异我按手头器件的典型布局做个参考表具体地址以你手里的数据手册为准寄存器功能说明0x00本地温度寄存器12 位补码高位在前0x01远程温度高字节补码0x10远程温度低字节低 4 位有效0x02状态寄存器含远程开路/短路标志0x03配置寄存器转换模式、分辨率0x04/0x05温度偏移寄存器校正值0.0625°C/LSB初始化时我一般把分辨率设成 12 位连续转换模式。轮询模式在电池供电的低功耗设备里有用但在 HVAC 控制器这种 220V 供电环境里连续转换反而省心不用担心漏读报警。3.2 读取与换算一个完整的 I2C 读函数下面这段是从传感器读取 16 位温度寄存器原始值的核心代码。I2C 底层的 Start、Stop、写字节、读字节函数用 PIC 的 MSSP 外设实现这里不展开直接看读取逻辑#define PJ85718DM_ADDR 0x48 // 7-bit地址 uint16_t temp_reg_read(uint8_t reg) { uint16_t val; i2c_start(); i2c_write((PJ85718DM_ADDR 1) | 0); // 写方向 i2c_write(reg); // 目标寄存器 i2c_start(); // repeated start i2c_write((PJ85718DM_ADDR 1) | 1); // 读方向 val (uint16_t)i2c_read(ACK) 8; // 高字节 val | (uint16_t)i2c_read(NACK); // 低字节 i2c_stop(); return val; }拿到原始值之后要换算成摄氏度。以 12 位分辨率的常见格式为例温度数据存放在 16 位寄存器的高 12 位每个 LSB 代表 0.0625°C。换算时先把高 4 位做符号扩展再整体右移 4 位int16_t raw (int16_t)temp_reg_read(0x00); // 本地温度原始值 int16_t t12 raw 4; // 符号扩展后的12位温度码 float temp_c (float)t12 * 0.0625f; // 转换成摄氏度这里最容易犯的错是忘记符号扩展。温度低于 0°C 时寄存器是补码表示直接拿 unsigned 转 float 会得到几百度的离谱值。所以读取时一定要用 int16_t并且先右移再做乘法。3.3 滤波滑动平均和报警值要分开处理HVAC 现场的温度信号不会像实验室里那么干净风机启停、压缩机吸合都会在读数上砸出毛刺。我建议对用于控制闭环的滤波值做滑动平均窗口一般取 8~16 次即可太长会让系统反应变慢太短又压不住毛刺。#define FILTER_WINDOW 8 static int16_t buf[FILTER_WINDOW]; static uint8_t idx; static int32_t sum; int16_t moving_average(int16_t sample) { sum - buf[idx]; buf[idx] sample; sum sample; idx (idx 1) % FILTER_WINDOW; return (int16_t)(sum / FILTER_WINDOW); }一个关键经验报警判断不要用滤波后的值要用原始值或者 2~3 次的快速均值。因为真正的过热、传感器开路是突发的滑动平均会把这种突变拉平导致报警延迟。我习惯温度显示和控制用滤波值报警和故障判断走另一条快速通道。3.4 Modbus RTU 从机实现要点HVAC 设备几乎都要把数据汇到上位机或者楼宇自控系统PIC18F86J16 的 UART 外设配一颗常规的 RS485 半双工收发器跑 Modbus RTU 从机协议就够了。我的寄存器规划是40001 存本地温度单位 0.01°C40002 存远程温度40003 存状态字40004 存设定点40005 存滞回参数。Modbus RTU 里最容易出问题的就是 CRC16。下面是标准的 Modbus CRC16 实现查表法和逐位法都可以我贴一个逐位版本逻辑清晰也好移植uint16_t modbus_crc16(uint8_t *data, uint8_t len) { uint16_t crc 0xFFFF; while (len--) { crc ^ *data; for (uint8_t i 0; i 8; i) { crc (crc 1) ? (crc 1) ^ 0xA001 : (crc 1); } } return crc; // 低字节在前发送 }另一个高频坑是 RS485 收发切换。发送完后必须等发送移位寄存器真正送出最后一个字节再把方向脚拉回接收态。我见过太多人发完立刻切方向最后一个字节丢半个上位机 CRC 永远报错。PIC 的 EUSART 模块有发送完成标志位发送前设置好发送后轮询这个标志再切方向问题就没了。3.5 报警脚怎么用PJ85718DM 的 ALERT 脚是开漏输出平时被外部上拉拉高温度越限时拉低。我把它接到 PIC18F86J16 的 RB0外部中断引脚配下降沿触发。中断服务程序里只做一件事置一个全局报警标志。真正的 I2C 读取、状态解析全部放主循环里做。原因很简单I2C 时序对中断打断很敏感如果在 ISR 里边发边收中途被更高优先级的中断打断总线时序就乱了轻则读到错值重则整条总线卡死。4. 精度与校准远端二极管测温的偏差来源与补偿方案4.1 影响精度的五个因素远端二极管测温的理论精度很高但那是理想情况。落到实际 PCB 和现场环境偏差主要来自五个地方引线电阻。PJ85718DM 给二极管注入的是电流电流流过 D、D- 之间的串联电阻会产生附加压降芯片把这个压降也算进 ΔV 里导致读数偏高。线越长、越细这个偏差越大我实测 10 米 0.2mm² 导线大约能带来 1~2°C 的正偏差。三极管的理想因子。ΔV 公式里的 ln(I1/I2) 就是两档电流比的对数所以理想因子 n 越接近 1测温越接近理想。不同厂家、不同批次的小三极管 n 值有细微差别芯片通常有校正寄存器按实际用管型号去设。噪声。远端引线就是一根天线变频器、继电器、开关电源的高频噪声如果耦合进 ΔV读数就会像心电图一样抖。应对办法就是前面说的双绞线加小电容。漏电流。高温高湿环境下 PCB 表面和线缆绝缘层会有微量漏电流相当于给二极管并联了一个电阻影响低频段的测量。所以远程通道周边走线要尽量干净线缆选绝缘好的材料。自热。传感器自身会消耗一点功率如果把它贴着发热器件放本地温度会明显偏高。远端三极管因为工作在微安级电流自热可以忽略本地通道才需要留心。4.2 校准流程冰水、恒温箱、两点法我一般不做单点校准而是做两点线性校准。流程是这样的第一步把远端三极管和一根高精度参考温度计绑在一起放进冰水混合物里等读数稳定后记录显示值和参考值的偏差。这一步给出 0°C 附近的偏差点。第二步把同样的一组探头放进恒温箱设到 85°C没有恒温箱就用沸水替代但要注意当地气压对沸点的影响再记一个偏差点。第三步用这两个点算出线性补偿系数把补偿值写进芯片的偏移寄存器或者直接存在 PIC 的内部 EEPROM 里。注意补偿值对本地温度和远程温度是分开设置的别搞混。第四步回到 25°C 附近复测确认补偿后的误差落在可接受范围。产线上如果要做批量标定就在这个流程前面加一个通电老化步骤让板子稳定半小时再测结果更可靠。4.3 现场标定的一个细节还有一件事经常被忽略校准点的环境必须和实际使用环境“热接触”一致。比如远程三极管装在风管里测回风温度校准的时候就要让它和参考温度计处在同一个热质量里不能一个贴风口、一个拿在手里。另外我在项目里发现出厂时校准得再准到了现场还是会因为安装位置变化产生偏差。所以固件里最好留一个远程偏移量寄存器或者 Modbus 可写的补偿寄存器让现场调试的人微调不用重新编译烧录。这个设计虽然只多了几十行代码但售后体验完全不一样。5. HVAC闭环控制落地从温度值到风机与压缩机的动作5.1 传感器位置怎么选每个温度点都对应一个动作HVAC 控制不是把温度读出来显示一下就完事关键是把每个温度点对应到明确的控制动作上。我按位置和用途整理了一张表是我做空调箱控制器时的分法测温点传感器通道控制用途主控板内部本地设备过热保护、内部风机调速回风管远程主控闭环决定风机/压缩机启停送风管远程盘管能力监测、风量异常判断表冷器表面远程防冻保护、防止盘管结冰回风温度是空调系统最常用来做主控对象的位置因为它代表整个空间的平均温度。送风温度则反映盘管当前的冷却或加热能力两个值配合可以判断系统是正常运行还是已经“力不从心”。5.2 滞回控制避免继电器和压缩机频繁启停最常见的控制逻辑就是滞回hysteresis控制。设定一个目标温度比如 22°C然后用回风温度做反馈控制风机或者压缩机。没有滞回的话温度在设定点附近微幅波动就会让继电器不停地吸合断开继电器寿命和电源稳定性都会出问题。滞回区间一般取 ±0.5°C 到 ±1°C。#define SET_POINT 22.0f #define HYST 1.0f static uint8_t fan_on 0; void hvac_control_tick(float return_temp) { if (!fan_on return_temp SET_POINT HYST) fan_on 1; // 升温越过上限启动 else if (fan_on return_temp SET_POINT - HYST) fan_on 0; // 降温越过下限停止 }这套逻辑看起来简单但现场调试时有个细节滞回区间不能设得太小。很多人觉得 ±0.5°C 已经不小了但实际 HVAC 系统热惯性大温度波动也大区间太小照样会频繁动作。我给自己的经验值是回风控温用 ±1°C送风保护用 ±0.5°C既兼顾舒适度又保护设备。5.3 安全联动防冻和过热是两套独立逻辑HVAC 的远程温度里防冻保护优先级最高。表冷器盘管在冬季如果水温过低或者风量不足盘管里的水可能结冰冻裂换热器是实打实的设备事故。所以盘管表面温度一旦低于某个阈值不管设定点是什么系统都必须立刻进入防冻模式关风机、开热水阀或者切换再循环模式。本地温度则承担反向保护。我写过这样一段逻辑本地温度超过 85°C 时强制把输出 PWM 降到 50%超过 95°C 时直接停机并锁存故障。锁存的目的是防止设备在故障状态下反复重启必须等人工复位或者温度降下来之后才能恢复。这个锁存标志我存在 PIC 内部 EEPROM 里断电重启也不会丢失。另外远程通道的开路/短路检测一定要做。三极管引线断掉或者短路时温度读数会跳到一个极端值如果不识别这个状态直接拿去控制后果很严重。芯片的状态寄存器一般会置位开路/短路标志位固件里读到这个标志就把对应通道的测量值标记为无效控制逻辑走安全默认值同时上报故障码。6. 实测数据与常见故障排查记录6.1 一组有代表性的实测数据我在某个模拟项目里搭了一套测试环境用 5 米和 15 米两种双绞线长度做了对比记录校准前后的远程温度读数偏差。环境温度约 28°C三极管选普通小信号 NPN加 100pF 滤波电容。线长校准前偏差校准后偏差风机启动瞬间波动1 米0.15°C±0.1°C±0.05°C5 米0.5°C±0.2°C±0.15°C15 米1.2°C±0.3°C±0.4°C加电容前从数据能直接看出来引线电阻带来的偏差是随长度线性增加的用两点校准可以压下去。但校准抵消不掉噪声噪声只能靠布线、屏蔽和滤波来解决。所以我的结论一向是校准解决系统性偏差布线解决随机性波动两者不能互相替代。6.2 高频踩坑记录现象、根因、处理做这类项目我把遇到过的故障整理成了一份排查清单每次现场出问题就按这张表查效率很高现象根因处理方式I2C 读回全是 0xFFSCL/SDA 没有上拉电阻加上 4.7kΩ 上拉到 3.3V远程温度读数乱跳三极管接反或 D/D- 挨着 PWM 线检查二极管连接方向线束远离强干扰源温度缓慢漂高传感器紧贴电源模块自热调整布局芯片远离发热源Modbus 偶发 CRC 错误收发方向切换过早等发送完成标志位再切换 DEALERT 报警不触发开漏输出缺上拉电阻给 ALERT 加 10kΩ 上拉低温读数异常偏高PCB 漏电流大清洗板面检查绝缘处理这里面最让我记忆深刻的是第一个坑。第一次打板回来I2C 怎么读都是 0xFF我查了半天以为是芯片焊坏了后来发现是原理图里漏画了上拉电阻。I2C 总线的上拉不是可选项是必须项这点新手特别容易漏。6.3 我的几点经验做了几轮这类项目之后我最大的感触是测温系统的难点从来不在“读出温度”这一步而在温度读数背后那一整条链路——硬件布局、机电干扰、标定补偿、故障识别、控制策略每个环节都可能让数据失真。PJ85718DM 配 PIC18F86J16 这套组合的价值就是用一个成熟的双通道测量方案把前面最难的模拟部分简化掉让开发者把精力放在固件逻辑和系统可靠性上。最后分享两个我自己的习惯第一版 PCB 上就把校准点和测试点都留出来不要等整机装好了再想办法另外一个通道不够用时可以通过 A0/A1/A2 地址线在总线上挂多颗 PJ85718DM每颗都能同时提供本地和远程温度扩展成多路测温系统非常顺手。这套路数做冷链监控、配电柜温度监测、甚至小型机房环境监控都是一样的打法。