1. 项目要解决的核心问题:本地温度为什么不能当远程温度来用
接到这个项目需求时,客户的要求只有一句话:在嵌入式控制板上测本地温度,同时把远端探头位置的温度也测出来,用于 HVAC 设备联动。听起来简单,可一旦细化到“本地”和“远程”这两个词,工程细节就完全不一样了。距离、线缆、电磁干扰、传感器供电、总线拓扑,每一环都可能让温度数据从“看着对”变成“根本没法用”。
这套方案的核心器件是 PJ85718DM 和 PIC18F85J10。PIC18F85J10 属于高性能 8 位单片机,引脚多、片上外设全,适合作为整个 HVAC 控制器的主控;PJ85718DM 则作为前端温度采集模块,负责规整本地传感器和远程总线传感器。把“采集温度”这件事从前端到主控做成一条清晰通路,后续的显示、风机控制、压缩机启停才有可靠的数据依据。
为什么要特意区分本地和远程?因为两者的电气环境差别很大。本地传感器贴着主板放,线缆短、信号稳,直接用 I2C 或者 SPI 读最快。远程传感器可能部署在风管、室外机、房间角落,线长几米甚至几十米,如果用普通 I2C 拉长线,时序会被线缆电容拖垮,通信错误率猛增。这种场景必须换思路,用带收发驱动、能容忍长线传输的总线方式,或者是带远端地址的传感器节点方案。PJ85718DM 的价值,就是把这些差异封装起来,主控统一通过寄存器去操作,底层协议的变化尽量被屏蔽。
1.1 HVAC 场景里最常见的两组温度测点
结合我实际做过的类似项目,HVAC 设备的温度测点大体可以分成两组。第一组在主板附近,比如控制板进风口温度、电源模块表面温度、通讯模块周围温度。这组测点离 MCU 很近,几厘米到几十厘米,适合用板载传感器或者 I2C 总线上挂着的小封装传感器。第二组则分布在需要被控温的真实环境里,比如回风温度、送风温度、室外环境温度、管道内温度,它们通常位于设备壳体外侧,甚至单独拉线到房间中间去。
第一组测数据的目的多半是保护电子硬件,防止板级过热;第二组才是真正的空调控制依据。在调试现场,我发现很多新手只接了一路回风温度,就把压缩机控制写死了,结果送风温度没检测,冬天热风直接把房间烤过头。设计架构时,至少要预留两路以上远程测点,而且远程通道要具备扩展能力,方便后续增加探头。
用 PJ85718DM 做前端管理的好处是,它天然自带多通道采集逻辑,把本地传感器的轮询和远程传感器节点的地址管理放在一个模块里,主控不需要频繁中断去处理位时序。这样在 HVAC 主循环里,温度刷新可以做到毫秒级稳定,不太影响其他控制任务。
1.2 PIC18F85J10 和 PJ85718DM 各自承担什么角色
PIC18F85J10 这颗片子,最大的优势是资源均衡。它有充足的外部引脚,可以同时接 PJ85718DM 的数字接口、LCD 显示、按键、风机调速 PWM、继电器控制,预留 UART 口做通讯调试也不显得拥挤。片上自带多个定时器和硬件串行外设,不需要全部用 GPIO 模拟时序。如果换成一颗小封装单片机,引脚规划和中断优先级就会很痛苦,HVAC 这种需要多种外设协同的场景很容易翻车。
PJ85718DM 在我这里扮演的是“采集前端”的角色。它可以连接若干个本地数字温度传感器,同时管理一条远程传感器总线,把不同物理位置的传感器统一编址。主控只需通过标准寄存器接口下发指令,比如“读取 2 号通道温度”,PJ85718DM 内部就会完成启动转换、等待读数、错误重试,最后把结果放到数据寄存器里。主控利用 I2C 或 SPI 把数据取回来就行。
这种“主控+前端”的分工,比让主控直接操作一堆传感器更稳。主要原因在于,主控的工作负担不只是读温度,还要跑 PID 算法、处理通讯协议、驱动继电器,如果把传感器时序细节都堆到主控里,一旦线缆干扰导致时序重试,主控实时性就会崩。PJ85718DM 挡在中间,脏活累活它干了,主控只拿到干净的结果。
2. 硬件链路搭建:主控、PJ85718DM、传感器三者怎么接
2.1 系统拓扑结构
整体链路设计上,我分了三层。最底层是传感器层,包括板边沿的本地传感器和多处远程探头;中间层是 PJ85718DM,负责采集和总线调度;最顶层是 PIC18F85J10,负责控制逻辑与人机交互。
链路的物理连接大致是这样:PIC18F85J10 通过一组 SPI 或 I2C 与 PJ85718DM 连接,这属于主控与前端模块之间的高速内部总线。PJ85718DM 向下,本地传感器接入其 I2C 扩展口,远程传感器则接到它的串行总线接口上。远程总线上可以挂多个地址不同的探头,具体数量由 PJ85718DM 的地址空间决定,实际项目中我通常挂 4~8 个,太多会增加轮询周期,降低实时性。
有一点要明确:PJ85718DM 承担的是“采集并整理”,PIC18F85J10 承担的是“决策并使用”。温度数据不是拿来显示的,而是用来风机调速、压缩机通断、报警输出的。因此软件上必须把温度读取函数设计成同步阻塞还是异步轮询,要提前想清楚。我建议用轮询方式,因为采集周期本身只有几十毫秒,在 HVAC 这种毫秒级控制场景里,阻塞几百微秒完全可接受,状态机反而能简化。
2.2 电源、上拉电阻与布线规范
硬件布线是整个项目里看似不起眼、实际上最容易出问题的部分。PJ85718DM 和传感器的供电,我建议统一用 3.3V 稳压轨,前提是传感器本身支持 3.3V。远程探头如果距离长,则需要考虑线上压降,必要时用 5V 供电、信号接口加电平转换。远程传感器在现场经常遇到的问题是供电不足导致转换结果偏移,不是传感器坏了,而是远端电压跌到了传感器的最低工作电压以下。
总线电阻方面,本地 I2C 接口上拉电阻我习惯选 4.7kΩ 到 10kΩ,这要看挂载数量。但远程总线延长之后,线缆电容会变大,4.7kΩ 上拉带来的上升沿可能不够,换成 1kΩ~2.2kΩ 通常会改善。不过上拉太小会增加静态功耗,长线反射和振铃也可能出现,需要示波器实测。我在自动化测试平台实测过,15 米双绞线、2.2kΩ 上拉、波特率 9600,波形还比较干净;如果波特率拉到 38400 以上,远端设备基本就很难稳定同步。
在 PCB 布局上,建议把 PJ85718DM 靠近 PIC18F85J10 放置,中间信号线不要太长,避免高速 SPI 信号形成环形天线。传感器走线远离继电器和压缩机驱动电路,尤其是感性负载切换时会产生高压尖峰,地线处理不好会把温度数据干扰得跳来跳去。输出级加 RC 吸收或者压敏电阻,传感器走线加磁珠隔离,这些措施对 HVAC 现场设备来说不是可选项,是必要项。
2.3 关键引脚分配参考
具体引脚分配上,每个项目会有差异,但大的思路是一致的。我提供一个实际用过的规划作为参考:PIC18F85J10 的 SPI 片选接给 PJ85718DM,作为模块的唯一控制入口;另一组普通 GPIO 用于 PJ85718DM 的中断输出和复位控制。本地传感器如果挂在 PJ85718DM 的 I2C 通道上,这个通道仅限板内,不延伸出去;远程总线则单独占用一组带收发器驱动的 UART 或者专用 1-Wire 端口,具体看传感器类型。
主控侧的 PWM 通道预留至少两路,一路给风机,一路备用水泵或电加热,不要在后期才想起没有多余 PWM。LCD 显示可以用并行或 SPI 方式,能省引脚就省引脚。所有预留的 UART 至少留一个给调试器用,这在后期排查问题时能省大量时间。
3. 软件驱动实现:初始化、读取、换算和出错重试
3.1 PJ85718DM 寄存器操作流程
PJ85718DM 对外的工作方式,我按寄存器来理解,上手会很快。模块内部主要有控制寄存器、状态寄存器、数据寄存器、地址配置寄存器几类。操作流程通常是这样:先通过 SPI 写控制寄存器,选择要读取的通道并启动温度转换,然后轮询状态寄存器,看转换是否完成,完成后读取数据寄存器的高低位。如果是远程多通道节点,还需要先写通道地址,再发出读取命令,等待节点返回结果。
给一段我实际调试过的初始化代码框架,可以直接作为参考模板:
#define PJ_CS_PIN LATBbits.LATB2 #define PJ_SPI_CLK LATBbits.LATB1 #define PJ_SPI_SDO LATCbits.LATC6 void pj_write_reg(uint8_t addr, uint8_t val) { PJ_CS_PIN = 0; spi_write_byte(PJ_CMD_WRITE | addr); spi_write_byte(val); PJ_CS_PIN = 1; __delay_us(10); } uint8_t pj_read_reg(uint8_t addr) { uint8_t tmp; PJ_CS_PIN = 0; spi_write_byte(PJ_CMD_READ | addr); tmp = spi_read_byte(); PJ_CS_PIN = 1; return tmp; }初始化阶段,我习惯先复位模块,然后读取模块 ID 寄存器,确认通信建立正常。这一步一定要做,很多看似“传感器读数不对”的问题,其实是主控和前端模块之间的 SPI 时序都没对齐,地址和数据全都错位。读模块 ID 等于给整套通信链路做一个心跳检查,虽然浪费几个毫秒,但能大大缩短硬件排错时间。
读取温度的逻辑我封装成了独立函数,返回原始值和处理后的温度值。主控主循环里只管调用这个函数,不用关心底层时序。每轮采集结束,把数据放到公共变量区,供显示刷新和控制算法使用。
3.2 温度数据解码与线性换算
不同的温度传感器,原始数据格式会不一样。比较常见的是 12 位二进制补码,单位为 0.0625°C,高位字节在前,低位字节在后的组织方式。真实温度的计算公式是这样:
实际温度 = (原始值 >> 4) × 0.0625°C,当原始值为负数时,需要按补码先取反再加 1,再换算。
用代码表示:
float temp_raw_to_celsius(int16_t raw) { float t = (float)raw * 0.0625f; return t; }在 HVAC 控制里,这个 0.0625°C 的精度基本够用。现场控制精度要求通常在 ±0.5°C 以内,毕竟空调系统本身的滞后效应很大。如果对精度要求更高,可以做两点校准。把传感器放在冰水浴和沸水浴里记录原始值,然后建立线性校正公式,把偏移和斜率修正到代码里。批量生产时,每个通道的校准参数建议存储在外部 EEPROM 或 PIC18F85J10 的数据 EEPROM 里,这样换板不换探头,校准值不丢。
这里要说个容易被忽略的点:温度换算结果不要频繁做浮点运算。主循环每 100ms 读一次温度,每次都做浮点换算,虽然单个耗时不大,但累积起来会影响其他实时任务。我的做法是先把原始值保存下来,只在显示和控制计算时再做一次换算,中间过程尽量用整数运算。
3.3 数据校验与异常值剔除
温度和电流、电压不同,它的变化趋势是缓慢的,正常情况下相邻两次采样之间的差值不会很大。利用这个特点,可以做一个简单的异常值剔除:如果某次采样值和上一次数值之差超过阈值,比如 5°C,先不要立刻采用,而是连续再读两次,两次结果互相接近才采信,否则上报传感器故障。
这种软件滤波在 HVAC 现场特别管用。工业环境里,变频器、接触器吸合瞬间会产生强烈的电磁干扰,传感器线如果恰好靠近动力线,ADC 转换结果就可能出现毛刺。做过一次软件滤波之后,毛刺对控制逻辑的影响能降到很低。虽然 PJ85718DM 本身带有一些数字滤波能力,但双保险总归没坏处。
远程探头返回超时也是常见问题。PJ85718DM 在内部会做重试,但主控也应当在规定时间内没有得到结果时,把该通道标记为故障,而不是一直死等。在 HVAC 设备中,某个探头掉了不能导致整机停机,正确做法是转用备用传感器或固定输出一个安全温度值,保证压缩机不会因为缺数据而误判断。
4. HVAC 控制逻辑:把温度值变成执行器动作
4.1 滞后比较实现风机与压缩机控制
温度采集只是手段,控制动作才是目的。HVAC 控制里最常用的一招是滞后比较,也叫回差控制。假设制冷模式下回风温度目标值是 25°C,如果探头测得 26°C 就启动压缩机,降到 24°C 才停止,那这中间 2°C 的回差可以避免压缩机频繁启停。
直接用代码判断:
#define TARGET_COOL 25.0f #define HYSTERESIS 2.0f if (temp_room > (TARGET_COOL + HYSTERESIS / 2.0f)) { comp_on(); } else if (temp_room < (TARGET_COOL - HYSTERESIS / 2.0f)) { comp_off(); }这类逻辑用文字描述很容易,但放到真实设备里要结合多个温度源。我认为制冷模式至少要看回风温度和蒸发器管温,回风温度决定压缩机是否运行,管温用于防止蒸发器结霜。如果只靠单一探头,夏天高湿环境很容易把蒸发器冻住,然后冷风送不出去,房间温度根本降不下来。PJ85718DM 的多通道能力在这里就体现出来了,一个模块接多路探头,主控算法可以综合判断。
风机的转速也可以根据温差做无级调节。温差大时风机高速运转,温差接近目标时降速,既省电又安静。具体的调速曲线,我建议现场实测调整,先把采集到的温度通过串口打出来,再对照设备实际风速决定占空比映射。想一次性调出一个完美的 PID 参数很难,从滞后控制和分段控制起步是更稳妥的做法。
4.2 远程探头故障时的降级策略
投运一段时间后,远程探头损坏是必然事件,不是会不会坏,而是什么时候坏。每路远程通道在软件中都应当有健康状态标志位。主控读取失败若干次后,将故障探头的温度值替换成备用通道数值,或者用最近一次有效值冻结。
如果所有远程探头同时故障,HVAC 设备要进入强制保护模式。压缩机如果继续工作而没有温度反馈,可能导致蒸发器结霜或冷凝器压力过高。实际项目中我见过因为探头脱落,压缩机硬生生把空调冻成冰坨的情况。所以故障降级的底线是:宁可停机,不要瞎运行。控制逻辑里必须有明确的“无有效温度数据则停止相应执行器”分支,这是安全优先级最高的一条,不能因为担心误停机而不跳转。
5. 实测记录:架构调整前后对比,以及需要注意的事项
5.1 第一版方案的失败教训
刚开始我图省事,让 PIC18F85J10 直接通过 I2C 去读板外的所有远程传感器,传感器节点用手工搭的电路,没有经过 PJ85718DM 统一管理。样机在实验室里跑得很欢,一到现场就出问题。客户现场的强电柜距离设备不到两米,线缆长度接近十米,I2C 时钟信号变形严重,数据读取经常超时,偶尔还会读出一会儿 15°C、一会儿 85°C 这种跳变值。
后来把架构改成现在的样子,远程传感器统一接到 PJ85718DM 管理的总线上,模块本身承担了波形成型和重试工作,主控只从模块寄存器取结果。再把传感器走线重新规划,避开动力线,加了屏蔽层,通信稳定性和读数一致性立竿见影。实测连续运行三天,温度波动基本保持在 0.2°C 以内,实验室和现场的数据基本一致。
这里也反映出一个经验:嵌入式系统实验室环境过得太顺,往往是因为没有真实干扰源。温度采集这类对噪声敏感的功能,必须在带负载、带线缆的条件下测试,而不是只测一块裸板。
5.2 优化前后的数据对比观察项
我整理了几项最重要的实测观察点,落地项目时可以按这个思路去做验证:一是在满载和空载两种工况下分别读取本地与远程温度,确认读数不随供电波动乱跳;二是人为拔掉一路远程探头,确认故障标志在 3 秒内能上报;三是用示波器观察远程总线波形,确认波特率和上拉匹配合理;四是长时间运行监控温度曲线的连续性,不能有周期性毛刺。
用这批指标跑数据,整套系统是否可靠会有一个非常直观的判断。不要只看某一次的绝对值,反而要关注变化趋势和跳变概率。温度采集系统真正难的不是测准一次,而是连续几个小时稳定可复现。哪个通道偶尔跳一下、哪个通道线一松就复位,这些才是真问题。
6. 常见问题与排查表
6.1 现场常见故障速查
| 现象 | 可能原因 | 检查与处理办法 |
|---|---|---|
| 本地温度正常,远程全部无数据 | 远程总线供电缺失、收发器方向控制错误 | 用万用表测探头端电压,确认总线使能引脚电平正确 |
| 单个远程通道读数跳变 | 接头氧化、线缆过长、上拉电阻不匹配 | 重新压接端子,缩短线缆,改用双绞屏蔽线并降低波特率 |
| 读到的温度始终为固定值 | 传感器已损坏或总线地址冲突 | 确认传感器地址有无重复,用模块自检命令单点读测 |
| 压缩机频繁启停 | 温度更新周期太慢或回差设置过小 | 缩短轮询周期,扩大回差,或者加入数据平滑 |
| 上电后 PJ85718DM 通信失败 | SPI 相位极性配置错误、复位时序不满足 | 对照模块手册确认 SPI Mode,检查复位引脚时序,示波器抓波形确认 |
这套速查表基本把我在现场遇到的高频问题都覆盖了,适合直接打印出来当调试小抄。很多问题表面上是传感器坏了,实际是通信配置和现场线缆布局的问题,优先排查链路,再怀疑器件本体。
6.2 依我来看,最终必须避开的坑
主要在几个地方。第一,远程传感器线径不要太细,24AWG 以上的屏蔽线是底线,太细的线不仅压降大,抗干扰能力也弱。第二,主控和前端模块之间不要用杜邦线长期跑,调试可以,产品阶段必须用焊接或者压接;杜邦线氧化后接触电阻增大,偶尔会出现随机通信错误,排查起来极其痛苦。第三,不要在设计里把所有通道都当成必须在线,一定要预设探头故障路径,否则现场任何一个探头失效,整套设备都会跟着出问题。第四,温度校准不要只在室温做一次,最好能在低温、常温和高温三个点做校验,确认传感器在量程内没有明显非线性。
PIC18F85J10 的看门狗配置也值得一提。HVAC 设备要求长期无人值守运行,看门狗必须开启,而且看门狗超时后要能把故障状态记录下来。温度采集模块如果在看门狗复位后没有重新初始化,会一直报错。我习惯把“模块重新初始化”写进复位向量后的自检流程里,这样即使系统被杀掉重启,整个采集链也能快速恢复。
做这套系统最大的体会就是:温度监测不是功能,是所有 HVAC 控制决策的地基。地基想打稳,前端采集模块要分担复杂度,主控要留足资源,软件要提前考虑异常降级。按照这个思路,用 PJ85718DM 配合 PIC18F85J10 去搭,整个项目的稳定性和可维护性都会比临时拼的电路好很多。如果后续想扩到更多测点,或者改成无线采集,这套框架的接口划分也能平滑过渡,不需要推翻重来。