在做暖通空调设备的嵌入式控制时,我最大的感受是:测到温度其实只占整个开发量的十分之一,剩下时间全都花在确认这个温度读出来可不可信、传到远端会不会丢、探头被拉断之后报警系统能不能第一时间发现。这个项目里用到的两片器件——PJ85718DM 和 PIC18F85K22——恰好把最烦人的两部分拆开了:PJ85718DM 承担温度探头微弱信号的调理和初步诊断,PIC18F85K22 负责采样、判断、显示和远程通信。这篇文章我会把从选型逻辑、信号链搭建、固件骨架到现场调试的完整过程梳理一遍,给正在做 HVAC 温度采集、机房环境监测或者设备内部温度保护的朋友一个可参考的落地方案。
先说清楚一个容易被忽略的事实:这类双端测温系统最大的价值不在“能测”,而在“长期稳定、出了毛病能查”。HVAC 现场往往同时存在风机、变频器、电动阀,电磁环境谈不上友好;而嵌入式设备内部空间小、发热源近,温度采样点选哪儿都可能是干扰。PJ85718DM 作为温度前端把模拟部分处理干净,PIC18F85K22 再用足够的 GPIO、串口和 ADC 通道把逻辑撑起来,整套系统无论放在空调箱旁边还是嵌进控制板里,都不会被信号问题拖后腿。
1. 双端测温方案的核心定位:为何不直接用成品温控器
1.1 项目背景与要解决的实际问题
这个项目的需求来源很典型:某处组合式空调机组需要同时监测送风温度和回水温度,控制柜里还要有一个本机显示的本地温度,同时数据要送进上位 BMS 系统做远程汇总。送风温度探头装在风道内,距离控制柜有二十多米;回水温度探头装在管道表面;控制柜本地温度则是为了监控设备发热。三个测点,三种位置,两种传输距离,这正好把“本地”和“远程”两个概念全部覆盖。
如果用成品温控器,每个测点配一台,本地显示倒是很方便,但远程数据要靠温控器自带的总线,不同厂家通讯协议不通用,后期接入 BMS 相当痛苦。如果用纯数字传感器挂 I2C 总线,布线距离超过十几米就开始不稳定,而且数字传感器的测温范围、探头形式都受限制,在 HVAC 现场很难做到防水、防潮、远距离同时兼顾。所以这个项目最终选了“模拟前端器件 + 8 位单片机”的组合:现场探头信号由 PJ85718DM 调理成干净模拟量,PIC18F85K22 做统一采集和协议转换,既保留本地控制的实时性,又通过 RS-485 把数据送到远程。
1.2 方案选型对比:数字传感器、模拟前端加单片机、成品温控器
很多人刚接触这种需求时,第一反应是“随便找个温度传感器芯片不就行了”。这里我列一个对比表,可以很直观地看到三种路线各自的边界:
| 方案 | 本地采集精度 | 远距离能力 | 灵活性与可定制 | 典型问题 |
|---|---|---|---|---|
| 数字温度传感器挂 I2C/SMBus | 高,免校准 | 弱,超过1米线缆就需注意 | 逻辑简单 | 探头形式少,长线时序易漂移 |
| PJ85718DM模拟前端 + MCU ADC | 中高,需校准 | 强,模拟量可配合屏蔽线走几十米 | 高,属性和连线均可定制 | 需要设计前端电路和校准流程 |
| 成品温控器/温度变送器 | 高,自带显示 | 强,4~20mA或总线输出 | 弱,受产品功能限制 | 价格高、协议封闭、显示逻辑不可改 |
这个项目最后走的是第二种。原因很现实:现场需要连接的探头不止一种,送风温度用 Pt100 更稳,本地温度用 NTC 成本更低,PJ85718DM 作为通用模拟前端可以适配不同传感器,只要把激励方式和增益调整好就行。相比之下数字传感器一旦选定型号,探头类型和量程基本就锁死了。
1.3 两颗芯片的分工与整体系统组成
整套系统的架构并不复杂,但分工非常明确。PJ85718DM 放在信号链的最前端,负责给温度探头提供激励、对微弱信号做放大和初步滤波,并输出一个和温度对应的电压信号;它在我的设计里还被用来做探头开路的诊断,后面会细说。PIC18F85K22 作为主控承担三件事:第一,用 ADC 定时采集本地和远程探头经前端调理后的电压;第二,完成数字滤波、温度换算、阈值告警;第三,通过 UART 驱动 RS-485 收发器,把处理好的数据打包上传。
系统组成可以拆成几个模块:传感器与前端调理板、主控板、本地显示与告警输出、RS-485 远程通信口。前端调理板负责所有的模拟信号处理,主控板全部做数字逻辑。这种“模拟归模拟,数字归数字”的分割,对后期调试帮助非常大——出现读数漂移时,先用示波器看前端输出,立刻就能判断问题出在传感器还是后级。
2. PJ85718DM 信号链这样搭:从探头到可采样的干净电压
2.1 传感器选型:Pt100、NTC 怎么选
温度传感器选型是整个信号链的地基。HVAC 场景下最常见的就是两类:热电阻和热敏电阻。Pt100 线性度好、重复性高,适合风道、水管这类需要长期稳定读数的测点;NTC 灵敏度高、成本低,适合设备内部温度监测这种范围窄、距离近的应用。
我在这套系统里的处理方式是:远程风道探头用 Pt100,三线制接法;本地设备内温度用 NTC 加串联分压。PJ85718DM 前端对两种传感器都适配,关键在于激励方式不同。Pt100 需要恒流激励或者精密电桥,NTC 则用恒压分压即可。设计时我把前端的第一级电路做成可配置的:通过跳线或者贴片电阻选择激励模式,这样一块前端板既能用在远程节点,也能作为本机前端。
顺便提醒一句,如果测温范围比较宽,比如某些冷库场景需要 -40℃ 到 +80℃,NTC 的非线性就会变得很难处理。这时候优先考虑 Pt100 或者 Pt1000,虽然价格高一点,但换来的是整个量程内的稳定精度,省下的调试时间远比器件差价值钱。
2.2 三线制接线与激励、放大的关键事项
Pt100 的引线电阻是读数误差的主要来源。两线制接法下,导线电阻直接串联进测量回路,20 米线的铜阻可能带来 0.5℃ 甚至更大的误差。三线制就是为了解决这个问题,它把一根引线作为采样线,激励电流不经过采样回路,从原理上抵消了线阻影响。
实际接线时需要注意,三根线必须是同一根电缆里的三芯,芯线截面积一致,否则线阻不对称,三线制抵消效果会打折扣。我在现场吃过这个亏:初期用的是两捆不同规格的线,结果温差越远读数偏得越厉害,后来换成同规格三芯屏蔽电缆,问题立刻消失。
放大环节要关注的是 PJ85718DM 前端的增益设置。我的做法是把整个测温量程映射到 MCU 供电电压的中段,不让输出顶到电源轨。比如系统使用 3.3V 供电,我把 0℃ 对应的输出设在 0.8V 左右,100℃ 对应在 2.4V 左右,这样 ADC 采样的有效分辨率和线性区间都比较好。前端放大器必须有足够的共模抑制能力,因为现场线缆会捡到不少共模噪声,如果前端器件本身的 CMRR 不够,后面加再多软件滤波都救不回来。
2.3 抗混叠滤波与前级保护
模拟信号的抗混叠滤波是很多人容易忽略的一步。PIC18F85K22 的 ADC 在采样时会对输入电容充电,如果输入信号里混着高频噪声,采样结果会出现随机跳变。前端输出级我加了一级二阶 RC 低通,拐点频率设在 10Hz 左右,主要滤掉 50Hz 工频干扰和变频器产生的高频噪声。这个带宽对温度信号完全够用,因为温度变化本来就慢,每秒采样几次已经非常充裕。
前级保护则要针对 HVAC 现场的意外情况。探头线在风道里可能被老鼠咬、被金属风管磨破皮,甚至可能在检修时被人为碰触,导致线与线之间短路。我建议在 PJ85718DM 输入侧加一对钳位二极管到电源和地,同时串入限流电阻,防止静电和意外短路损坏前端。这套保护电路成本就几毛钱,但能让整机故障率下降一大截。
2.4 断路、短路诊断的辅助电路逻辑
温度探头断线是 HVAC 现场最高频的故障。探头线在风道里振动、接线端子氧化、检修时插头没插紧,都会造成断路。如果系统不做断线检测,断线后前端输出通常会漂到某个极限电压,MCU 可能把它当成超高温或超低温,触发错误的停机或者报警,这种误导比不报警更危险。
我利用 PJ85718DM 的诊断输出配合 MCU 的 GPIO 来检测断路:正常情况下诊断脚保持低电平,探头开路时前端内部比较器翻转,诊断脚输出高电平。MCU 每个采样周期先读诊断脚,再读 ADC 值。只要诊断脚为高,立即进入“传感器故障”状态,不再相信 ADC 数据,同时通过 RS-485 上报故障代码。这样远程运维人员一看报文就知道是哪个探头断了,而不是看到一堆离谱温度干着急。
3. PIC18F85K22 固件骨架:采集滤波、迟滞判断与本地告警
3.1 程序框架和任务调度
PIC18F85K22 在项目里承担控制核心的角色。固件我用了典型的前后台结构:主循环做业务逻辑,定时器中断做采样时钟基准。定时器产生 2ms 的时基,在中断里累加计数,分别得到 10ms、100ms、1s 的调度节拍。温度采集放在 100ms 节拍里,显示刷新放在 200ms,RS-485 发送和接收状态机放在 10ms,这样每个任务有明确周期,不会互相抢占。
之所以用这种简单的调度方式而不是上操作系统,是因为 8 位 MCU 跑系统的开销不划算,而且温度监测的逻辑全是顺序性的,任务之间没有复杂的优先级抢占需求。把中断服务程序保持得尽量短,所有耗时操作都放到主循环里执行,是我一贯遵循的原则。
3.2 ADC 采样与数字滤波(附代码)
PIC18F85K22 的 ADC 是逐次逼近型,我在项目里配置为 10 位分辨率、左对齐方式。采样顺序是:先读诊断脚,再选通道,延时让采样保持电容充分充电,然后启动转换,转换完成后把结果存入缓冲区。为了提高稳定性,每个通道我连续采 7 次,去掉一个最大值和一个最小值,剩下的 5 次取平均,等效于一个“限幅+均值”的复合滤波。
这里给出一个简化的采样与滤波代码逻辑,具体寄存器位以编译器头文件为准:
uint16_t read_adc_single(uint8_t ch) { ADCON0 &= 0xC3; // 清除通道选择位 ADCON0 |= (ch << 2); // 选择当前通道 __delay_us(20); // 等待采样电容充电 GO_nDONE = 1; // 启动转换 while (GO_nDONE); // 等待转换完成 return (uint16_t)((ADRESH << 8) | ADRESL); } uint16_t read_stable_value(uint8_t ch) { uint16_t buf[7]; uint16_t min, max, sum = 0; for (uint8_t i = 0; i < 7; i++) { buf[i] = read_adc_single(ch); } min = max = buf[0]; for (uint8_t i = 0; i < 7; i++) { if (buf[i] < min) min = buf[i]; if (buf[i] > max) max = buf[i]; } sum = 0; for (uint8_t i = 0; i < 7; i++) { if (buf[i] != min && buf[i] != max) sum += buf[i]; } return sum / 5; }这套滤波对抑制偶尔的尖峰干扰非常有效。单纯滑动平均被一个异常大值带偏后要好久才能拉回来,而“去极值再平均”直接让异常样本不参与计算,读数稳定性明显改善。
3.3 温度换算、告警迟滞和本地联动
滤波之后得到的还是 ADC 码值,要换算成温度。这里我没有直接在 8 位 MCU 上跑大量浮点运算,而是用定点整数:温度内部以“毫摄氏度”为单位存放,即 25.36℃ 存成 25360。换算时先查一个粗分段的线性化表,再做线性插值,整个运算都是整数乘除,耗时短,MCU 的负担很小。
告警逻辑必须有迟滞,否则继电器在阈值附近来回抖动会把现场的人逼疯。比如高温报警设为 60℃,那么解除温度设为 58℃,中间这 2℃ 就是回差。我在固件里用状态机实现:
if (temperature_mc > ALARM_SET_MC && alarm_state == 0) { alarm_state = 1; alarm_output = 1; } else if (temperature_mc < ALARM_CLR_MC && alarm_state == 1) { alarm_state = 0; alarm_output = 0; }ALARM_SET_MC 和 ALARM_CLR_MC 分别是置位温度和解除温度,都存放在数据存储区,现场可以通过串口命令修改。本地联动包括点亮对应报警 LED、驱动蜂鸣器,以及把一个继电器输出置为故障态,用于切断相关设备。这个继电器动作在 HVAC 场景里经常用来启动排风机或者关闭电加热,逻辑非常简单但可靠性要求高,所以我直接使用了硬件状态位而没有加软件延迟。
4. 远程温度的 RS-485 之路:接线、协议与 BMS 对接
4.1 为什么走 RS-485 而不是 WiFi 或 4-20 mA
远程温度传输的通道选择,我基于一个朴素的逻辑:现场环境要稳、协议要开放、后期维护要简单。WiFi 看起来方便,但空调机房和风道附近的金属结构严重衰减信号,而且设备一多,AP 配置和密码管理都是负担。4-20mA 模拟量传输确实抗干扰好,但它只能单向传一个温度值,诊断信息、开关量状态、远程校准全都传不了。
RS-485 是目前 HVAC 行业里最稳妥的选择。差分信号有很强的共模抑制能力,在波特率 9600bps 下可以稳定走一千米;总线支持多点挂接,一台主控可以轮询几十个远程节点;Modbus RTU 协议又是事实标准,几乎所有 BMS 系统都支持。所以我毫不犹豫地选择了 RS-485 加 Modbus RTU,远程节点的温度和其他状态数据全部数字化打包。
4.2 硬件层面的隔离、终端电阻与地环路问题
RS-485 的硬件设计里最容易踩的坑是地环路。现场有多个节点,如果每个节点都接地,节点之间的地电位差会在总线线上产生电流,轻则数据乱码,重则烧毁收发器。我在每个远程节点上都用了隔离设计:通信侧和主控侧之间隔一个隔离电源模块,信号通过数字隔离器耦合。这样即使现场地电位不干净,电流也无法在总线上形成环路。
接线规范方面,两端的终端电阻必须加上,120Ω 并联在 A、B 线之间,位置在总线的最远两端。布线要避免星型拓扑,尽量手拉手串接。现场调试时我发现,终端电阻加不加,波形完全是两回事:不加的时候波形沿很差,偶尔还会反射出毛刺,加上之后立刻平直。还有一点,屏蔽层要单端接地,我一般接在主站侧,避免屏蔽层成为地环路的一部分。
4.3 Modbus RTU 实现思路与帧结构代码
Modbus RTU 的从站实现并不复杂。主站发请求帧,从站解析地址码、功能码、寄存器地址,然后生成响应帧。项目里最常用的功能码是 03 读保持寄存器,我把本地温度、远程温度和故障状态映射到保持寄存器区,单位是 0.1℃。比如寄存器地址 0x0001 存放本地温度,0x0002 存放送风温度,0x0003 存放本地温度告警状态。
CRC16 校验是这个协议里的关键,我直接给出一个常用的实现片段:
uint16_t modbus_crc16(uint8_t *buf, uint16_t len) { uint16_t crc = 0xFFFF; while (len--) { crc ^= *buf++; for (uint8_t i = 0; i < 8; i++) { if (crc & 0x0001) { crc >>= 1; crc ^= 0xA001; } else { crc >>= 1; } } } return crc; }发送完一帧后,从站必须接收完整的 8 字节请求,校验通过才解析。处理完任务后,主站会在轮询周期结束后得到响应。主站侧我设了 500ms 超时,超时后重发一次,连续三次失败就标记该节点离线。这套机制在项目中非常可靠,至今没有出现过数据静默丢失的情况。
5. 现场调试记录:三个真实问题与排查链路
5.1 读数系统性偏差:采样时序和参考电压惹的祸
第一次整机联调时,本地温度读出来比水银温度计高 0.8℃。这个偏差看起来不大,但在 HVAC 控制里已经足够让风机启停逻辑错乱。我最开始怀疑传感器问题,换了探头依旧偏高;又怀疑前端增益,用源表量了前端输出,电压确实对应偏高。
真正的问题藏在采样时序里。ADC 转换完成后,我直接接着采样下一路,没有给采样电容留足放电时间,导致上一通道的残余电荷混进了当前通道。修正方法是:通道切换后固定插入 20μs 延时,并且每路在转换前先读取诊断脚。改动之后偏差降到了 0.1℃ 以内。另一个相关问题是 ADC 参考电压,我第一次用了芯片内部参考,温漂明显,后来改成外部精密基准,长时间稳定性才过关。
5.2 探头断线导致误报警:断路检测让故障定位少走弯路
项目运行到第二个月,远程风道温度突然上报为 -50℃。按原有逻辑,主机会把这个温度当成异常值处理,触发低温报警。正好我当时已经加了断路检测功能,上报报文里带了故障状态位,这才定位到是探头断路而不是真正的低温。
赶到现场发现,探头接线盒里的螺丝端子松动,振动导致 Pt100 的一根线脱落。这类故障在现场太常见了。所以我的建议非常明确:任何长期运行的温度监测设备,都必须有断路检测能力,而且要在通信协议里把“传感器故障”和“真实温度超限”区分开。前者是设备本身需要维护,后者是环境流程需要调整,混为一谈会给后续运维制造无数麻烦。
5.3 RS-485 偶发乱码:接地、终端与换线
RS-485 总线的偶发乱码是排查起来最耗时间的故障。第一次现场测试时,十几帧里偶尔出现一帧 CRC 错误,重启后又能正常很久,非常随机。我起初以为是波特率误差,用示波器量了波形,觉得占空比没问题。
后来我把排查重点转向地环路。拆开节点检查发现,有个节点把通信线的屏蔽层接到了设备箱体上,而这个箱体又是接地的,等于屏蔽层形成了接地点,和主站之间产生了电位差。我按“屏蔽层单端接地”的原则改掉后,乱码消失。这个案例给我的经验是:RS-485 的故障,先查物理层,再查协议层。物理层里优先查接地,其次终端电阻,然后才考虑软件时序。
5.4 双点校准实施方法
温度采集系统的出厂校准,我采用的是双点校准法。以 Pt100 通道为例:零点用冰水混合物提供 0℃,满量程用恒温水槽提供 80℃,记录下实际 ADC 值,计算出增益误差和偏移误差,写入 MCU 的数据存储区。之后每次运行时,先读取校准参数,再进行温度换算。
校准参数我用的是两个无符号整数:gain 和 offset。换算公式为:
temperature_mc = (raw_adc * gain) / 1000 + offset;其中 gain 的初始值是 1000,表示没有增益修正。偏移的单位是 0.1℃。这套方法的精度完全取决于标准源,只要标准源靠谱,整套系统可以达到 ±0.2℃ 的长期精度,对 HVAC 应用绰绰有余。现场维护时,如果某个探头老化导致读数偏了,直接在后台改 offset 即可,不用更换硬件。
6. 实测数据、结果分析与后续扩展
6.1 长期稳定性实测结果
系统完成校准后,我在模拟风道环境里做了 72 小时连续运行测试。环境温度在 15℃ 到 35℃ 之间波动,回水温度稳定在 45℃ 左右。每 10 分钟记录一次本地温度、送风温度和回水温度,三天下来数据非常平稳:本地温度波动不超过 ±0.3℃,送风温度在设定值附近波动 ±0.5℃,回水温度波动 ±0.2℃。
印象最深的是凌晨时段电压波动造成的干扰,前端输出纹波明显偏大,但经过数字滤波后,ADC 采样结果依旧稳定,这说明整套“前端硬件滤波 + 数字软件滤波”的双重策略确实有效。RS-485 每天上报约 8640 帧,三天下来几乎没有漏帧,CRC 错误帧也是零,这个结果对后续批量复制方案非常有信心。
如果把这个方案扩展成多条送风、回风温度测点,最直接的办法是在远程节点上扩展通道数。PJ85718DM 前端可以做成多路的,主控芯片也有足够的 ADC 输入引脚,每条通道独立采样、独立滤波、独立上报,逻辑不需要大改。另外一种扩展思路是把本地温度用来做闭环控制:结合电动调节阀的开度,让 PIC18F85K22 直接输出 PWM 或 PID 来控制供热,这样系统就可以从“温度监测”升级成“温度控制”。
6.2 后续扩展:从监测到控制的演进路线
在实际项目中,温度监测很少只停留在“看数据”这一步。下一步我打算把 RS-485 的从站模式升级成“既上报又接收”,主站下发目标温度,PIC18F85K22 结合本地温度和回水温度做一个增量式 PID,输出控制信号驱动外部阀门或风机。这样 P 和 I 参数可以通过 Modbus 寄存器在线修改,调试不再需要反复烧录固件。
功耗方面,PIC18F85K22 支持多种低功耗模式,远程节点如果改用电池供电,可以让 MCU 定时醒来采样一次,然后进入休眠,RS-485 平时不发送数据。只要能接受几分钟一次的上报频率,整体平均功耗可以压得很低,非常适合冷库、粮库这类不方便布线长期供电的现场。
最后再分享一点这段时间反复验证得到的心得:这类测温系统真正考验人的不是电路图和代码本身,而是“信号是否干净、故障是否可诊断、协议是否可维护”这三件事。把 PJ85718DM 的模拟前端和 PIC18F85K22 的数字逻辑配合好,再加上完整的断路诊断和标准的远程协议,这套双端测温方案就能从一个试验板变成真正能长期运行的现场设备。