1. 项目定位与整体方案选型很多人一听到“嵌入式温度监测”第一反应就是拿一块开发板、插个DS18B20、串口打印温度完事。但真到了HVAC暖通空调或者工业嵌入式场景事情就完全不一样了你要考虑传感器离主控远不远、供电稳不稳、现场有没有强干扰、需不需要远程查看、上报失败怎么补偿、掉电之后数据还在不在。这个项目标题里的两个核心器件——PJ85718DM和PIC18F97J60——恰好回答了两个关键问题前端采集怎么做后端联网怎么传。PJ85718DM是一颗本地温度传感器I2C接口带可配置报警输出。PIC18F97J60则是Microchip早期集成以太网控制器ENC28J60一类方案的8位MCU80引脚、内置MAC/PHY传统但不简单。两者组合起来可以实现“本地实时测量 远程网络上报”的经典架构既适合HVAC的楼宇自控节点也适合嵌入式设备内部的温度巡检。选这套方案而不是一颗带以太网的MCU配模拟热敏电阻核心原因有三个第一PJ85718DM的I2C数字接口规避了模拟信号长线传输的压降和干扰问题。HVAC现场经常有电机启停、变频器工作模拟信号线上感应的噪声很容易让ADC读数跳变。用数字传感器信号线走的是I2C协议只要电平规范、上拉电阻正确抗干扰能力明显更强。第二PIC18F97J60自带以太网物理层BOM里少一颗外部PHY芯片布线也省事。对于需要在楼宇弱电间或设备柜内部署的节点来说一块板子直接出RJ45走线清晰、调试方便。虽然性能和现在的Cortex-M系列没法比但胜在资料全、寄存器手册厚、任何问题都能翻到答案适合做产品原型验证。第三这套组合的成本和功耗都适合中低密度部署。HVAC里往往一个楼层十几个节点每颗传感器和MCU的单价压制住了整体方案才推得动。PIC18F97J60的休眠电流也低如果只做周期上报电池供电的温湿度标签也能撑很久。这个项目适合谁参考一类是做楼宇自控、暖通空调系统集成的工程师需要往网关或服务器上报多个温区数据另一类是嵌入式产品开发人员设备内部PCB或外壳上需要多点温度记录同时还要求网口上云。以下所有思路和代码都按照“一个节点、一只主控、一组传感器、走TCP/UDP上报”的最小可行系统来展开。2. 硬件架构与关键引脚设计2.1 PJ85718DM 传感器接口细节PJ85718DM从接口上看很像常见的LM75系列I2C从机地址默认是1001 A2 A1 A0地址引脚硬接决定。手册里给的测温范围是-55℃到125℃精度典型值±0.5℃分辨率为9到12位可配默认上电是9位也就是0.5℃步进。做HVAC温控9位其实够用但如果要做温差趋势判断建议配置成12位量化步进约0.0625℃能看出更细的变化。接线时需要注意三点SDA和SCL必须接上拉电阻。I2C是开漏结构不加上拉或上拉太小通信时序会错乱。我习惯在3.3V系统里选4.7kΩ上拉到VDD如果线缆长度超过30cm改成2.2kΩ保险。A0/A1/A2地址引脚不要悬空。虽然有些传感器内部有弱下拉悬空也能工作但为了多挂几颗传感器时地址可预期最好硬接到VSS或VDD。OS/ALERT引脚是可编程报警输出通常接到MCU的外部中断引脚。这样传感器一旦越限MCU不用轮询也能立刻知道。HVAC场景里“超温报警”是刚需这个引脚别省。电源方面PJ85718DM工作在2.7V到5.5V逻辑电平跟随VDD。如果主控是3.3V供电传感器也接3.3V如果现场有5V供电的传感器版本注意MCU引脚是否容忍5VPIC18F97J60有些端口是5V容忍的但最好查数据手册确认别盲目直连。2.2 PIC18F97J60 的内置以太网外设PIC18F97J60的以太网模块在数据手册里叫Ethernet Module包含MAC和10BASE-T/100BASE-TX PHY。外部只需要配一个25MHz晶振内部PLL会倍频加一个带网络变压器的RJ45座比如HR911105A那种再配几个匹配电阻和电容就能跑起来。它的内部缓冲区从0x4000开始最大可用约8KB。发送和接收环形缓冲需要你手动管理两个指针ERXST/ERXND定义接收缓冲区范围ETXST/ETXND定义发送缓冲区范围。这跟用SPI外挂ENC28J60的思想很类似只是搬到了片内且没有SPI那层访问开销。引脚分配原则是让以太网模块的差分对TPIN/TPIN-、TPOUT/TPOUT-远离复位电路和晶振差分线对内等长、对间拉开距离。我第一版PCB就吃过亏RJ45下面走了I2C线结果传感器偶尔通信失败后来把I2C换到另一层并包地才稳定。所以布局时接口区域要“干净”。2.3 电源与复位电路PIC18F97J60有多个供电引脚AVDD、DVDD、OSCVDD每个引脚都要就近放0.1μF去耦电容。它内部集成稳压器给以太网PHY供电但需要外部引脚接一个电阻具体值参考手册通常是2.7kΩ到3.3kΩ来调节。忘了这个电阻PHY不工作网络灯都不亮。复位电路推荐用带手动复位按键的方案方便调试。MCLR引脚上拉10kΩ到3.3V并联0.1μF电容到地按键并联在电容上。这样上电慢、抗干扰也不会因为现场电机启动导致复位。供电上建议给PIC18F97J60单独用一颗低压差稳压器从24V或12V降下来而不是直接从开关电源输出接。HVAC控制柜里的电源噪声很大开关尖峰处理不好MCU会随机复位。2.4 最小原理图连接速查表下表是验证过的连接方式可直接抄信号PJ85718DM引脚PIC18F97J60引脚说明I2C时钟SCLSCL例如RC3上拉4.7kΩ到VDDI2C数据SDASDA例如RC4上拉4.7kΩ到VDD报警输出OS/ALERTINT0或INT1可选用于越限中断地址A0/A1/A2硬接VSS-按需分配地址以太网差分TX-TPOUT/TPOUT-接变压器以太网差分RX-TPIN/TPIN-接变压器晶振-OSC1/OSC225MHz配22pF电容这只是一个简表具体引脚复用要对照项目的数据手册。我在实际项目中是把I2C放在PORTC中断用PORTD的INT0这样代码配置也比较直观。3. 软件框架与核心逻辑实现3.1 TCP/IP协议栈怎么选PIC18F97J60这类8位MCU跑全量TCP/IP协议栈会吃力最常见的做法是用厂商提供的轻量协议栈或者开源精简栈。推荐从Microchip的MLAMicrochip Libraries for Applications里拿TCP/IP Stack虽然老但专门为PIC18系列优化过状态机清晰参考资料多。协议栈的核心抽象是“套接字”底层是MAC层的收发环形缓冲。使用上你只需要初始化协议栈然后周期性调用协议栈状态机函数// 主循环中周期调用 void main_loop(void) { // 网络协议栈任务 StackTask(); // 应用任务比如读取传感器、组装报文、发送数据 AppTask(); }如果你的应用只需要“上报温度到服务器”可以考虑三种方式TCP长连接、UDP周期上报、HTTP POST。我个人的经验表格如下方式优点缺点适用场景TCP长连接数据可靠、服务器可主动下发控制MCU资源和功耗相对高设备数量少、网络稳定UDP周期上报开销小、丢包可容忍服务器端需容忍乱序和丢包高频传感器数据、大规模节点HTTP POST调试直观可对接云平台报文冗余大MCU解析稍重原型验证、对接IoT网关在这个项目里我建议做成“双模”平时用UDP周期上报本地和远程温度收到特定命令后切换为TCP连接几分钟用于首次入网配置和固件调试。这样工作量不大但实用性很强。3.2 本地温度读取驱动PJ85718DM的读取流程就是标准的I2C寄存器读取。核心寄存器包括配置寄存器0x01、温度寄存器0x00、上下限寄存器0x02/0x03。配置寄存器里最关键是设置分辨率和比较器/中断模式。我的驱动代码骨架大致这样uint8_t tempSensorInit(uint8_t addr) { uint8_t cfg 0x60; // 12位分辨率比较器模式 return i2c_write_byte(addr, 0x01, cfg); } float tempSensorRead(uint8_t addr) { uint8_t buf[2]; int16_t raw; float temp; i2c_read_bytes(addr, 0x00, buf, 2); raw (buf[0] 8) | buf[1]; temp raw / 256.0f; return temp; }注意PJ85718DM的温度寄存器高字节是符号位整数位低字节是小数位。12位分辨率下低字节高4位有效读出来的16位原始值除以256即可得到浮点温度。如果传感器是9位模式低字节只有最高位有效直接用16位值除以128会差很多所以务必先配置好分辨率再读。3.3 远程温度处理逻辑“远程温度”在这里指的是经过以太网从远端获取的温度而不是本地I2C温度。设计上我做了这样一个数据模型本地温度每5秒读一次PJ85718DM记录进环形缓存保留最近60次数据。远程温度作为UDP客户端周期向数据服务器发送本地温度同时作为UDP服务器监听其他节点发来的温度信息存入数据表。远程温度来源一般有两种场景多台设备互为节点A设备上报自己的本机温度给B设备B设备显示“机房A温度”。设备续订一个远端天气/温度数据源作为环境补偿值。两种场景的数据存储方式完全不同。第一种需要一个节点路由表第二种更简单每30分钟请求一次即可。我在原型里实现了第一种路由表用静态数组超时清理。3.4 主循环状态机设计嵌入式程序最忌一个函数里写完所有逻辑。我习惯用状态机划分任务状态 S_IDLE空闲等待定时器时间片。状态 S_READ_LOCAL读取本地传感器更新数据缓存。状态 S_NET_TX发送UDP上报包。状态 S_NET_RX处理接收到的UDP数据包更新远程温度。状态 S_ALERT本地/远程温度越限点亮指示灯并通过日志输出。这样主循环结构清晰后期加“数据存储”或“显示面板”功能也容易扩展。void AppTask(void) { switch (app_state) { case S_IDLE: if (g_flags.read_timer) { app_state S_READ_LOCAL; } break; case S_READ_LOCAL: g_temp_local tempSensorRead(TEMP_ADDR); app_state S_NET_TX; break; case S_NET_TX: UDPPut(); app_state S_NET_RX; break; case S_NET_RX: UDPGet(); app_state S_IDLE; break; } }别小看这个状态机它让“远程温度获取失败”之类的异常分支变得很好加在S_NET_RX里如果解析失败可以跳到一个专门的S_ERROR状态记录错误计数器而不会干扰整机循环。4. 本地与远程温度监测的实操细节4.1 本地温度传感器滤波与校准PJ85718DM的读数本身已经比较平稳但HVAC环境有风机和电动阀风道附近的传感器数据仍会有小幅波动。解决办法有两种一种是软件滑动平均一种是限幅滤波。滑动平均代码很简单#define TEMP_FIFO_LEN 8 float temp_fifo[TEMP_FIFO_LEN]; uint8_t temp_fifo_index 0; float tempFiltered(float new_val) { float sum 0; temp_fifo[temp_fifo_index] new_val; temp_fifo_index (temp_fifo_index 1) % TEMP_FIFO_LEN; for (uint8_t i 0; i TEMP_FIFO_LEN; i) sum temp_fifo[i]; return sum / TEMP_FIFO_LEN; }限幅滤波则用于剔除明显跳变比如上一次读25.1℃这次突然读到32.5℃多半是I2C时序受干扰或传感器电源波动。可以设定最大变化幅度2℃/采样周期超过就丢弃本次读数沿用上一个有效值。校准方面PJ85718DM出厂精度不错但如果你用在高精度HVAC计量场景建议在25.0℃冰水浴和70.0℃恒温槽里做两点校准。将读到的偏移和增益系数写入EEPROM软件在读完原始值后做一次线性矫正。注意EEPROM写入要防掉电保护可以在结构体前写校验字上电时检查。4.2 远程温度上报的数据格式UDP报文我自定义成紧凑二进制格式而不是JSON。8位MCU解析JSON或者拼装JSON都费劲而且UDP包一长网络传输更容易分片。建议报文结构如下typedef struct { uint8_t header; // 0xAA uint8_t dev_id; // 设备ID uint16_t seq; // 序列号 float temp_local; // 本地温度 float temp_remote;// 远程温度 uint8_t flag; // 报警标志位 uint8_t crc; // CRC8 } temp_report_t;这个结构体在C里最好__attribute__((packed))浮点数传输用小端序——PIC18是小端服务器端多数x86也是小端直接用即可但如果服务器是ARM跑大端需要转换。4.3 远程温度获取与超时判断如果“远程温度”数据来自网络上的另一个节点接收时一定要考虑超时节点断线、网络堵塞都会导致数据陈旧这时候上报远程温度需要带上数据有效时间戳。我设计了一个老化计数器#define REMOTE_TEMP_TIMEOUT_S 120 uint32_t remote_temp_age_s; float remote_temp_value; uint8_t remote_temp_valid; void remoteTempUpdate(float v) { remote_temp_value v; remote_temp_age_s 0; remote_temp_valid 1; } void remoteTempAgeTick(void) { if (remote_temp_valid) { remote_temp_age_s; if (remote_temp_age_s REMOTE_TEMP_TIMEOUT_S) { remote_temp_valid 0; } } }在状态机的周期任务里每秒调用一次remoteTempAgeTick上报时如果remote_temp_valid为0则把temp_remote写成一个特殊值比如 -100.0服务器端收到就知道远程数据超时了。4.4 报警与日志PJ85718DM的OS引脚能硬件报警但远程温度没有对应引脚只能软件比较。我设计报警分级普通告警本地温度超过设定值5℃以内OS引脚产生中断写日志。严重告警本地或远程温度超过上限10℃以上开启网络发送告警UDP包同时驱动蜂鸣器。恢复事件温度回到正常范围后补发一条恢复报文。刚开始做的时候很容易漏掉恢复事件结果现场误报警后维护人员不知道设备是否已恢复正常。所以状态切换要记得记录“上一个状态”只在状态变化时发送事件。日志存储8位MCU没有文件系统可以用外部SPI Flash记录循环日志或者直接通过UDP发给服务器由服务器落盘。后者更省成本也便于集中查看前提是网络可靠。5. 常见问题与排查技巧实录5.1 传感器读数异常跳变现象I2C读取偶尔返回0xFFFF温度直接跳到-0.5℃或者125℃附近。排查步骤先检查I2C上拉电阻。示波器看SDA/SCL上升沿如果上升沿超过1μs多半上拉太大或者线电容太大。再看PJ85718DM供电。传感器电压跌落时I2C可能死锁。测量传感器VDD引脚的纹波HVAC场景容易有几十mV的毛刺必要时加10μF电解电容。最后检查地线。传感器和主控共地距离过长时地电位差会导致I2C高电平识别不了。用万用表测两个板子地之间电压最好小于50mV。我遇到最坑的情况是OS引脚悬空造成的中断风暴代码里把OS引脚配置成输入上拉后不再抖动才恢复正常。5.2 以太网PHY偶尔不工作现象网线插上link灯不亮或刚上电能通信过一会儿死机。这类问题多半是硬件问题25MHz晶振是否起振用示波器看OSC2引脚波形幅值要足够。晶振旁边的负载电容值不能随意改PCB不同电容值可能影响起振余量。PHY偏置电阻是否接对检测方法很简单用万用表量TPOUT/TPOUT-对地电压正常在1.0V到1.3V之间若为0V或接近VDD说明内部偏置没建立。隔离变压器中心抽头是否接对有些RJ45集成变压器中心抽头需要接电源有些接电容到地。按数据手册接但注意共模电感方向别焊反。软件上如果协议栈初始化后长时间没收发部分PHY会自动进入省电模式。PIC18F97J60的以太网模块也有掉电模式主循环一定要周期调用协议栈函数不能因为暂时没数据就跳过了。5.3 协议栈死锁或缓冲区溢出现象程序跑一会儿后网络中断协议栈内部计数不对重发连环发生。原因常出在MAC缓冲区配置上。PIC18F97J60的以太网缓冲区有限如果你把发送缓冲和接收缓冲设得过于接近或者收发过程中没有及时释放RX缓冲区就会出现死锁。我的做法RX缓冲设为从0x4000到0x6000共8KBTX缓冲从0x6000到0x6400共1KB发送前先检查TX缓冲区是否有空间没有就循环等待但加一个超时上限。每次收完一帧后立即处理处理完尽快清ERXCON把缓冲区权交还给硬件。避免在接收中断里做大量处理正确姿势是中断里置标志主循环里做UDP解析。这个和很多嵌入式工程师开发习惯一致但实现时要真正隔离好才可以。5.4 远程温度不上报不上报可能出现在三个位置发送失败UDP目标端口或IP不对。用PC上的Wireshark抓包先看是否有源IP发出的UDP包。没有包就是MCU侧发送逻辑没执行有包但服务器没收到检查端口和路由。接收失败设备做UDP服务器时需要正确设置绑定端口。PIC协议栈的UDP socket绑定端口要对应远端请求的源端口否则收不到。数据老化远程温度对象超时后没有发无效标记主控一直发陈旧数据。这个从代码逻辑上检查即可。调试技巧在设备里预留一个测试模式短按按键后向固定IP发送一条带设备ID和版本号的测试报文。这个模式我在现场排查网络问题上帮了大忙简单但有效。6. 项目扩展与长期运维建议这套系统做完最小原型以后你会发现真正的价值在于长期数据积累。温度曲线、越限频率、设备健康度这些只有运行几个月后才能看到。所以从第一天设计就要考虑数据侧服务器端要按设备ID和月份建表温度数据单独存不要和报警事件混在一张表里否则查询很慢。上报周期别设太短HVAC的温度变化很慢5到10秒一次足够太频繁徒增网络和功耗。给每个节点配一个固件版本字段方便后续批量升级。此外这套架构也可以很容易替换掉前端传感器。比如把PJ85718DM换成其他I2C接口的温度传感器例如SHT30、TMP117驱动改动量很小因为协议栈和网络上报部分完全复用。硬件上只要保持I2C地址可配置即可。如果未来要增加“远程控制”比如通过服务器下发目标温度就要在UDP报文里增加方向位和命令字同时在MCU端加一个命令解析状态机。这部分并不复杂但要注意命令校验和身份识别避免网络里任何设备都能改写配置。我在实际开发中还遇到过供电闪断导致参数丢失的问题后来把校准参数和配置备份成三份存储每次上电读校验和选多数通过的版本。这个“三冗余参数”思路虽然土但在现场极好用。7. 个人实操体会与一点火花这套PJ85718DM加PIC18F97J60的方案我从画图到调通大概用了两周。第一周卡在以太网PHY偏置电阻上link灯怎么都不亮第二周卡在I2C地址冲突因为板上另一颗芯片居然占用了传感器默认地址。踩过几次坑之后我养成了一个习惯原理图阶段就把所有I2C器件的地址列成一张表画出完整的总线拓扑确认没有冲突再投板。同时给PIC18F97J60的以太网接口留好测试点因为网络问题用示波器点引脚远比看代码容易定位。如果你现在正准备做类似的项目我建议你先别急着加复杂协议把“读温度 UDP上报 看门狗”跑通后续再加HTTP或MQTT。开发嵌入式稳定压倒一切一个8位MCU如果什么功能都往上堆最后结果往往是到处救火。这套系统还可以扩展到更多场景冷链运输记录仪、机房环境监测、农业大棚多区温度采集。只要把PIC18F97J60的以太网口换成充电管理加4G模块整个架构的思想依然成立——本地物理量感知远程数据汇聚。最后再分享一个小技巧在协议栈主循环里放一个翻转某个GPIO的示波器钩子测量任务周期是否稳定。温度监测应用对实时性要求不高但周期抖动会影响滤波效果。这个钩子能让你一眼看出哪个任务拖慢了主循环比任何调试器都好用。