搞热泵、新风机组或者机房空调的朋友,应该都有过这种经历:控制柜里主控板正常工作,但上位机看到的温度数据总是慢半拍,或者干脆飘得离谱。问题的根源往往不在传感器本身,而在“本地采集”和“远程上传”这两条链路没有统筹设计。我最近在折腾一个楼宇自控类的改造项目,就用 PJ85718DM 搭配 PIC18F85J10,把嵌入式控制器里的本地温度监测和 HVAC 末端的远程温度回传一起做了。这篇文章就把这套方案的选型逻辑、接口设计、通信协议和实际踩坑记录完整写出来,给准备做类似温度监测系统的朋友一个可以直接抄的参考。
先交代一下背景。HVAC 系统里,温度监测点通常分成两类:一类是控制器自身附近的本地温度,比如主控箱内温度、回风温度;另一类是需要走线到远端的风道温度、水管的供回水温度、或者多个风机盘管支路的区域温度。本地温度可以直接挂在 MCU 的引脚上,远程温度就得考虑总线布线、节点供电、抗干扰和故障隔离这些问题。我选的 PJ85718DM 是一款数字温度传感器,负责把温度物理量变成数字信号;PIC18F85J10 则负责采集、处理、联动控制和远程通信。整个方案跑下来,稳定性不错,调试过程中也积累了不少经验,下面一条条拆开讲。
1. 方案整体设计与选型逻辑
1.1 HVAC 温度监测的两种距离要求
先别急着看传感器型号,得先想清楚本地温度和远程温度的物理差异。
本地温度监测,传感器到主控板的距离一般不超过几十厘米,信号是点对点的,干扰源主要来自电源纹波和主控板自身的数字开关噪声。这种情况下,传感器选型最自由,用 NTC 热敏电阻加 ADC 也行,用数字传感器更方便。
远程温度监测就完全不一样了。传感器分布在天花板风道里、水管保温层里、或者新风机组的表冷器旁边,布线长度从几米到几十米不等。这时候要考虑三个问题:一是传感器供电怎么解决,二是在强电、变频器、风机电机附近怎么保证信号完整,三是某个传感器短路或者断路的时候,不能把整条总线拖死。
我最终选择的架构是这样的:本地温度传感器就近挂在 PIC18F85J10 的专用接口上,远程传感器则通过抗干扰能力更强的总线方式挂载,每个节点分配独立地址,主控板周期性轮询。这样布线简单,扩展也容易。
1.2 PJ85718DM 的特征与选型原因
PJ85718DM 从型号命名和封装特征来看,属于典型的工业级数字温度传感器,常见的封装形式支持贴片焊接,适合直接设计到 PCB 上,也适合做成小探头延伸到被测位置。
这类传感器最大的优点是已经把“模拟信号调理 + 模数转换 + 数字通信接口”集成在一起。和传统的 NTC 方案相比,省掉了分压电阻、滤波电容、ADC 基准源这些外围电路,更关键的是省掉了“校准”这一步。NTC 因为个体差异,每批料都需要做分压曲线校准,工厂量产的时候非常麻烦;而数字传感器出厂前已经做了校准,精度参数标注明确,软件里直接读寄存器就能拿到温度值。
在 HVAC 这种温差变化相对平缓的场合,PJ85718DM 的转换精度和分辨率完全够用。我实测下来,静态环境下的读数重复性很好,不会出现同一温度点两次采样偏差很大的情况。
提示:选数字温度传感器的时候,不要只看精度参数,还要关心转换时间。有些传感器的最高分辨率档位需要在位转换上花几百毫秒,在实时性要求高的控制回路里可能不够用,后面我会详细说我在这块的处理方案。
1.3 PIC18F85J10 在系统中的角色定位
PIC18F85J10 是 Microchip 的 8 位 PIC 单片机,80 引脚,内部资源丰富。我选它,主要看中几点。
第一是自带 ECAN 模块。这意味着做远程通信的时候,不需要外挂独立的 CAN 控制器芯片,直接用 MCU 内置的 CAN 外设就能组网。第二是多个串口可以并行工作,一路跑 CAN 总线处理远程温度,另一路跑 UART 和触摸屏或者上位机调试通信,互不干扰。第三是引脚数量足够多。除了接温度传感器和通信接口之外,还能留出足够的 I/O 去驱动继电器控制风机、水泵、电加热器。
在系统里,PIC18F85J10 就是个“采集 + 决策 + 分发”的中间层角色。它把本地温度挂在脚下,把远程温度通过总线拉回来,跑一遍滤波和控制算法,然后输出 PWM 或者继电器信号去驱动执行机构,同时把数据打包成协议帧,丢给更上层的协调控制器。
有人可能会问,为什么不用 32 位单片机?如果只是做温度采集,确实用不上 32 位,但 HVAC 里除了温度还有湿度、压力、水流量这些参数要处理,8 位机在成本、功耗、开发难度和长期供货稳定性上有天然优势。PIC18F85J10 的性能对这类应用来说属于“够用就好”的典型代表。
2. 传感器连接与本地温度的采集实现
2.1 数字接口方式如何选
PJ85718DM 这类传感器,数字接口常见的是 I2C 和单总线(1-Wire)两种。我的建议是:本地温度用单总线,远程节点用 I2C 或者单总线都可以,但要加总线驱动电路。
单总线的最大好处是节省引脚。一根数据线既能供电(寄生供电模式)又能传数据,适合在长线上挂多个传感器。但单总线的时序要求比较严格,读写时序都需要在微秒级别精确控制,如果用不擅长精确延时的开发环境,或者系统里有繁忙的中断服务程序,就很容易出现时序被破坏的情况。
I2C 的优势是有两个引脚(SCL/SDA),通信有应答机制,时序相对宽裕,程序写起来不容易出错。缺点是在长距离传输的时候,总线电容过大,如果上升沿太慢,通信就会出错,一般建议加 PCA9600 之类的 I2C 总线缓冲器,或者在每个节点上降低上拉电阻阻值。
我在这个项目里,PJ85718DM 都跑在单总线模式下,原因很朴素:节省 MCU 引脚,而且传感器的内部寄存器可以直接寻址,不需要额外的地址引脚,硬件上省事。
2.2 驱动时序与软件实现要点
单总线协议看起来简单,但真正写驱动的时候有几个关键细节。标准的单总线时序包括复位脉冲、存在脉冲、写时序和读时序,所有的时序都以时间槽为单位。以常见的约定为例:
- 复位:主机拉低总线 480us 以上,再释放总线,传感器会在 15~60us 之后拉低总线 60~240us 表示存在。
- 写 1:主机拉低总线 1~15us 后释放,整个时间槽约 60us。
- 写 0:主机拉低总线 60us 后释放,整个时间槽约 60us。
- 读时序:主机拉低总线 1~15us 后释放,并在 15us 内采样总线电平。
PIC18F85J10 的指令周期和延时计算需要根据晶振频率仔细算。我用的是内部振荡器,配置好之后,写了一个简单的延时函数,每个时间槽通过 NOP 指令做微调。
注意:单总线对延时精度很敏感,尤其是读时序的采样窗口。我调试的时候发现,如果延时函数里插入了中断处理,读回来的数据就会偶发错乱。解决办法是在读时序期间暂时屏蔽可能抢占 CPU 的中断,或者把传感器驱动放到最高优先级中断里处理。
下面是我在项目里用的一段简化驱动核心逻辑(C 语言描述),主要演示单总线读时序的状态机思路:
// 单总线读一个字节 uint8_t onewire_read_byte(void) { uint8_t res = 0; for (uint8_t i = 0; i < 8; i++) { res >>= 1; if (onewire_read_bit()) { res |= 0x80; } delay_us(60); // 完整时间槽 } return res; } // 单总线读一个 bit uint8_t onewire_read_bit(void) { uint8_t val = 0; OW_DIR = OUTPUT; OW_OUT = 0; delay_us(2); // 拉低起始 OW_OUT = 1; OW_DIR = INPUT; // 释放总线 delay_us(5); // 在采样点之前等待 val = OW_IN; // 采样 delay_us(50); return val; }这种软件模拟的方式优点是灵活,缺点是占 CPU 时间。对于温度采集这种低频操作,完全够用。如果以后要接几十个传感器,建议改用硬件单总线控制器或者专用芯片。
2.3 转换精度与速度的取舍
PJ85718DM 这类数字传感器的配置寄存器里,一般都有一段用来设置转换分辨率。以常见的 9 位到 12 位可调为例:
- 9 位分辨率:转换时间最快,约 90ms 以内。
- 12 位分辨率:转换时间最长,往往超过 700ms。
HVAC 的温度控制,变化速率本身就不快。风道里的温度传感器,就算分辨率低一点,反应也不会差太多。但有个例外:供回水温度,特别是冬天供热工况下的供水温度,如果传感器采样间隔太久,PID 控制器很容易产生超调,温度冲到 60°C 才反应过来,然后阀门来回震荡。
我的做法是:所有温度默认用 12 位分辨率,但根据传感器的安装位置做区分。风道温度、室内空气温度这种慢变参数,不追求高频率更新,甚至可以 1 秒采一次;水管温度和水箱温度,虽然也不快,但是因为参与 PID 调节,要求每次采样的有效性更高,所以我会在转换完成后再读一次,确保数据是新鲜的,不要读上一次转换的缓存。
这个细节在调试 PID 的时候体现得特别明显。你如果发现调节曲线一直有规律的波浪形,往往不是 PID 参数的问题,而是采样数据本身有延迟。
3. 远程温度的通信链路与协议设计
3.1 为什么选择 CAN 而不是 RS-485
远程温度节点,我在方案设计的时候对比过 RS-485 和 CAN 总线,最后选了 CAN。核心考量有三点。
第一是物理层抗干扰。HVAC 现场最大的干扰源就是变频器和感性负载(风机电机、水泵电机),RS-485 虽然可以通过屏蔽双绞线和终端电阻改善,但在长距离走线接近变频器输出线的时候,仍然可能出现共模干扰导致的误码。CAN 的差分信号本身抗共模能力强,而且带有 CRC 校验和错误检测机制,链路出错会自动重发,可靠性明显高。
第二是多主机能力。RS-485 通常是一主多从结构,主机轮询从机,如果主机出问题,整个网络就瘫痪。CAN 网络理论上每个节点都能主动发数据,虽然我在这个项目里依然是单主轮询,但以后扩展的时候,节点可以主动上报异常,不需要占用主机资源。
第三是 PIC18F85J10 自带 ECAN 模块。硬件上省掉了一颗外置 CAN 控制器,成本降低,可靠性反而提高。
远程节点的结构差不多是这样:每个远程温度节点由一颗 PJ85718DM 负责采集温度,通过一颗小 MCU(或者带 CAN 接口的专用传感器节点芯片)把数据打包成 CAN 帧,通过屏蔽双绞线挂到总线上,主控板通过 PIC18F85J10 的 ECAN 外设周期性发远程帧请求。
3.2 帧格式与节点地址规划
CAN 2.0B 的扩展帧共有 29 位标识符,我实际用的时候只用了标准帧 11 位,完全够用。帧格式设计得很简单:
- ID[10:8]:功能码。0 表示读取温度请求,1 表示温度数据响应,2 表示节点状态。
- ID[7:0]:节点地址。0x00 为广播地址,0x01~0xFE 为具体节点地址,0xFF 保留。
数据段格式固定为 8 字节:
- 字节 0:温度整数部分(有符号数,单位 °C)。
- 字节 1:温度小数部分(精度 0.01°C)。
- 字节 2:传感器状态位,Bit0 表示转换完成,Bit1 表示传感器断线。
- 字节 3:预留,值为 0xFF。
- 字节 4~7:可以为后续湿度、压力等传感器预留。
Node ID 的分配我不是用拨码开关,而是做成“首地址 + 自动递增”的方式。主控板第一次上电的时候,发送广播帧要求所有节点报告自己的序列号,然后按照序列号从小到大分配地址。这样做的好处是生产的时候不需要人工拨码,不会因为拨码错误导致两个节点冲突。
3.3 远程节点的低功耗与唤醒策略
远程温度节点如果做成分体式设备,可能会用电池供电或者从被监测设备上取电。如果从设备取电,比如风机盘管的控制电源,那么 24V AC 转 3.3V 的电源设计得稳一点就行。如果是电池供电,低功耗策略就是大头。
我实测过的休眠策略:节点每隔 5 秒唤醒一次,读温度,然后进 CAN 总线监听模式。如果总线没有请求,继续睡;如果收到主机的点名请求帧,就立刻把温度数据发回去,再继续睡。这个策略下,节点平均功耗可以做到很低。
具体实现上,有一个坑:PJ85718DM 从休眠状态唤醒到转换完成,需要等待传感器内部的振荡器稳定。如果节点一被唤醒就立刻转换,前几次读出来的温度可能会比实际温度偏大。我的解决办法是:唤醒后先不转换,等待 100ms,再启动转换;或者干脆上一次转换的数据缓存下来,先发缓存数据,同时启动新一次转换,下次请求再发新数据。
注意:不要小看这 100ms 的启动等待。如果远程节点很多,主机按顺序轮询,每个节点都多 100ms,60 个节点就是 6 秒,控制系统的响应会变得很迟钝。解决方案是:主机轮询的时候分两轮,第一轮只发请求帧,每个节点收到请求后先回一个 ACK,第二轮再收集温度数据,这样总线上等待时间就摊开了。
4. HVAC 联动控制与关键算法
4.1 温度采样滤波与数据可信度判断
原始温度一旦采集回来,理论上可以直接用于显示,但 HVAC 控制不能直接用原始数据。因为压缩机和风机启停的时候,电流变化会引起电源波动,温度读数会出现毛刺;风道里的温度传感器还会受到冷热气流扰动的影响,瞬时值波动比较大。
我用的滤波策略分成两级。第一级是滑动中值滤波:取最近 5 次采样值,去掉最大最小,取中间 3 个的平均。这个办法对付毛刺很有效,而且响应延迟不大。第二级是一阶低通滤波,公式很简单:
T_filtered_new = T_filtered_old * (1 - alpha) + T_sample * alpha其中 alpha 的取值决定了滤波的平滑程度。alpha 太大,噪声滤不掉;alpha 太小,剧烈的温度变化被拉平,控制滞后又太大。我实测下来,alpha 取 0.2 到 0.3 比较合适,对应的时间常数大约 5~10 秒,既能滤掉气流扰动,又不至于让 PID 觉得“温度老变”。
除了滤波,数据可信度判断是这个项目里我觉得最有价值的地方。每个温度节点在 ROM 里存了“初始偏差校准值”和“工作范围上限/下限”。如果当前温度超过上限或者低于下限,主控板会标记该传感器“异常”,并且不再参与控制,改用相邻传感器的平均值替代。这个机制在冬季供暖项目里特别重要,一旦某个水管传感器冻裂,控制逻辑不会把电动阀开到最大,避免系统崩溃。
4.2 温差控制与 PID 参数整定
HVAC 控制里,直接控温度不如控温差。比如说,冬季供热的时候,回风温度 20°C,送风温度如果因设备效率变化而波动,直接控送风温度会导致控制目标漂移。我采用的控制逻辑是:
- 计算送风与回风温差 DeltaT。
- 设定目标温差值,比如 8°C。
- 用 PID 调节电动阀开度或者风机转速。
这种方式的好处是:当室外温度变化引起热负荷改变时,温差控制能自动跟随,不需要人工重新设定目标温度。
PID 参数方面,我用的是增量式 PID,输出的是开度增量,而不是绝对开度。这样做的原因是:风机盘管的电动阀一旦断电或者重启,如果输出绝对开度,很容易出现阀门位置丢失、控制跳变的问题。增量式只改变相对量,执行机构的位置可以慢慢逼近,系统更稳定。
增量式 PID 的核心代码逻辑比较简单:
float pid_incremental(float error) { float delta = Kp * (error - error_prev) + Ki * error + Kd * (error - 2.0f * error_prev + error_prev2); error_prev2 = error_prev; error_prev = error; return delta; }这里的 Kp、Ki、Kd 我没有用一些复杂的整定软件去算,而是从工程经验起步:Kp 先给一个能产生稳定响应但不振荡的数值,Ki 慢慢加,Kd 尽量小。因为温度系统是大惯性系统,Kd 太大反而容易引入噪声和高频抖动。
4.3 传感器断线、短路与失效保护
温度传感器在 HVAC 现场是最容易损坏的部件。要么是被老鼠咬断线,要么是接线端子进水腐蚀导致短路,要么是 PCB 焊盘在振动环境下开裂。软件层面必须对每一种失效模式做好预案。
断线的情况最容易识别。单总线设备在总线被拉高的时候如果检测不到存在脉冲,基本就是断线了。I2C 设备如果从机不回应 ACK,也能判断链路异常。但短路的情况比较隐蔽,表现为读出来的温度数值是一个固定的异常值,比如 0xFF 字节,或者温度直接跳到 -127°C。这时候滤波算法会把异常值滤掉,但控制逻辑不能无视,必须立刻上报。
我设计的状态机是这样的:
- 正常状态:持续更新时间戳,每 5 秒刷新一次。
- 超时状态:超过 3 个周期没有收到有效数据,标记为“可疑”,控制逻辑改用备份传感器数据。
- 失效状态:连续 5 分钟异常,标记为“失效”,在触摸屏上显示红色告警,同时把该节点的控制参数切换到安全默认值。
安全默认值需要根据现场情况单独设,比如供水温度失效,就把电动阀开到 50% 开度;送风温度失效,就把风机频率降到 60%。原则是:宁可舒适度差点,也不能冻裂水管或者把设备烧了。
5. 实测过程中的问题与排查心得
5.1 传感器读数漂移的元凶:电源和地线
调试第一版样机的时候,主控板上的温度和热电偶温度计对比,发现读数整体偏高了 1.2°C 左右。一开始怀疑是传感器精度问题,后来用示波器测了传感器供电引脚,发现有 50mV 左右的高频纹波。手头没有低噪声 LDO 的时候,我是加了一个 10uF 陶瓷电容和 0.1uF 高频旁路电容解决的。
这里有个容易被忽略的细节:数字温度传感器的电源如果来自 DC-DC 开关电源,纹波抑制做的不好,转换结果会因为内部比较器的参考电平波动而产生偏移。解决思路不是盲目加滤波电容,而是先量纹波,分清是低频还是高频,再去针对性选电容。100Hz 的低频纹波,10uF 独石电容没什么效果,要加电感或者换低纹波电源。
另外,单总线长线接地问题也踩过坑。远程节点通过屏蔽双绞线连接,屏蔽层如果只在主机端单端接地,现场长线末端的地电位和主机地电位之间存在电势差,传感器读数会周期性跳动。后来改成屏蔽层两端都接地,并且尽量让数据线和地线双绞,这种跳动立刻消失了。
5.2 CAN 总线通信偶发失败的排查
远程温度数据偶尔丢帧,是个特别让人头疼的问题。CAN 总线本身有重发机制,但重发会占用总线带宽,如果总线上挂的节点多了,连续重发可能导致整个网络瘫痪。
我的排查步骤:
- 双端接上 120 欧姆终端电阻,测量差分电阻,确认是 60 欧姆左右。如果电阻不对,说明有节点脱落或者线路断了。
- 用示波器看 CAN_H 和 CAN_L 的电平。静态时候应该是 2.5V 左右,显性电平差 2V 左右。如果负压过头,说明共模电压超标。
- 检查每个节点的 CAN 收发器,是否有节点在总线繁忙时错误地拉低总线。
最终发现的问题是:有一个节点的 CAN 收发器供电用的是 3.3V LDO,但这个 LDO 的输入来自 24V 开关电源,瞬间负载变化导致 3.3V 跌落,CAN 收发器进入欠压保护,直接把总线拉住了。解决方法是换了一个带使能脚的 LDO,并且在节点电源入口加了 TVS 二极管,防止总线上的浪涌倒灌。
5.3 EMC 干扰导致温度跳变
有一次在现场调试,设备一启动变频器,远程温度节点就开始乱跳。后来发现原因不在传感器,也不在总线,而是变频器启动瞬间,强电线缆和传感器数据线在同一个线槽里,电磁感应把高频噪声耦合进来了。
处理办法有三种组合使用:
- 数据线换成屏蔽双绞线,屏蔽层良好接地。
- 传感器探头远离变频器输出线,至少留 20cm 距离。
- 在传感器的开关量输出或者模拟量输出口(如果支持)加 RC 滤波。
还有一个物理隔离的办法是改用光纤做远程通信,但成本较高,我只在最关键的传感器节点上用了。
5.4 快速排查清单
| 现象 | 可能原因 | 排查步骤 | 解决办法 |
|---|---|---|---|
| 读数整体偏高 | 电源纹波大 | 示波器量 VDD | 加旁路电容或换 LDO |
| 读数周期性波动 | 地电位差 | 量两端地电位 | 屏蔽层双端接地 + 双绞线 |
| 单总线偶发通信失败 | 中断抢占时序 | 关中断读时序 | 读时序期间屏蔽中断 |
| CAN 丢帧 | 节点欠压 | 量各节点供电 | 加 TVS + 换 LDO |
| 温度跳变较大时伴随设备启停 | EMC 干扰 | 检查线缆布线 | 换屏蔽线 + 物理隔离 |
| 远程节点唤醒后数据偏差大 | 唤醒时间不足 | 示波器看唤醒格 | 延长唤醒等待时间 |
这个排查清单在我后续维护另一套系统的时候直接复制过去了,基本上能覆盖 80% 的现场问题。如果你在实际调试中也碰到类似问题,先按这个顺序查,基本不用整天对着一堆数据发愁。
最后分享一个我个人的调试体会:温度监测系统的问题,七成出在物理层,也就是电源、地线、接线和干扰上,只有三成才是软件逻辑的问题。所以拿到一个新系统,我习惯先花时间把硬件连接、接地和屏蔽做扎实,再动手调协议栈和滤波算法。PJ85718DM 和 PIC18F85J10 这套组合,本身硬件资源是绰绰有余的,把基础打好了,后续不管是扩展到湿度监测、压力监测还是加更多的远程节点,都会顺畅很多。