资讯动态

PIC18F85J10与PJ85718DM:HVAC嵌入式I2C温度采集方案详解

发布时间:2026/10/22 6:39:18 来源:尧图企业网站定制
做嵌入式温度采集尤其暖通空调HVAC这类要在电控箱里长期连续运行的控制器最常见的方案就是一颗 8 位单片机接几颗 I2C 数字温度传感器。这次要讲的项目就是用 PIC18F85J10 作为主控通过 I2C 总线读取 PJ85718DM 数字温度传感器同时监测本机温度和远端探头温度覆盖嵌入式设备本板防过热和 HVAC 现场空气温度反馈两类场景。适合正打算做温控器、风阀控制器、机柜温度监测或者单纯想把多路温度采集做稳定的朋友参考。整个项目做下来真正花时间的其实不是“读出温度”本身而是怎么把本地和远程温度都读得准、读得稳以及现场长线供电、变频器干扰、传感器故障之后控制器该怎么表现。下面按我在实际调试中整理的顺序把方案选型、硬件接线、固件实现、HVAC 落地和排错经验一次说清。1. 先把方案盘清楚为什么是这颗 MCU 和这颗传感器1.1 项目需求拆解标题里的信息量其实不小PJ85718DM 负责把温度变成数字量PIC18F85J10 负责采集、处理并执行控制应用场景是嵌入式设备和 HVAC。拆开看这个项目有四个层面的硬需求。一是本地温度监测。嵌入式设备里要防止主控板局部过热比如电源芯片、功率管区域温度异常时提前告警。二是远程温度监测。HVAC 系统里控制回风温度、送风温度、室外环境温度时传感器不可能都装在 PCB 上必然有一段线缆把探头引到风管或室外。三是控制逻辑。单纯“测温度”没有意义必须根据温度差去驱动继电器、接触器或者给上位机报数据。四是长期稳定性。HVAC 设备不是实验室几分钟跑完就结束常常几个月不停机温度传感器一旦失效或者总线被干扰控制器不能无故宕机或误动作。所以这个项目不是一个“点灯式”的测温 demo而是一个偏工业可靠性的综合采集控制问题。PJ85718DM 在我手头的定位是低成本、免校准、数字化传输的主力探头配合 PIC18F85J10 的 MSSP 接口既能把本地探头直接贴在主板上也能把第二颗、第三颗探头拉到远端。1.2 PIC18F85J10 为什么够用选 PIC18F85J10 不是因为它性能多强而是因为它在这个场景里足够匹配且整套成本压得住。这颗 8 位机属于 PIC18 J 系列工作电压范围宽适合 3.3V 主控系统内部带多个 MSSP 模块、UART、定时器和 EEPROM。以温度采集这种任务来说每秒最多处理几路 I2C 数据运算量根本谈不上压力真正有用的是它有独立的 MSSP 硬件模块CPU 只需要操作寄存器就能完成 I2C 通信不用软件模拟时序这会省掉大量调试时间。另一层考虑是 EEPROM 和看门狗。HVAC 现场要保存设定温度、传感器偏移校准值、故障次数统计内部 EEPROM 能直接做掉不用外挂存储。看门狗则保证程序卡死或总线异常时能自动复位对于无人值守设备是刚需。再加上 J 系列引脚多后面要扩展按键、LCD 1602、蜂鸣器、继电器驱动I/O 完全够用。1.3 PJ85718DM 是干什么的PJ85718DM 是一颗低功耗 I2C/SMBus 接口数字温度传感器寄存器模型和市面上常见的兼容型数字温度芯片类似内部有温度 ADC出厂前做过校准直接通过 I2C 读寄存器就能拿到带符号的温度数据不需要像 NTC 热敏电阻那样做分压电路、查表、逐批标定。它带 A0-A2 地址引脚一条 I2C 总线上最多可以挂 8 颗所以“本地和远程温度”这个需求最直接的实现方式就是同一型号放两颗或者多颗每颗配一个不同地址。相比 NTC 方案数字传感器最大的优势是免标定和抗干扰。NTC 在 HVAC 里用了很多年但阻值分散性大每块板子都要校准长线传输时线阻还会直接叠加进误差而 PJ85718DM 这种数字传感器温度先在自己内部变成数字量长线传输的是 I2C 电平信号对线阻不敏感。相比 1-Wire 单总线方案I2C 的时序容错更好逻辑分析仪抓波形也直观排查起来简单得多。2. 硬件和接线本地温度与远程温度是怎么接出来的2.1 最小系统和电源处理PIC18F85J10 的最小系统按照数据手册搭就行但有几个细节在 HVAC 场景下特别容易踩坑。供电我建议用 3.3V LDO 单独给 MCU 和传感器供电如果系统里有继电器或接触器那一路驱动电源要彻底隔离至少做到地线分开。实测继电器吸合瞬间如果电源抖动超过 0.3VI2C 通信就会出现随机失败温度读数偶尔跳变。MCU 的 VDD/VSS 引脚比较多每一对都要就近放 0.1uF 陶瓷电容总入口再加 10uF 电解电容。晶振用外部晶体而不是内部振荡器。PIC18F85J10 内部振荡器虽然能用但 I2C 时序和 UART 波特率在温度变化大的现场会受影响外部 8MHz 晶体配合内部 PLL 或直接分频是最稳的选择。本地传感器如果贴在 PCB 上要避开板上的发热源。我做过一次实测把传感器放在 LDO 旁边 5mm 处读数比旁边冷风道里的温度高了 2.3 度这种偏差不是软件能完全补掉的布局阶段就要留出距离。远程传感器则通过端子引出供电、地、SDA、SCL 四根线采用屏蔽双绞线这是 HVAC 现场最标准的接法。2.2 I2C 上拉电阻和地址分配I2C 总线是开漏结构SDA 和 SCL 必须有上拉电阻才能工作。上拉阻值选择会直接影响通信稳定性阻值太大上升沿太缓阻值太小灌电流偏大。3.3V 系统、100kHz 标准速率下总线上挂两颗传感器、线长半米以内用 4.7k 上拉没问题如果远程探头线长超过 2 米建议把上拉降到 2.2k甚至可以在远端传感器附近再补一个上拉电阻。地址分配属于“接线前就要想好”的事。PJ85718DM 的三个地址引脚高低电平决定 7 位地址的低三位。我的习惯是第一颗本地探头地址 A0-A2 全接 GND得到基准地址 0x48第二颗远程探头把 A0 接 VDD地址变成 0x49。换算成 I2C 8 位地址时本地是 0x90远程是 0x92这个值在固件里直接写死比运行时再去扫描总线省事也不会因为总线挂异常设备导致误判。2.3 远程探头的走线、距离和抗干扰远程测温最大的坑是线缆电容和现场干扰。I2C 设计初衷是板级总线不是长线传输总线。100kHz 速率下普通双绞线走 2 米以内问题不大走到 5 米时线电容会明显拖慢上升沿这时候要么把速率降到 10kHz要么选低电容屏蔽线要么在远端也加上拉。我实际项目中有一段 8 米长的探头线降速后跑得很稳但再往上加长度就不划算了。如果现场走线非常长超过 10 米我不建议继续硬扛 I2C。更合理的是改成 RS485 分布式采集每个区域节点用一颗小单片机读就近的传感器再把结果通过 Modbus 协议上传给主控。标题里的 PIC18F85J10 在 HVAC 系统里完全可以作为区域节点的主控这样每段 I2C 都保持短距离区域之间的长线交给 RS485抗干扰能力会强很多。屏蔽线的处理也有讲究屏蔽层只能单端接地接到控制板的 GND不能接到远端传感器那一侧的 GND否则会形成地回路反而把干扰引入总线。我在现场就遇到过把屏蔽层两头都接地之后压缩机一启动温度读数就跳 1 度的情况改成单端接地后立刻干净了。2.4 端子处的保护电路HVAC 现场电磁环境比实验室恶劣得多变频器、压缩机、接触器启停时会有很强的空间干扰。传感器端子引到设备外部还需要考虑静电和误接。我习惯在每个远端端子的 SDA、SCL 对地各加一颗 TVS 管电源入口加一颗防反接的肖特基二极管SDA、SCL 再各串 100Ω 到 220Ω 的电阻限制异常电压的冲击电流。这些元件成本不高但能避免现场一根线接错就烧掉一片传感器。本地传感器如果和控制板共电源共地保护可以简化但也不建议省略。很多 HVAC 控制器长期带电维修维修人员用万用表表笔碰到端子是常有的事有了 TVS 和串阻至少不至于直接烧到主控的 MSSP 引脚。3. 固件实现从 I2C 波形到稳定温度值3.1 I2C 外设初始化PIC18F85J10 的 MSSP 模块配置成 I2C 主机模式用的是标准做法。下面这段初始化代码在常用的 PIC C 编译环境里可以直接用关键是 SSPADD 的计算主模式时钟等于 Fosc / (4 × (SSPADD 1))要 100kHz 时反向算出加载值即可。#define _XTAL_FREQ 8000000UL void I2C_Init(void) { // 主机模式时钟 Fosc / (4 * (SSPADD1)) SSPCON1 0x08; SSPCON2 0x00; SSPSTAT 0x00; // 7位地址、标准电平 SSPADD (_XTAL_FREQ / (4UL * 100000UL)) - 1; // 100kHz SSPCON1 | 0x40; // 使能 MSSP }如果远程探头线变长需要把速率降到 10kHz只要把 100000 换成 10000SSPADD 会自动变大时钟变慢I2C 上升沿的要求就宽松很多。这个参数我在调试时反复改过10kHz 下 5 米双绞线完全能跑只是采集速度慢一点但温度本身变化慢500ms 轮询一轮完全感受不到延迟。3.2 一次完整的温度读取流程PJ85718DM 的温度读取流程和同类寄存器兼容芯片一致先发送起始条件写器件地址加写位再写温度寄存器指针 0x00然后重启总线发器件地址加读位连续读两个字节最后发停止条件。读回的高字节和低字节拼成一个 16 位数值右移后乘以 0.0625 就是摄氏度。#define SENSOR_LOCAL_ADDR7 0x48 // 本地探头 #define SENSOR_REMOTE_ADDR7 0x49 // 远程探头 unsigned char I2C_WriteByte(unsigned char dat) { unsigned char res; SSPBUF dat; while (!SSPIF); SSPIF 0; res ACKSTAT ? 1 : 0; // ACKSTAT1表示无应答 return res; } unsigned char I2C_ReadByte(unsigned char sendAck) { unsigned char dat; RCEN 1; while (!SSPIF); SSPIF 0; dat SSPBUF; ACKDT sendAck ? 0 : 1; // 1发ACK0发NAK ACKEN 1; while (!SSPIF); SSPIF 0; return dat; } unsigned int ReadTempReg(unsigned char addr7) { unsigned char msb, lsb, err; SEN 1; while (!SSPIF); SSPIF 0; // START err I2C_WriteByte(addr7 1); // 写地址 if (err) return 0xFFFF; err I2C_WriteByte(0x00); // 温度寄存器 if (err) return 0xFFFF; RSEN 1; while (!SSPIF); SSPIF 0; // 重启 err I2C_WriteByte((addr7 1) | 1); // 读地址 if (err) return 0xFFFF; msb I2C_ReadByte(1); lsb I2C_ReadByte(0); PEN 1; while (!SSPIF); SSPIF 0; // STOP return ((unsigned int)msb 8) | lsb; }读回裸寄存器值之后转成温度数值有两个注意点。一是要考虑符号位温度零下时 16 位值转成有符号数再右移右移时按带符号处理。二是温度高位和低位拼成 int 后直接做算术右移不要无脑除以 16负数除法的行为和右移不一致容易在零下温度时出错。signed int code (signed int)raw; signed int temp12 code 4; // 12位有符号温度码 long temp_x100 temp12 * 25L / 4; // 扩大100倍的温度1LSB0.0625度用扩大 100 倍的定点数表示温度是为了后面控制逻辑不需要浮点数。比如 23.4375 度temp_x100 等于 2343和设定值 2200 比较时直接用整数比较没有浮点运算在 8 位机上省很多指令。3.3 滤波、校准和故障剔除温度传感器读数不能拿来直接用至少要过三关滤波、校准、故障剔除。滤波方面我实测最有效的是“中值滤波 滑动平均”组合。每路传感器连续读 5 次取中间值再把这 5 次的中间值放进最近 8 个有效样本的环形缓冲里求平均。这样既挡掉了单次毛刺又让温度变化曲线足够平滑。HVAC 控制里温度变化本身是秒级甚至分钟级的多几轮滤波不会拖慢响应但对抑制变频器干扰非常有效。校准方面数字温度传感器出厂误差一般在 ±0.5 度左右HVAC 大多数场景直接能用但如果你对绝对精度有要求可以用冰水混合物和精密水银温度计做单点偏移校准。偏移量保存在 PIC18F85J10 的内部 EEPROM 里下次上电自动加载。注意是单点偏移而不是斜率校准对于这种传感器来说单点已经能纠正大部分误差。故障剔除方面读回 0xFFFF、0x8000 这种明显异常的值以及算出来超过 -40 到 125 度的范围都直接判为无效样本跳过不参与滤波。连续 5 次读到无效样本就置故障标志传感器故障后控制系统按安全状态运行而不是用一组乱跳的温度去控制压缩机。3.4 多路轮询和主循环调度本地和远程两颗传感器不需要同时读温度变化慢只要周期性轮询即可。我的做法是在主循环里用一个 10ms 时基每路传感器 500ms 读一轮两路就 1 秒一个完整周期。这样每一路都能完成 5 次连续采样、中值滤波、滑动平均CPU 占有率很低剩下的时间都留给显示刷新和控制逻辑。void Task_UpdateTemperatures(void) { unsigned int raw; signed int code; raw ReadTempReg(SENSOR_LOCAL_ADDR7); if (raw ! 0xFFFF) { code (signed int)raw 4; FilterPush(0, code); // 送入本地滤波队列 } raw ReadTempReg(SENSOR_REMOTE_ADDR7); if (raw ! 0xFFFF) { code (signed int)raw 4; FilterPush(1, code); // 送入远程滤波队列 } }主循环里再放一个看门狗清狗计数。I2C 每次开始、停止、读写都要加超时判断不能无限等 SSPIF。我习惯在每步操作里用 10ms 超时超时就退出本次读取并返回错误这样即使某个传感器把总线拉死主循环也能继续跑不会导致整个控制器卡死。4. HVAC 场景怎么落地4.1 恒温控制滞回比 PID 更实用HVAC 控制里最常见的需求是恒温控制比如设定 22 度。直接用 PID 在 8 位机上做其实没有必要大多数商用温控器用的都是滞回控制。滞回的核心是设定一个开启阈值和一个关闭阈值中间留一个死区防止继电器频繁通断。我用定点温度 temp_x100 做比较设定值 2200 代表 22.00 度滞回量设置 300也就是 3 度。实际做下来加热和制冷切换之间留 0.5 度左右的死区再配合接触器的机械延迟继电器一天通断次数能控制在几十次以内完全不会像 PID 参数没调好时那样疯狂抖动。4.2 多区域远端扩展的总线设计一根 I2C 总线上最多挂 8 个 PJ85718DM这决定了用纯 I2C 做多区域采集时有上限。如果 HVAC 项目里区域超过 8 个我建议不要把 8 颗传感器全挂在一条远程总线上因为每颗传感器的线缆都可能走不同方向地电位差和干扰会互相叠加。更稳妥的做法是按区域分组一个区域控制器只负责本区域的两三路温度区域之间用 RS485 通信。比如一个楼层有 4 个 VAV 区域每个区域一个 PIC18F85J10 节点节点之间走 RS485 总线主控制器统一汇总。这个架构下I2C 永远只出现在节点内部距离短、干扰小整体可靠性和可维护性都明显更好。如果一定要把多组远程传感器复用到同一颗 MCU 上可以用 I2C 总线多路开关把不同组的传感器挂到不同通道MCU 通过切换通道分时读取。这样其实是用硬件把总线隔离成多个短线段比一条长线挂多个设备稳定得多。4.3 报警、参数保存和数据记录传感器故障和温度超限在 HVAC 里必须区别处理。我的经验是温度超限分两级第一级是预报警比如温度超过设定值 5 度亮黄灯、通过 UART 上报第二级是动作报警比如超过 10 度直接切断制冷或加热输出防止设备在异常工况下继续运行。传感器本身故障则走另一套逻辑按停机或按上次有效值估算绝不能拿一个错误温度去启动压缩机。设定参数、校准偏移、报警阈值都存在 EEPROM 里。PIC18F85J10 的 EEPROM 操作不复杂但要注意写入寿命和写周期时间。现场调试时我不建议频繁通过上位机改写 EEPROM频繁写会把寿命耗尽。合理做法是把易变参数放在 RAM只有确认最终参数后才批量保存一次。5. 调试这几天踩过的坑和速查5.1 上电读数全是 0xFF却找不到原因这种情况十有八九是总线上根本没有从设备应答。我先说排查顺序按这个顺序查基本几分钟能定位。先用逻辑分析仪或示波器抓 SDA、SCL 波形看 MCU 发的地址字节之后有没有 ACK 低电平。没有 ACK直接从这几个方向查传感器供电有没有接对VDD 和 GND 有没有接反A0-A2 地址引脚电平是不是自己预期的那样比如你程序写 0x48但传感器地址脚全接高就是 0x4F肯定应答不了上拉电阻有没有焊虚SDA 和 SCL 线序有没有在端子上接反。一个很容易忽略的点是很多市售温度传感器模块上的丝印 SDA、SCL 和实际引脚顺序不一定一致焊板前先用万用表二极管档量一下模块上排针和传感器引脚之间的连通关系比你写完程序再去猜快得多。5.2 SDA 被从机拉死软件怎么恢复I2C 最烦的故障是 SDA 一直为低整个总线被锁死。常见原因是某颗传感器在上电时序异常时进入错误状态或者在通信中途 MCU 复位了而传感器还在等后续时钟。遇到这种情况单纯重发起始条件没用必须让传感器收到足够多的时钟脉冲来解锁。我的处理是在每次 I2C 操作前先判断 SDA 和 SCL 电平如果 SDA 异常为低就软件产生 9 个时钟脉冲然后发一个 STOP 条件再重新初始化 MSSP。配合看门狗即使总线被锁控制器也能在几百毫秒内恢复通信。这个方法对这类寄存器兼容的数字温度传感器都有效。5.3 远程温度读数跳变先别怀疑传感器远程探头读数波动大的时候多数开发者第一反应是换传感器但按照我的经验真正原因往往是走线干扰或滤波不够。我之前出现过现场数据在压缩机启动瞬间跳 3 度的情况单独测传感器又是好的最后定位到是传感器线缆和压缩机动力线走在同一个线槽里屏蔽层又两头接地形成地回路。把动力线分开走、屏蔽层单端接地、远端加上拉、软件再补一道中值滤波后问题彻底消失。要注意不是所有跳变都要靠硬件解决。纯软件的角度把采样次数从 3 次提高到 5 次、滑动窗口从 4 个变成 8 个效果也很明显。温度信号本身低频适当增加平滑不会损失真实响应。5.4 常见问题速查表现象可能原因处理办法所有读数都是 0xFF无 ACK传感器未应答查供电、地址引脚、上拉电阻、线序读数固定为 0x00读到了配置寄存器或地址错误确认寄存器指针写入 0x00 后再读本地读数偏高传感器靠近发热源调整 PCB 布局加散热隔离远程读数乱跳干扰、地回路、上拉不足屏蔽层单端接地降速加滤波总线偶尔死锁传感器异常状态软件 9 时钟恢复配合看门狗换板子后读不到焊接问题或传感器损坏用逻辑分析仪对比正常板和故障板波形零下温度显示正数符号位处理错误温度码按有符号右移再乘 0.0625我个人在实际调试里最大的体会是这类温度采集项目真正决定成败的往往不是芯片本身而是布线和软件容错。先把一颗传感器读稳、连续跑一天看数据曲线再写控制逻辑比一上来就堆功能稳妥得多。后面如果再扩展这个框架可以直接套用到多区域温控、机柜温度监控、冷链数据记录这些类似的场景换传感器型号、换 MCU 平台核心思路都一样。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑