做 HVAC 和嵌入式温度监测的人都有个共同体会:写控制逻辑容易,把温度测准反而难。尤其当系统既要读本地环境温度,又要把传感器甩到十几米外的风管、水管上时,选型、布线和驱动全都要重新考虑。我最近在做的一套温控面板,就是用 PJ85718DM 搭配 PIC24FJ128GA310 来同时监测本地温度与远程温度,把面板附近的环境温度、回风温度和送风温度全部拉进同一个系统。这套组合的思路很简单:数字温度传感器走单总线,多个测温点共用一条线;主控用自带 LCD 段码控制器和实时时钟的 16 位单片机,面板电路省掉一堆外设。对正在做温控器、数据采集仪表或者嵌入式小系统的工程师,这篇文章能把从器件选型、硬件设计、单总线驱动到多点轮询、LCD 显示、现场排查的完整链路讲清楚,可以直接拿来做参考骨架。
1. 项目拆解:本地与远程温度监测到底在解决什么问题
1.1 “本地”和“远程”是两个完全不同的测温场景
先说一个常见误区:别把温度采集当成同一件事来处理。本地温度和远程温度虽然读出来的都是数字,但背后的工程约束完全不同。
本地温度一般指设备所在位置的环境温度,对温控面板来说就是安装处的室温。它有三个特点:第一,传感器离主控很近,走线短,信号质量基本不用操心;第二,响应速度要求高,房间温度虽然变化慢,但用户盯着屏幕,希望数字能快速跟随体感变化;第三,容易受设备自身发热干扰,单片机、电源、LCD 驱动电路都会让本地温度读数虚高。所以本地温度往往不是只做一次读取就行,而是要做滤波、校准,甚至把传感器安装位置从热源附近挪走。
远程温度就是另一套逻辑了。传感器可能装在几十米外的风管里、冷热水管上、室外冷凝器旁边,走线穿过桥架、线槽甚至配电箱。在这种环境里,模拟信号会被严重干扰,NTC 长线拉出去分压网络根本不准,所以数字传感器几乎是唯一可靠方案。它的输出直接就是数字,抗干扰能力强,线长一点也能稳定读到。可问题变成了怎么布总线、怎么防静电、怎么在一条线上识别出多个传感器。这些都是本地测温不会遇到的问题。
把两个场景放在同一个项目里,选型思路就会很清晰:本地和远程统一用一种数字传感器,主控用一颗够用的单片机,分时轮询所有测点。
1.2 为什么是 PJ85718DM 配 PIC24FJ128GA310
PJ85718DM 这类器件,典型形态是单总线数字温度传感器。我手头这颗的数据手册参数和常见的单总线传感器一致:测温范围覆盖 -55~125°C,12 位分辨率下精度在 ±0.5°C 级别,每个器件出厂带唯一的 64 位序列号,一条总线上可以挂多个器件。对 HVAC 这种需要多个温度点、走线距离长的现场,这些特性几乎量身定做。
PIC24FJ128GA310 是 16 位单片机,选它不只是因为主频够用,更重要的是它把仪表面板最需要的几个外设都集成进来了:LCD 段码控制器、实时时钟、足够的定时器和串口。以前做温控器要外挂 LCD 驱动芯片、RTC 芯片,现在板上省掉好几颗器件,BOM 成本和布板面积都能压缩。单总线的时序用普通 GPIO 模拟完全够用,不占硬件外设资源。
这一对组合的价值在于:传感器负责把温度问题简化成数字问题,单片机负责把所有数字问题统一处理。没有 ADC 标定、没有多路模拟开关、没有每个温度点一套分压电阻,温度通道从“三路模拟采集”变成“一条数据线上的三个节点”。
提示:如果你的 PJ85718DM 实际是其他接口形式的数字传感器,只需要把驱动层换成对应协议,本文的硬件架构和软件分层思路依然可以直接套用。
2. 硬件链路:从传感器到单片机的完整设计要点
2.1 PJ85718DM 的接线方式与电源方案
先讲接线。单总线接口一般三根线:VDD、DQ、GND。DQ 就是数据线,所有传感器并接在一条线上,每个传感器旁边配一个 100nF 去耦电容,电源线上再加一点滤波,能明显减少供电毛刺。
电源方案有两种:寄生供电和外部供电。寄生供电就是 DQ 既传数据又给芯片供电,可以少拉一根线,但远程线长、器件数量多时电流供应不稳,不建议在 HVAC 现场用。外部供电最稳:VDD 单独接电源,DQ 只传数据。引线超过 10 米后要特别注意上拉电阻,典型值 4.7kΩ 在短线上没问题,长线我习惯压到 2.2kΩ,甚至 1kΩ,保证信号边沿够陡。上拉电阻别贪大也不要贪小,太大会让上升沿变慢、误码率上升;太小会给总线灌太多电流,多个设备同时操作时可能把引脚拉不低。
电平匹配是容易忽略的细节。主控跑 3.3V,传感器也供 3.3V,这样 DQ 的高电平不会超过单片机 VDD。如果传感器用 5V 供电,建议在 DQ 上加一路电平转换或者分压,不要直接把 5V 信号送进 3.3V 的 IO。很多项目第一次调不通,问题就出在电平不匹配上。
2.2 PIC24FJ128GA310 的 GPIO 配置和外围电路
主控侧的 GPIO 要选一个可以配置成开漏或推挽输出的端口,因为单总线是“线与”结构,驱动代码里要在输出和输入两个模式之间切换。我习惯在 DQ 引脚上并联一个 1nF 电容到地,滤掉高频毛刺;但电容不能太大,否则边沿爬升太慢,时序会乱。1nF 是安全和速度的平衡点,远程线特别长时宁可不加,把滤波放在电源上更稳妥。
ESD 防护必须做。HVAC 现场传感器线会拉到室外,雷击感应、接触起电机率不小。我会在接线端子入口加一个小 TVS 管,把 DQ 和 VDD 都保护住,TVS 的电容要选得小一点。这个地方省下来的钱,不够一次返修的人工费。
PIC24FJ128GA310 的 LCD 控制器同样需要几个电容配合内部电荷泵,具体引脚看手册。最麻烦的地方在于段码和 COM 引脚的映射:原理上是把每个 LCD 段对应到一个内存位,控制器自动刷新。配置一次之后基本不用管,比外置 LCD 驱动芯片省心很多。下面列一个简单的端口规划表。
| 信号 | 主控引脚 | 说明 |
|---|---|---|
| DQ | 任意 GPIO | 接 4.7kΩ 上拉到传感器供电,并联 1nF 电容 |
| VDD | 电源输出 | 3.3V,与单片机电平一致 |
| LCD COM/SEG | 专用引脚 | 按段码表映射,配置偏置电压 |
| TVS | 端子入口 | 保护 DQ 和 VDD,选低电容型号 |
3. 软件实现:单总线驱动、多点轮询与显示状态机
3.1 单总线时序怎么快速打通
单总线协议本身不复杂,但微秒级时序对嵌入式程序来说比较娇气。调试时我会先把关键动作拆成五个最小函数:复位、写 1、写 0、读 1、读 0,分别验证,再组合成读字节、写字节、读温度。
/* 单总线复位与读取一个字节,端口定义按实际硬件改动 */ #define OW_DIR_OUT() TRISBbits.TRISB4 = 0 #define OW_DIR_IN() TRISBbits.TRISB4 = 1 #define OW_WRITE_LOW() LATBbits.LATB4 = 0 #define OW_READ() PORTBbits.RB4 static void ow_reset(void) { OW_DIR_OUT(); OW_WRITE_LOW(); delay_us(480); /* 复位脉冲 */ OW_DIR_IN(); /* 释放总线,靠上拉拉高 */ delay_us(70); /* 等存在脉冲 */ presence = OW_READ();/* 0 表示有器件响应 */ delay_us(410); /* 补完整个复位时隙 */ } uint8_t ow_read_byte(void) { uint8_t val = 0; for (uint8_t i = 0; i < 8; i++) { val >>= 1; OW_DIR_OUT(); OW_WRITE_LOW(); delay_us(6); OW_DIR_IN(); delay_us(9); if (OW_READ()) val |= 0x80; delay_us(50); } return val; }这里有个容易被坑的地方:延时函数必须关中断。单总线时序要求微秒级精度,如果中断把时序打断,比如复位脉冲被拉长到 800us,器件可能误判,后续读写全乱。两个方案:一是做临界区保护,在单总线操作期间把优先级高的中断屏蔽掉;二是把单总线操作塞进不可嵌套的中断服务里。第二个方案不推荐,它会把其他任务卡死。
读回的数据换算成温度也有固定套路。单总线温度传感器的暂存器通常是两个字节,温度高字节包含符号位,低字节的低 4 位是小数部分。先把两个字节拼成一个 16 位整数,再右移 4 位,最后做有符号补码转换,就得到 0.0625°C 分辨率的温度值。我第一次做的时候忘了处理负数,零下的温度直接显示成很大的正数,后来补了符号判断才正常。
3.2 多点轮询与地址管理
单总线最大的价值是多点,系统的复杂度也主要在管理这些点。每个器件都有全球唯一的 64 位序列号,第一步就是“枚举总线”。常见做法是用 Search ROM 命令配合逐位读回序列号,本质上是一个深度优先搜索,按位处理两轮就能跑通。更工程化的做法:首次焊接后在调试串口打印每个传感器的序列号,手动整理成程序里的地址表,并给每个地址指定一个测点名称。批量生产时我更推荐后者,稳定可靠,还省掉运行时的搜索代码。
地址表建好之后,轮询逻辑就清晰了:复位 -> MatchROM 指定地址 -> 发温度转换命令 -> 等转换时间 -> 复位 -> MatchROM -> 发读暂存器命令 -> 读 9 个字节 -> CRC 校验 -> 转成温度值 -> 显示。这个流程对每个传感器循环执行一遍。
转换时间要特别注意。12 位分辨率下典型转换时间是 750ms,如果总线上挂了 5 个传感器,按顺序每个读完再显示,一轮要好几秒,体验很差。我的做法是先把所有传感器的转换命令都发出去,等一段时间后再统一读取。单总线支持广播启动转换,也就是用 SkipROM 代替 MatchROM 发一次转换命令,所有传感器会同时开始转换,等 750ms 后挨个 MatchROM 读结果。这样 5 个点一轮只需要 750ms 加少量读取时间,效果完全不同。
设备数量少、距离短时可以省掉 Search ROM,但千万别省 CRC 校验。远程传感器受干扰后,读出来的温度可能偶尔跳一个很大的值,如果程序不校验,控制逻辑就会收到伪数据。温度错误和通信错误,总要有一个能被程序识别出来。CRC 校验不算复杂,读完 9 个字节后按 64 位序列号和通道数据的多项式算一遍,对上就显示,对不上就重读,最多重读三次。
3.3 本地校准与显示状态机
即使是数字温度传感器,本地温度依然会有误差。误差来源主要是传感器旁边其他器件发热,加上探头到空气的热阻。我通常在测试阶段处理:用一个经过校准的参考温度计放在传感器旁边,读出差值,然后在程序里做一个偏移常量。比如室温 25°C,传感器读出来 25.6°C,就在转换结果里减 0.6°C。这个偏移在批量生产时可以放到外部存储里,实现产线在线校准。远程传感器装在管道里,环境温度相对均匀,一般不需要这个处理。
显示部分,PIC24FJ128GA310 的 LCD 控制器用起来比较舒服。先把段码表的位映射定义好,比如一位数字需要 a~g 七段加小数点 dp;再把温度值按位拆分,写进对应的显存位。我习惯在显示层加一个状态机:正常情况下显示本地温度,短按按键切换到远程温度,再按切回;采集失败时显示短横线而不是上一次的温度值,避免误导用户。这个状态机和单总线采集是解耦的,采集任务把最新值放到公共变量,显示层定时取用。千万不可以在显示刷新函数里面去做单总线时序操作,一旦赶上低优先级任务,刷新会被拖得很慢,面板会显得很卡。
4. 从温度测量到控制:HVAC 与嵌入式场景怎么落地
4.1 HVAC 温控面板的典型接线和策略
一个典型的 HVAC 应用会有这样几个测点:室内温控面板附近的环境温度、回风口温度、送风管温度,有时还要看盘管进出水温度。前两个相对近,最后一个可能隔着整个机房。全部用 NTC 或热电阻做模拟采集,每路都要独立布线、独立校准,增益误差和线阻误差很难对齐。用 PJ85718DM 这类单总线传感器后,这些传感器全部并联到同一根两芯屏蔽线上,地址表写清楚哪个点是回风、哪个点是送风,程序里按需读取。
控制策略不复杂但很讲究。比如送风温度过低往往意味着表冷器或加热器有问题,远程温度异常时不仅要显示报警,还要能通过继电器把风机关掉或者开启辅助热。又比如本地温度和回风温度之间温差过大,说明回风短路或者风量不足。这些判断逻辑不依赖具体传感器,只依赖本地/远程每个点的温度值,所以架构上要把温度采集模块放到底层,控制逻辑放上层。底层稳定、上层逻辑才敢放心写。
这里有一个很实用的小技巧:远程传感器只用来做控制参考,不要用它去做面板本地显示的主要来源。因为远程数据刷新周期受总线轮询影响,界面上看会“一顿一顿”的。本地温度可以每个显示周期都读一次,远程温度放慢到 2~3 秒更新一次,用户看起来就流畅很多。
4.2 嵌入式小系统的通用扩展方向
同样是这套硬件,换一个外壳就能变成通用温度记录仪。采集逻辑和 LCD 逻辑完全复用,把实时时钟的时间戳和温度值写进外部存储,或者通过串口传出去。做电池供电时,PIC24FJ128GA310 的低功耗模式能派上用场:平时休眠,LCD 保持显示,定时器每 5 秒唤醒一次去读传感器、刷一次显示,再睡回去。单总线器件在这个场景下能耗也比较低,转换完就进入空闲状态。
要接上位机或触摸屏,就相当于给面板加一个通信从机。温度采集仍然在单片机里完成,定时刷新温度缓存,通信协议只读缓存,不去直接触碰单总线时序。如果让协议处理和单总线时序挤在同一个任务里,应答很容易被卡断。把“采集循环”和“通信循环”分离是这类系统的一个通则,也是我做过几个项目后最深的体会。
5. 现场调试与问题排查实录
5.1 常见故障速查表
调试阶段遇到的大多数问题都有规律可循,整理成一张速查表,现场排查会快很多。
| 现象 | 可能原因 | 排查动作 | 参考处理 |
|---|---|---|---|
| 总线上一个器件都读不到 | DQ 上拉缺失或 GPIO 方向配置错 | 示波器看复位后总线波形 | 检查 4.7kΩ 上拉,确认输入输出切换方向 |
| 某个远程点读数随机跳变 | 线长太长、干扰大、走线贴近动力线 | 换屏蔽双绞线重新布线 | 加大上拉、加滤波电容、降低轮询速度 |
| 读数固定为 85°C | 上电后直接读缓存,没有启动转换 | 用示波器确认命令时序 | 每次读前先发转换命令并等待 |
| 本地温度明显偏高 | 探头靠近发热源 | 手感或热成像确认热源位置 | 挪传感器位置、程序加偏移修正 |
| 读数全是 0xFF | 总线短路到 VDD,或器件损坏 | 万用表测 DQ 电压 | 检查焊接、更换器件 |
| LCD 显示偏淡或残影 | 偏置电压配置不合适 | 查 LCD 寄存器配置 | 调整偏压设置、改变刷新频率 |
5.2 实际操作避坑经验
第一,远程传感器最怕的不是传感器本身,而是施工布线。我在现场遇到过一种情况:同一根桥架里既有动力线又有传感器线,单总线波形看起来没大问题,温度却偶尔跳 1~2°C。后来把传感器线换成屏蔽双绞线,屏蔽层单端接地,问题就消失了。单总线虽然抗干扰,但不要拿它当电力线用,布线上贪的省,最后都会在调试里还回去。
第二,单总线几乎没有隔离能力。如果传感器和主控分别供电,共地没接好或者地电位差大,通信就会失败。现场施工时给传感器供电最好和主控电源共地;实在需要隔离,就加数字隔离器,不要硬扛。我见过一个项目在调试台上一切正常,到现场就乱跳,最后发现是传感器电源和主控电源来自不同开关电源,地电位差了将近 1V。
第三,多点应用别忘了给每个传感器加清晰的地址标识。有一回批量装配,几个传感器外壳上没打标,装配工人把回风和送风装反了,程序显示的温度和实际监控点位完全对不上。从那以后我在硬件设计上强制要求传感器线束用不同颜色、不同端子,程序里的地址表也写清楚测点名称和安装位置。
软件上还有一个容易踩的坑:读不到器件时程序卡在等待循环里,看门狗没喂,整机复位。处理办法很简单,所有单总线操作都要加超时判断,超过若干毫秒就放弃本次读取,标记该通道故障,然后继续跑其他通道。
这半个月调下来,我最大的体会是:这套架构里最值得抄的作业不是驱动代码,而是分层方式。硬件抽象、协议栈、数据缓存、显示逻辑、控制逻辑各自独立,每层只做一件事。这样即使某天换了另一种单总线传感器型号,或者 LCD 面板改了段码布局,改动范围依然可控。给准备复刻这套方案的朋友两个实际建议:第一,第一版 PCB 上把 DQ 的上拉电阻做成可跳线选择的,2.2kΩ 和 4.7kΩ 都留位置,现场调线长时可以快速切换;第二,程序里给温度采集留一个“测试模式”,上电后自动按地址表顺序把所有传感器读一遍并在 LCD 上轮流显示,工程调试时能省掉至少一半的沟通成本。