☰
嵌入式HVAC温度监测:PIC18F47J53与PJ85718DM的本地远程采集方案
2026/10/22 6:43:08 网站建设 项目流程

做嵌入式温度监测的人,尤其是和暖通空调(HVAC)打交道时,十有八九会遇到一个尴尬场景:自己手边这块板子上的温度特别好测,房间另一端、风管深处的温度就成了玄学。这段时间我把 PJ85718DM 这颗数字温度传感器和 PIC18F47J53 这颗外设丰富的8位单片机搭在一起,做了一套既能采集本地温度、又能通过远程节点读取远端温度的监测方案,在一套小型HVAC样机上连续跑了小半个月,本地和远程的温度曲线都能稳定上传。

这套方案解决的不是什么高深问题,却很典型:嵌入式设备内部要测板卡温度,HVAC现场要测风管送风温度、回风温度和机房环境温度,而这两类温度往往不在同一块板子上,距离可能从几十厘米到几十米不等。所以整篇文章就顺着我的实际开发过程往下走:先说为什么选这两颗料,再讲硬件上埋了哪些雷,然后是代码层面的关键实现,最后把现场踩过的坑整理成速查表。适合正在做环境监测、智能楼宇、设备状态监控或HVAC控制器的朋友参考。

1. 方案选型与整体设计思路

1.1 为什么是 PJ85718DM 和 PIC18F47J53

先说传感器。PJ85718DM 是一颗带I2C接口的数字温度传感器,标称测量范围覆盖了常规HVAC场景,从零下的冷媒管道环境到设备内部七八十摄氏度的热点区域都够用。关键是它直接把温度转换成数字量,不需要额外搭运放、分压电阻和ADC前端电路,这对于空间紧张的嵌入式板卡来说非常友好。我最早用的是NTC加精密电阻的方案,硬件上多两个元件还不算麻烦,麻烦的是每块板子都要做校准,批次一换曲线就飘,后期维护成本高。换成PJ85718DM之后,精度指标由器件本身保证,出厂校准也已经完成了,软件里只需要做IO口初始化和寄存器读取,能省掉一大块模拟调试的时间。

再来说单片机。PIC18F47J53 是带丰富数字外设的8位MCU,Flash和RAM对于单纯做温度采集来说绰绰有余,I2C、UART、SPI这些接口都齐,还有一个比较可靠的中断系统。有人可能会问,这种应用为什么不用个几块钱的STM32或者国产Cortex-M0?我的回答是:在已有方案里,PIC18系列在工业现场的稳定性和开发工具链的成熟度经得起考验,而且8位机在这种简单任务下的功耗更低、抗干扰表现也更可控。HVAC现场到处都是继电器、接触器和变频器,单片机抗干扰能力比单纯的CPU主频更重要。

PJ85718DM 负责把物理温度变成数字量,PIC18F47J53 负责把所有数字量汇总、处理、打包成协议帧并转发出去,这一对组合在成本、功耗、开发效率三个维度上比较均衡,适合中小型项目使用。

1.2 “本地与远程温度”到底怎么拆解

这个标题里的“本地”和“远程”容易让人误解成云平台和局域网的关系。实际上我这里说的是物理位置上的本地和远端。以我做的HVAC样机为例:

  • 本地温度:机柜内部空气温度,或主控板附近的环境温度,由安装在主机PCB上的 PJ85718DM 直接负责采集;
  • 远程温度:风管送风温度、空调机组回风温度、机房门窗附近区域温度,由独立的远端节点板采集,再通过通信线缆传回主机。

两个角色的采集电路几乎相同,区别在于通信链路。本地传感器直接挂在主控芯片的I2C总线上,地址独立,读取方便;远程节点则做成RS485从站,主机通过Modbus或私有协议统一下发查询指令。为什么不用I2C把远程传感器直接拉过去?因为I2C是单端信号,抗共模干扰能力弱,线缆超过一两米之后就容易出现数据错乱。HVAC现场的电线槽里经常和220V动力线走在一起,I2C在这种环境里很难稳定工作。RS485是差分传输,传输距离可以到几百米,又能多节点挂载,后续想扩展第三个、第四个测温点也不至于重新改硬件。

所以整个系统的数据流向是:PJ85718DM 采集到的温度数值经过芯片内部处理,由I2C总线送到PIC18F47J53,单片机做滤波和协议转换后,本地温度直接用于显示或控制逻辑,远程温度则通过串口汇聚到上位机或楼宇自控系统。这套架构拆开看其实就是“传感器-主控-通信”三段式,但每个环节里都有不少细节,后面逐一展开。

2. 硬件设计:可靠性的关键不在原理图而在细节

2.1 PJ85718DM 的接入与地址配置

PJ85718DM 的典型接法并不复杂,VDD接电源,GND接地,SDA和SCL接单片机的对应I2C引脚,然后在这两根线上分别加上拉电阻到VDD。上拉电阻阻值我推荐4.7k到10k之间,系统工作电压3.3V时选10k没问题,5V供电时也可以选4.7k。阻值太小会增大总线功耗,太大则会导致沿变缓、高速通信时容易出现误码。400kHz通信速率下10k上拉已经够用,如果总线上挂载的从设备较多,可以适当降低到4.7k。

地址配置也要留意。这类I2C温度传感器通常会有地址选择引脚,通过对A0、A1接高接低的组合,可以在一条总线上挂载多颗同型号传感器而不冲突。实际接线时我把地址脚全部接地,用默认地址,这样最简单;如果项目里需要多颗传感器,建议把地址引脚接到单片机的通用IO口,通过软件动态切换地址。这个技巧在做多路温度采集时非常实用:硬件上不需要为每颗传感器单独分配一组IO,只需要一个I2C接口加上几个地址控制引脚就够了。

在画PCB时,PJ85718DM 位置要尽量靠近被测量物体,但不要直接贴在发热元件上,否则测到的就不是环境温度而是元件表面温度了。SDA和SCL走线尽量短,旁边不要平行走大电流或继电器控制线,有条件的话可以加一组串联电阻(如33Ω)和100pF对地电容,形成简单的RC滤波。

2.2 PIC18F47J53 最小系统与供电

MCU本身的最小系统是这套硬件的基础。供电方面,PIC18F47J53 是宽电压工作,3.3V和5V都可以跑。HVAC现场常用24V交流电源,我建议先用隔离DC-DC把24V变成5V,再经过LDO降到3.3V给MCU和传感器使用。隔离电源这步不能省,因为现场大功率设备启停时电源线路上会有很强的浪涌和地电位差,不隔离的话复位和死机是家常便饭。每个电源引脚旁边都要放0.1uF陶瓷电容,电源入口再放一个10uF以上的电解电容或者钽电容用于低频储能。

复位电路看起来简单但最容易埋坑。MCLR引脚需要接一个10k上拉电阻到VDD,同时并一个100nF电容到地,防止干扰脉冲误触发复位。早期我图省事,直接给MCLR接个10k了事,结果现场一启动大功率风机MCU就重启,后来并联电容才好。如果项目预算允许,可以加一个带手动复位功能的专用复位芯片,可靠性会更高。

调试接口也必须在设计初期预留。ICSP编程接口至少要引出VPP、MCLR、PGD、PGC、VDD、GND这六根线,并且引脚附近预留测试点。温度监测项目经常要在现场修改通信参数或采样策略,没有调试口的话后期每改一次程序都要拆机,非常痛苦。

2.3 远程节点的RS485物理层

远程温度采集的硬件核心是RS485收发器。收发器选型上我用的是带自动方向控制的型号,省去了单片机侧DE/RE引脚的控制逻辑。接线方式也要注意,一条RS485总线上所有设备的A端接A端、B端接B端,不能交叉。总线的两端各接一个120Ω终端电阻,这是匹配线缆特性阻抗用的,能有效减少信号反射。

线缆选屏蔽双绞线,屏蔽层在主机侧单点接地,不能两端都接地,否则会形成地环路,反而引入干扰。对于HVAC这种环境,线缆尽量远离变频器和动力线,不可避免交叉时要走垂直方向。总线上还应该加TVS管做浪涌保护,因为传感器节点可能装在风管或屋顶,雷击感应和静电放电的概率比室内设备高得多。通信波特率不要一味求快,9600或19200在这个应用场景下完全够用,波特率低了抗干扰能力更强。

2.4 HVAC环境独有的抗干扰细节

HVAC现场和实验室最大的区别是电磁环境极其恶劣。我遇到过的情况包括:冷水机组启动时电压瞬间跌落,变频器运行时空间电磁干扰导致传感器读数跳变,以及多台设备共用一根地线导致地电位漂移。针对这些情况,除了前面提到的隔离电源和屏蔽双绞线之外,还有几个小措施很管用:输入端口加TVS和共模电感,传感器I2C引线串磁珠,MCU的ADC基准引脚加更大的滤波电容。另外外壳要可靠接地,但要通过接地端子和星型接地方式,避免形成接地环路。

软件上也要做配合,后面会单独讲滤波。我这里想强调一个容易被忽略的点:传感器供电不要直接从MCU的某个GPIO拉,也不要和继电器或蜂鸣器共用电源支路,最好单独走一小段线接到电源滤波电容之后。这样传感器电源纹波小,温度读数更稳定,同时也能避免负载突变造成的电压跌落。

3. 软件实现:从I2C寄存器到远程协议

3.1 I2C驱动程序与温度读取流程

PIC18F47J53 内部有硬件I2C模块(MSSP),软件只需要做寄存器配置和数据收发。初始化时把I2C配置为主机模式,通信速率设为100kHz或400kHz都可以。传感器对这种低速通信完全不敏感,我实际用的是100kHz,稳定性优先。

下面是I2C初始化和读取传感器原始温度数据的示意代码,风格是PIC18系列的寄存器直接操作,方便对照数据手册理解:

void i2c_init(void) { TRISCbits.TRISC3 = 1; // SCL 输入 TRISCbits.TRISC4 = 1; // SDA 输入 SSPCON1 = 0x28; // I2C 主模式,使能 SSPCON2 = 0x00; SSPADD = 249; // 4MHz/ (4*(249+1)) = 100kHz,具体按实际时钟计算 SSPSTAT = 0x80; // 标准速率模式 } unsigned int read_temperature(void) { unsigned char high_byte, low_byte; unsigned int raw_value; i2c_start(); // 起始条件 i2c_write(0x48 << 1 | 0x00); // 器件地址 + 写 i2c_write(0x00); // 温度寄存器地址 i2c_stop(); i2c_start(); // 重新起始 i2c_write(0x48 << 1 | 0x01); // 器件地址 + 读 high_byte = i2c_read(1); // 读高字节,发ACK low_byte = i2c_read(0); // 读低字节,发NACK i2c_stop(); raw_value = (unsigned int)((high_byte << 8) | low_byte); return raw_value; }

这段代码的逻辑很简单:先向传感器写入要读取的寄存器地址,然后重新发起起始条件并切换为读模式,连续读两个字节拼成16位原始值。细节上要注意读最后一个字节时必须回NACK,否则传感器会认为主机还想要继续读而一直占用总线,导致后续通信异常。

3.2 原始值到摄氏度的换算

PJ85718DM 这样的数字温度传感器,内部寄存器保存的是二进制补码格式的温度数据,换算关系以器件手册为准。以12位精度为例,通常每个LSB代表的温度值可以从手册中查到,常见的换算方式是将原始值乘以一个固定系数。我实际使用的代码是这样的:

float convert_to_celsius(unsigned int raw_value) { float temp; // 假设12位精度,LSB = 0.0625°C,需要考虑符号位 if (raw_value & 0x8000) { raw_value = raw_value | 0xF000; // 负数时符号扩展 } temp = (float)((int)raw_value) * 0.0625; return temp; }

负温度处理是容易出错的地方。如果寄存器只用12位表示数据,高几位是符号扩展位,直接把16位原始值当作有符号数处理,必须先做符号扩展。我在第一次调试时就忽略了这一步,导致零下的温度读出来变成了一个很大的正数,看上去像“传感器损坏”,实际上是自己的换算问题。

3.3 本地温度的软件滤波和校准

温度采集的原始数据直接拿去显示往往会有小幅跳动,特别是有变频器干扰或电源纹波较大的场合。我用的策略是两级滤波:先做中值滤波,再从连续N次有效值中取平均。中值滤波可以剔除偶发的粗大误差,滑动平均则能把常规噪声平滑掉。

具体实现是:每200毫秒读一次传感器,连续读到5个数,排序后取中间值作为本周期结果;再把最近5个周期的中值存到一个环形缓冲区,求算术平均后输出。这样处理之后,温度显示基本稳定,实测跳动范围从±0.3摄氏度降到了±0.1摄氏度以内。对HVAC控制来说,这个波动级别完全可以接受。

校准方面,PJ85718DM 本身精度已经不错,但在产品出厂前我仍然会做一次单点校准:把传感器和标准温度计放在同一恒温环境中,读出差值,然后在软件里减去这个固定偏移。要注意这个偏移是加法性的,和温度本身不充分相关,所以最好在预期工作温度范围的中值附近做校准。如果要求更高,可以标两个点做线性补偿,偏移和斜率都修正一遍。

3.4 远程温度采集与主从轮询协议

远程传感器的通信我用了极简主从协议,帧结构尽量模仿Modbus RTU,但比完整Modbus更简化。主机周期性广播或定向发送查询帧,从机收到后解析地址和自己的地址一致,则准备数据并应答。

帧格式如下:

[地址1字节] [功能码1字节] [数据长度1字节] [数据N字节] [CRC16低字节] [CRC16高字节]

以查询远程节点温度为例,主机发送:地址 0x01,功能码 0x03,数据长度 0x00,CRC校验。从机正常应答时返回:地址 0x01,功能码 0x03,数据长度 0x02,温度高字节,温度低字节,CRC校验。主机程序里设置一个超时时间,例如50毫秒,如果收不到应答就认为该节点离线,连续三次离线就置故障标志,同时继续轮询下一个节点。

主循环的轮询顺序是这样的:

void poll_remote_node(void) { unsigned char frame[8]; unsigned char response[16]; unsigned char len = 0; build_query_frame(frame, 0x01, 0x03); uart_send_buffer(frame, 6); // 这里假设查询帧固定6字节 len = uart_wait_response(response, 50); // 等待响应,超时50ms if (len >= 7) { unsigned int raw_temp = (response[4] << 8) | response[5]; remote_temp = convert_to_celsius(raw_temp); } else { remote_timeout_count++; } }

这套协议的优点是对单片机资源要求极低,调试时直接用串口助手就能看帧数据。如果项目需要对接标准楼宇自控系统,建议把应用层换成标准Modbus RTU,底层物理层和帧结构基本不用改。

3.5 数据上报与显示

主机在完成本地和远程温度的采集后,除了内部做控制判断,还要把数据送出去。最简单的做法是通过UART以文本格式上报,比如每2秒输出一行:

T1:23.45,T2:26.80,T3:22.10

T1是本机温度,T2是远程节点1温度,T3是远程节点2温度。上位机或调试终端只要按行解析即可,非常直观。如果要接LCD或OLED屏幕,逻辑也类似,把浮点数格式化之后刷到指定区域。另外预留一个运行状态字和传感器在线状态,上位机看到“离线”而不是一个错误温度,这点在实际项目中很重要。

4. 实测数据与运行效果

4.1 本地与远程采集精度对比

硬件调试完成后,我在恒温环境下对本地和远程两路测温通道做了对比测试。用一块经过校准的工业级PT100仪表作为参考标准,读数记录如下(均为稳定后的数值):

工况参考温度PJ85718DM本地PJ85718DM远程绝对偏差
待机22.50°C22.48°C22.51°C≤0.03°C
加热运行45.20°C45.15°C45.26°C≤0.08°C
通风运行16.80°C16.78°C16.85°C≤0.07°C

可以看出,两路传感器在稳定工况下都能把误差控制在0.1摄氏度以内。误差的主要来源是传感器自身精度、板卡温升和环境气流扰动,和远程通信链路关系不大。RS485传输过程只影响数据的完整性,不影响测量精度,只要CRC校验通过,远端读到的数值就等同于本地直接读取的数值。

4.2 通信稳定性与轮询效率

系统里目前挂了两个远程节点,主机每500毫秒轮流查询一次,整轮查询耗时不到100毫秒,剩余时间留给本地采集和显示刷新。以9600波特率运行,连续运行一周的统计结果是:总查询次数约120万次,其中完整应答并校验通过的比例在99.6%以上,剩下的掉帧主要是人为插拔线缆造成的。在HVAC现场这种干扰环境下,这个成功率已经足够实用。

如果后续要接更多节点,可以把波特率提到19200或38400,轮询周期也可以做动态调整。我的建议是先把物理层做稳,再提高轮询频率。总线不稳定时,一味加快轮询只会增加冲突概率。

4.3 长时间运行稳定性

样机在模拟HVAC工况下连续运行了14天,期间每天模拟10次温度变化循环,从25摄氏度升到50摄氏度再到25摄氏度。整机没有出现死机、I2C总线卡死或RS485通信异常需要人工干预的情况。MCU内部看门狗也配置了,但全程没有触发过复位。这说明硬件抗干扰设计和软件超时处理都是有效的。

供电部分,我测过整机输入电压在19V到29V之间波动时,本地和远程读数都没有明显漂移。隔离电源在这中间起到了关键作用,如果直接用一个非隔离的降压模块,电压跌落很可能会把单片机的ADC参考电压拉偏,进而影响温度计算的准确性。

5. 常见问题与排查技巧

5.1 实测踩坑对照速查表

问题现象可能原因解决办法
I2C总线卡死,读不到传感器从机异常拉低SDA,主机等待ACK超时软件里加总线恢复命令(给SCL数个时钟脉冲),或重启后重新初始化
温度数据出现明显跳变电源纹波过大、I2C走线靠近干扰源、滤波不够改善电源滤波,传感器供电独立,软件增加中值滤波
RS485偶尔丢帧或收到乱码总线没有终端电阻、波特率不匹配、屏蔽层接地错误两端加120Ω电阻,确认所有节点波特率一致,屏蔽层单端接地
MCU频繁复位MCLR受干扰、电源跌落MCLR接上拉和滤波电容,电源加隔离和LDO,复位走线远离强电
远程节点离线地址设置重复、线缆断路、节点供电异常检查地址拨码,用万用表量A/B线电压,确认节点电源正常
PLC或上位机读不到温度协议字节序或CRC算法不一致用串口助手抓帧对比,统一为低字节在前,CRC16-Modbus算法校验

5.2 I2C总线卡死的现场处理

I2C总线卡死是最常见的问题,不像RS485那样有明确的帧边界,最容易出现在传感器和单片机电源时序不一致的时候:单片机上电发送读指令,传感器还没准备好,应答超时后总线状态就乱了。我在软件里专门写了一个恢复函数,检测到总线忙时时钟引脚输出9个脉冲,释放被拉住的SDA,然后重新执行初始化。这个技巧不需要额外硬件,就能解决绝大多数总线卡死问题。

现场如果出现彻底无法恢复的情况,我建议查一下上拉电阻有没有焊接错误,以及SDA/SCL是否接反。我遇到过SDA和SCL接反导致读回来的数据完全无规律的情况,那时候查了半天寄存器才发现是物理接错。

5.3 温度读数“看起来正常但就是偏低”

这个坑很隐蔽。传感器虽然放在机柜内,但如果靠近冷风入口或者被大电容、散热片遮挡,测到的温度会低于环境平均温度。判断方法是把传感器和数据记录仪放在同一位置对比,如果偏差是固定的,通常是安装位置问题,而不是传感器精度问题。HVAC工程对温度传感器的安装位置通常有规范要求,例如风管测温要插入到管道断面1/3处以上,而不是贴在管壁外面。嵌入式板卡测温也要避免把传感器放在热风死角,这往往比换更高精度的芯片带来的改善更大。

5.4 远程通信超时与重试机制的优化

远程通信程序里我设置了两个超时层级:单帧接收超时50毫秒,整轮查询超时200毫秒。从机响应慢时,主机不会立刻判定离线,而是连续3次超时才置故障位。这个机制能识别偶发干扰,又不至于把瞬间丢帧误判成设备故障。程序里还记录每个节点的累计掉帧数,便于在现场查看趋势。实测中有一次发现某个节点掉帧率特别高,后来查出来是连接线用了非屏蔽普通线,且和一条变频器输出线平行走了两米。换成屏蔽双绞线并远离动力线后,掉帧率从3%降到了0.1%以下。

最后再分享两个小经验

整套系统做完,我最大的感受是:温度监测这种项目,硬件抗干扰设计比选一颗“更高级”的MCU更重要,软件滤波和协议超时处理比堆功能更重要。PJ85718DM 和 PIC18F47J53 的组合谈不上惊艳,但胜在稳定和够用。如果你也要做类似的嵌入式或HVAC温度采集,建议从架构上先把“本地传感器”和“远程节点”分开考虑,分别解决供电、通信和安装问题,再合到一起联调,这样排查问题时会清晰很多。

最后一个小技巧:给远程节点写固件时,在程序里加一个软件版本号和节点编号,通过RS485回传给主机。现场节点数量一多,这个信息能帮你快速确认线缆有没有接错、固件有没有刷错版本。这种小细节成本几乎为零,但能省下大量现场排查时间。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询