2026/10/22 6:41:49

基于PJ85718DM与PIC18F55K42的本地远程温度采集方案详解

基于PJ85718DM与PIC18F55K42的本地远程温度采集方案详解 每年入夏总有一批项目卡在温度上嵌入式设备机箱里温度起来了代码里却不知道哪个点是热源暖通项目现场风管两头温差明显控制器却只看一个测点。近端远程都要同时掌握我最后把方案落在 PJ85718DM 与 PIC18F55K42 这套组合上。PJ85718DM 是一颗带本地测温通道、同时支持一路远程温度探头的数字温度传感器PIC18F55K42 作为主控通过 I2C 总线把两路温度读回再换算成可用的工程温度。这篇文章把我从选型、硬件连线、软件读取到现场调试踩坑的完整过程写出来适合正在做嵌入式散热监测、HVAC 送风回风温差控制或者类似远程测温需求的工程师参考。1. 一冷一热两种工况为什么最终选定双通道测温方案1.1 嵌入式测温与HVAC测温差在哪做测温方案之前先得想明白一件事嵌入式设备和 HVAC 现场对温度的要求根本不是同一个维度。嵌入式关心的是板上局部过热传感器离热源可能就是几厘米采样周期可以做到每秒几次甚至几十次追求的是快速响应和低功耗HVAC 关心的是风管、房间、冷却塔这些大空间里的温度趋势探头往往拉出去好几米甚至十几米采样周期一秒一次就已经非常充裕反而更在意长线缆带来的干扰和温度滞后。我把两种场景的核心差异列个表方便后面所有设计决策对号入座对比项嵌入式设备内测温HVAC现场测温典型测温点机箱内、PCB附近、功率器件风管送风/回风、房间、室外探头距离厘米级数米到十几米采样频率需求1Hz~10Hz0.2Hz~1Hz主要干扰电源纹波、自热电机启停、长线耦合、凝露精度侧重短时过温保护温差趋势与稳定性本地与远程温度在这两类项目里有个共同理解本地温度指传感器所在电路板或设备附近的温度远程温度指通过探头拉到被测点的温度。很多控制器真正想知道的不是绝对温度有多准而是看两个温度的差值——嵌入式里是机箱内部和外部环境的温差HVAC 里是送风和回风的温差。所以测两路不是奢侈而是控制逻辑的基本盘。1.2 PJ85718DM 的本地加远程测温工作方式PJ85718DM 最吸引我的地方是它一颗芯片同时处理本地和远程两路温度不需要我再外挂一颗模拟前端。本地通道内部用带隙基准电路感知芯片自身温度这个原理和多数数字温度传感器一样核心是把 PTAT与绝对温度成正比电压转换成数字量。芯片自己知道自身体温这就够了。远程通道则是通过激励外部 PN 结来测量远端温度。具体工作时芯片给探头的二极管或三极管 PN 结施加两个不同大小的电流通过测量两次正向压降的差值来反推温度。为什么不用直接测 Vbe 绝对电压的办法因为单个 PN 结的绝对压降受工艺、型号、线阻影响很大离散性太严重而 ΔVbe 与温度的关系几乎只取决于玻尔兹曼常数和电子电荷线性度和一致性都好很多所以工业测温芯片普遍走这条路。如果你的现场条件不适合拉 PN 结探头也有更朴素的用法利用芯片的地址引脚在同一根 I2C 总线上挂两颗 PJ85718DM一颗放本地、一颗放远程。我实际的项目里两种方式都用过双通道方案适合机箱内部加一个远端温度监测点双芯片方案适合多点分布式测温。标题里说的本地与远程温度用双通道模式就能覆盖。1.3 PIC18F55K42 在此承担的角色与选型理由PIC18F55K42 是 8 位单片机我在这套方案里主要用到它的 I2C 主模式、定时器中断、看门狗和低功耗模式。它是一个 K42 系列器件自带可配置逻辑单元、带计算功能的 ADC 等外设但对于我们这个纯数字温度读取场景最实用的其实是稳定的内部振荡器和成熟的 MSSP 串口模块。为什么用 8 位机而不是上 32 位成本、功耗、启动时间都能省一点而且温度监测根本不需要跑复杂算法读两个寄存器、做滑动平均、做阈值判断8 位机的资源绰绰有余。为什么又不用纯模拟方案温度传感器直接输出数字信号长线传输不受模拟小信号衰减的影响现场校准和调试都更简单。PIC18F55K42 在我这边的定位就是一个可靠的温度数据搬运工定时唤醒读温度处理数据输出控制。2. 从传感器到单片机接口电路里不能省的部分2.1 I2C上拉、供电与地址位的处理PJ85718DM 和单片机的物理连接看起来简单就四根线VDD、GND、SDA、SCL最多再加一根 ALERT 报警输出。但 I2C 是开漏结构SDA 和 SCL 必须有上拉电阻才能输出高电平这个电阻值的选择直接影响整条总线的稳定性。我在 3.3V 系统里通常从 4.7kΩ 上拉起步如果总线上挂的设备多、或者线缆超过半米就换成 2.2kΩ。上拉电阻太大上升沿会变缓超过规范要求的上升时间后设备可能把高电平误判成低电平上拉电阻太小低电平灌电流变大又会增加功耗和干扰。400kHz 速率下总线电容一般控制在 400pF 以内普通跳线超过 20cm 就得留意了。供电策略也很关键。如果 MCU 是 3.3V、传感器也工作在 3.3V那 SDA/SCL 直接上拉到 3.3V 就行。如果传感器只支持 5V而 MCU 是 3.3V就不能简单地把上拉电阻接到 5V否则高电平会直接灌进 MCU 引脚时间长了必然损坏。稳妥做法是传感器和 MCU 统一用 3.3V 供电或者加一颗双向电平转换芯片高压侧上拉到 5V、低压侧上拉到 3.3V。地址位是另一个经常翻车的地方。PJ85718DM 的 A0/A1有些型号是 A2/A1/A0引脚可以硬接 GND 或 VDD 来选择总线地址挂多颗传感器时靠这个区分。我习惯在原理图上把地址引脚附近的走线画明显并且直接标注电平避免调试时反复猜。2.2 远程探头线缆的屏蔽、保护与补偿远程探头是这套方案里最脆弱的一环。HVAC 现场探头常常要穿到风管里、拉到天花板上面线缆一长什么怪问题都可能出现。远程 PN 结探头不要用普通杜邦线要选屏蔽双绞线屏蔽层在单片机侧单端接地。双绞是为了抵抗差模磁场的耦合屏蔽层单端接地是防止地环路变成天线。线缆本身的电阻不能忽略。远程探头的线缆越长串联电阻越大测量结果会出现单调偏移。遇到这个问题先别急着改软件用万用表量一下线缆两端的实际电阻对照数据手册给出的补偿曲线或者经验系数做修正。更隐蔽的是接插件氧化端子压接不紧、镀层不好接触电阻从几十毫欧漂到几欧读数就会跟着跳。所以现场探头连接处我坚持用压接端子接头位置喷涂一层保护剂防止凝露腐蚀。如果传感器接口附近有雷击浪涌风险比如室外风管温度探头一定在 PCB 上加 TVS 管。HVAC 现场很多 I2C 芯片坏掉不是单片机的问题是浪涌从长线缆直接灌进传感器造成的。2.3 电源、地线和板级布局的注意温度传感器本身是低功耗器件但它的读数很诚实PCB 上的任何发热都会通过铜箔传导过来。想测空气温度传感器下方就不要铺大铜皮让它和空气接触想测板温反而要通过铜皮保证热耦合。很多样机测出来温度偏高不是传感器坏了是底下铺了一块电源铜皮。地线处理上信号地和风机、继电器、加热器的大电流地要分开走最后单点汇合。电机启动瞬间有几安培的电流突变哪怕是 0.1Ω 的地线阻抗也会产生 0.5V 以上的地弹直接落在传感器和单片机之间的通信基准上。这个问题在实验室样机上几乎看不出来一到现场装进机组就原形毕露。3. 用代码配置工具生成工程跑通本地与远程温度读取3.1 时钟、I2C主模式与采样节拍配置PIC18F55K42 支持内部振荡器工作温度监测这个场景对时间精度要求不高我直接用内部高频振荡器分频到 32MHz省掉外部晶振。然后在开发环境的代码配置工具MCC里勾选 MSSP 模块配置成 I2C 主模式速率选 400kHz。如果探头线缆超过一米我会主动降到 100kHz牺牲一点速度换稳定。有一个细节很容易坑人MCC 生成代码时会默认分配引脚但默认分配的不一定是你实际板子上接线的引脚。生成完工程后第一件事是打开引脚分配页面核对 SDA 和 SCL 到底映射到哪两个引脚再对照原理图确认。我见过不止一个朋友拿着默认生成的代码去调查了半天才发现传感器根本没接到 MCU 默认的 I2C 引脚上。采样节拍用定时器来做不要在主循环里写软件延时。我习惯用 Timer0 配置成 1ms 中断在中断里累加计数到 1000 次就置一个1秒到的标志主循环里读到标志再去读温度。这样采样周期稳定也不会因为某次 I2C 通信卡顿影响整个系统节拍。3.2 传感器寄存器的读写思路PJ85718DM 这类数字温度传感器的寄存器操作思路大同小异一般有指针寄存器、配置寄存器、本地温度寄存器、远程温度寄存器、报警上限和迟滞寄存器。读温度前先要把指针指向温度寄存器地址然后连续读两个字节。写配置时先写指针寄存器再写配置字节。具体 I2C 事务流程是启动信号 → 发送器件地址加写位 → 发送寄存器指针 → 重复启动 → 发送器件地址加读位 → 读高字节 → 读低字节 → 发送非应答 → 停止信号。读两个字节时第一个字节要应答第二个字节要让传感器知道后面没有数据了所以发 NACK。很多人在这里搞反两个字节都发 ACK传感器就会一直输出下一位导致数据错位。配置寄存器里最关键的是转换模式选择。连续转换模式适合调试和实时监控传感器每秒钟都在转换单次转换模式适合低功耗场景MCU 需要的时候才触发一次转换转换完成后读取读完让传感器继续休眠。3.3 本地与远程温度读取的完整代码流程我给出一个非常简化的流程用来表达核心思路。实际工程里要把错误处理和超时判断加进去尤其是 I2C 总线 NACK 之后的重试逻辑。#define SENSOR_ADDR 0x48 // 根据A0/A1实际配置调整 #define REG_LOCAL 0x00 // 本地温度寄存器 #define REG_REMOTE 0x01 // 远程温度寄存器 void sensor_write_byte(uint8_t reg, uint8_t val) { i2c_start(); i2c_write((SENSOR_ADDR 1) | 0); // 写地址 i2c_write(reg); // 指针 i2c_write(val); // 数据 i2c_stop(); } void sensor_read_word(uint8_t reg, int16_t *raw) { uint8_t hi, lo; i2c_start(); i2c_write((SENSOR_ADDR 1) | 0); i2c_write(reg); i2c_restart(); i2c_write((SENSOR_ADDR 1) | 1); // 读地址 hi i2c_read(1); // ACK lo i2c_read(0); // NACK i2c_stop(); *raw (int16_t)((hi 8) | lo); } int main(void) { // 初始化时钟、I2C、定时器等 // 配置传感器12位分辨率连续转换 sensor_write_byte(0x01, 0x60); while (1) { if (sample_flag) { sample_flag 0; int16_t local_raw, remote_raw; sensor_read_word(REG_LOCAL, local_raw); sensor_read_word(REG_REMOTE, remote_raw); // 交给换算和滤波模块处理 } } }读取期间要小心中断打断 I2C 事务。在 I2C 的 start/stop 序列中间如果单片机被一个长中断抢走几十微秒总线时序就乱了。我把 I2C 读取放在主循环里执行定时器中断只负责置标志不让中断函数里去直接动 I2C 总线。4. 把原始寄存器值变成可靠温度值换算、滤波与报警4.1 补码换算与分辨率处理PJ85718DM 这类 12 位精度温度传感器温度数据在寄存器里通常占高 12 位低 4 位是无效位。每个 LSB 对应 0.0625℃这个值来自 1/16℃ 的分辨率也就是 12 位温度数据里每 16 个计数对应 1℃。换算时先把原始 16 位数据右移 4 位再按有符号数做符号扩展最后乘 0.0625。int16_t raw; // 从传感器读回的原始值 int16_t value; // 右移后带符号的整数 float temp_c; // 摄氏度 value (int16_t)(raw 4); temp_c (float)value * 0.0625f;下面几个典型值可以自检代码有没有写对寄存器原始值(16bit)右移4位后的有符号整数对应温度(°C)0x0000000x00A0100.6250x0A00160100x19A041025.6250xFF00-16-1负温度一定要小心符号扩展。如果直接把 0xFF00 当成无符号数右移会得到 0x0FF0也就是 255换算出来变成 15.9375℃完全错了。用 int16_t 类型承载原始数据再右移编译器会保留符号位才能得到正确的 -1℃。4.2 滑动平均和阈值迟滞怎么选转换出来的温度不要直接用原始数据会有随机噪声尤其远程通道受线缆和接插件影响更大。我一般加一个滑动平均保留最近 N 个样本求平均。嵌入式场景 N 取 8 到 16既有平滑效果又不会让响应慢到没法用HVAC 场景我常常取 60 个样本相当于一分钟平均因为暖通控制本来就不需要反应那么快反而需要抑制风门、风机短暂动作带来的温度尖峰。#define WINDOW 8 static float samples[WINDOW] {0}; static uint8_t idx 0; float avg 0.0f; samples[idx] temp_c; idx (idx 1) % WINDOW; for (uint8_t i 0; i WINDOW; i) { avg samples[i]; } avg / WINDOW;阈值报警一定要加迟滞。比如设定超过 50℃ 报警到 50℃ 触发但回落时不要到 50℃ 以下就立刻取消那样风机关了又开继电器会在一两度区间里反复跳动。我通常设置 0.5℃ 到 1℃ 的迟滞窗口超过 50℃ 报警低于 49.5℃ 才复位。嵌入式散热风扇的迟滞甚至可以给到 2~3℃避免频繁启停。4.3 温差计算在 HVAC 和嵌入式里的落地有了本地和远程两路温度最有价值的其实是差值。HVAC 系统里送风温度和回风温度的差值能直接反映系统换热效果制冷模式下回风温度比送风温度高说明房间里的热量正在被带走差值太小可能是风量不足或者滤网堵了。嵌入式设备里机箱内部温度和外部环境温度的差值如果持续变大说明散热风道出了问题。这个温差不一定要在 MCU 里算得多么复杂做两个标志位就够local_overlimit、remote_overlimit然后在控制逻辑里组合判断。PIC18F55K42 的 CLC 模块甚至可以把比较结果做成硬件自动输出不需要 CPU 干预适合做硬件风扇联动不过初学者不要一上来就搞这些先用软件标志位逻辑更透明出了毛病也好查。5. 现场调试踩过的三个坑以及完整排查链路5.1 总线读回全FF或总是NACK第一个坑上电后读任何寄存器返回值不是全 FF 就是 I2C 总线在地址阶段就收到 NACK。遇到这个问题我的排查链路非常固定。先用示波器看 SDA 和 SCL 的波形如果 START 之后地址字节发出去第九个时钟上 SDA 没有被拉低说明传感器没有应答。第一步查器件地址看 A0/A1 引脚实际电平是否和代码一致。我踩过一次原理图上 A1 接了 VCC结果代码里还按两个地址位都接地的 0x48 去读一直 NACK。改成 0x4A 之后立刻通了。第二步查 SDA 高电平。用示波器看 SDA 空闲时是否被拉到接近 VDD如果只有零点几伏大概率上拉电阻没焊或者短路了。第三步查供电。传感器 VDD 有没有 3.3V有些现场的辅助供电线压接不牢一上电有电一接负载掉压也会让传感器工作不稳定。最后还有一个隐蔽问题5V 传感器配 3.3V 单片机上拉电阻接在 5V 上MCU 输入引脚长期承受 5V 高电平虽然没烧但内部保护二极管漏电会把 I2C 电平拉得很怪。排查到最后一步我一般会强制把速率降到 100kHz 再试一次排除总线电容太大导致边沿过缓的影响。5.2 远程读数跳变或单调偏低第二个坑本地温度很稳远程温度一会儿跳 ±1℃一会儿整体偏低两度。这种问题最容易让人怀疑传感器坏了但大多数时候坏的是物理连接。我的排查顺序是先关掉软件滤波看原始值是否真跳。然后万用表量远程探头连接端子到 PN 结之间的电阻如果阻值在几十欧以上大概率是接插端子氧化或者压接不紧。把线缆换成短线把探头直接挪到传感器旁边对比如果读数接近本地温度说明原来的长线缆引入的电阻或者耦合噪声是主因。还有一种情况探头虽然没坏但激励电流在细长线上造成额外压降导致测得温度偏低这是线阻补偿的问题。查清楚线缆电阻后在软件里做固定偏移修正或者在硬件上加大线径。远程探头最忌讳用杜邦线怼着用当时测没事三个月后端子氧化读数漂到你怀疑人生。5.3 风机一启动温度读数就漂第三个坑是 HVAC 现场特有的风机或者变频器一启动远程温度瞬间跳 2~3℃严重时 I2C 直接乱码过一会儿自己恢复。我开始以为是软件问题加滤波、加延时都没用后来用示波器把探棒夹在 SDA 和 SCL 上盯着风机启动瞬间看线缆上会感应出一串毛刺。排除链路是这样的先把远程探头线从原路径拉出来悬空或者临时穿一根金属软管看读数是否稳定。如果稳定说明是空间辐射耦合进长线如果还不稳定查电源地线看电机启动电流是不是在公共地上砸出电压尖峰导致传感器电源抖动。这两种路径的解决办法不一样前者靠屏蔽后者靠分离接地和电源滤波。最后我用的组合方案是远程线全程套金属软管屏蔽层单端接地传感器电源入口加磁珠加 10μF 和 100nF 电容滤波I2C 线上串 33Ω 电阻软件里风机启动后延迟 200ms 再采一次连续读三次取中值而不是平均值。故障彻底消失。这类问题在样机阶段根本复现不出来所以做 HVAC 项目的朋友一定要在立项时就按长线、强干扰场景预留硬件措施。6. 低功耗采样与总线异常恢复的收尾建议6.1 单次转换加定时唤醒把功耗降下来如果这套系统是电池供电的嵌入式设备传感器长期连续转换就是一种浪费。把配置寄存器改成单次转换模式MCU 在定时器唤醒后给传感器发一条触发转换命令等待几十毫秒转换完成读取结果然后让传感器进入关断状态MCU 也继续睡。我做过一个 30 秒采样一次的设备电池续航比连续模式延长了一个量级。单片机这边也要配合。PIC18F55K42 在等待转换完成期间可以直接进 SLEEP用定时器唤醒。需要注意的是唤醒后 I2C 模块可能处于不确定状态所以我把 I2C 重新初始化放在每次唤醒后执行而不是依赖上一次的状态。这样稍微花几微秒但换来的是稳定。6.2 总线卡死的恢复和看门狗配合I2C 总线卡死是个经典问题。最常见的原因是单片机在 I2C 事务中途复位SCL 恰好停在低电平那么总线就被这个单片机自己锁住了。看门狗复位只能让程序重来但如果 SCL 还是低重新初始化 I2C 也没用必须手动把总线解放出来。恢复办法是把 SCL 临时配置成普通 GPIO 输出手动产生 9 个时钟脉冲让从设备释放总线然后再重新初始化 I2Cvoid i2c_bus_recover(void) { SCL_TRIS 0; // 设为输出 SCL_LAT 0; for (int i 0; i 9; i) { SCL_LAT 0; __delay_us(5); SCL_LAT 1; __delay_us(5); } // 重新初始化I2C模块 }看门狗的超时时间一定要大于单次 I2C 操作的最长时间。我之前把看门狗设得太短结果总线上一笔正常的长时间读取操作触发了复位反而更容易卡总线。现在我的习惯是看门狗超时设为最长 I2C 事务时间的 5 倍以上这样既能兜底死循环又不误伤正常通信。这套方案我前后改了三轮最后沉淀下来的经验是温度采集看着是单片机最基础的活但本地加远程两路一起做难点全在物理层和现场环境。PJ85718DM 负责把两路温度变成数字PIC18F55K42 负责把数字变成可靠的数据真正决定系统成败的是探头线怎么走、滤波窗口怎么设、总线异常怎么恢复。如果你也在搭类似的系统建议先按这个顺序验证短线上电跑通 I2C再拉长探头线最后再进现场环境。每一步都稳定了后面才省心。