
做 HVAC 控制器那阵子我吃过 NTC 热敏电阻不少苦头。回风温度、盘管温度各接一个 10K NTC看起来很简单实际上 B 值分散、线缆长度、ADC 参考电压随便哪个因素都能让读数偏 1~2°C更别提现场换一个型号的探头就要重新校准一遍。后来我把系统改成数字温度传感器方案主控用 PIC18F65K40本地和远程各挂一颗 PJ85718DM通过 I2C 总线把温度读回来。这一改校表流程少了抗干扰能力上来了到现场调试也顺了很多。文章适合正在做嵌入式温控、HVAC 控制器、工业现场测温的开发者参考。我会把选型理由、硬件布局、固件框架、现场调试踩过的坑、校准验收方法都交代清楚基本是按照一套可以复现的完整流程来写。1. 为什么温度要拆成“本地”和“远程”两路来测1.1 两类场景里两路温度各测什么先聊一个很多人忽略的问题温度监测场景里的“本地”和“远程”到底指的是什么。在 HVAC 系统里本地温度通常指控制器电控盒内部的环境温度它反映的是电路板自身发热、散热风道是否通畅、继电器或功率器件是否过温。远程温度则装在风道、冷媒管、压缩机回气管、蒸发器盘管这类真正参与热交换的位置。这两处物理环境完全不同控制盒内是静态空气远程探头可能贴在金属管壁或者风道气流中间温差可以很大升降温速率也完全不同。嵌入式产品同样是这样。我做过一个电池管理相关的项目本地传感器放在主控板上测 PCB 环境温度远程传感器用线缆引到电芯表面和功率 MOS 管散热器上。板上温度再正常电芯温度也可能已经到临界值了。如果整机只放一颗传感器你永远无法同时知道“设备自身热不热”和“被控对象热不热”。1.2 双点温差比单点绝对值更有价值两路温度合在一起最有价值的不是各看各的而是做温差判断。我举一个实际例子冷凝器蒸发器距离较近的系统里盘管温度和回风温度会形成一个正常温差区间。风机运行正常、冷媒充注量正常时这个温差基本稳定。如果盘管温度和回风温度越来越接近可能预示冷媒泄漏如果温差突然拉大又可能是风量不足或者换热表面结垢。单靠一路温度绝对数值这些早期异常很难发现只有把本地和远程对比着看才具备故障预判能力。这套逻辑在嵌入式设备里也成立。我见过一个功率模块的热保护设计本地测模块附近板温远程测散热器基板温度。两者温差最能反映散热器是否安装到位——如果温差异常大而负载没变化最可能就是导热硅脂老化或紧固件松脱。所以系统设计第一件事就是把设备自身温度和被控介质温度分开至少做成两路。2. 器件选型为什么是 PJ85718DM PIC18F65K402.1 数字温度传感器比 NTC 少一条校准曲线传统控制器大量用 NTC 热敏电阻加 MCU 内部 ADC。NTC 的优势是便宜但代价非常明显阻值-温度曲线非线性严重B 值有批次离散ADC 参考电压精度有限长线缆的铜阻还会直接串进分压网络。现场换一种探头型号整个查表代码大概率要重新标定。PJ85718DM 这类数字温度传感器把测温元件、ADC、参考电压、数字接口全封装进一颗小芯片MCU 通过 I2C 拿到的就是量化好的温度数据中间不需要任何模拟调理。出厂校准已经完成非线性由内部修正B 值离散、元件误差这些问题从系统里被直接抹掉了。这里说明一下PJ85718DM 的具体供电范围、I2C 地址引脚数量、转换时间等参数不同批次或封装可能存在差异我下文的实现按常见 I2C 数字温度传感器的表型展开实际项目请先对照规格书确认。数字输出在远程探头场景还有一层隐藏优势只要 I2C 信号能通线缆电阻和长度几乎不影响温度精度。NTC 走 3 米线缆铜阻就能引入好几欧误差折算下来温度偏 1~2°C 很常见而数字传感器把 ADC 放在探头端模拟信号不经过长线天然免疫这类问题。2.2 K40 系外设和场景的匹配点PIC18F65K40 属于中端增强型 8 位 MCU选它做这类控制器最核心的原因是外设刚好匹配不是参数堆得高而是每一分资源都用得上。第一是硬件 I2C 外设。K40 系的 MSSP 模块能自动处理 START、STOP、ACK 时序CPU 只需要在中断里读写缓冲寄存器。相比之下GPIO 模拟 I2C 在远程线缆较长时裸引脚边沿容易抖动而且整个 CPU 被位操作占满主循环里其他任务几乎没法跑。第二是 5V 供电和宽工作温度范围。HVAC 电控盒里电源普遍是 24V/12V/5V 的工业逻辑5V 直接供电不用做电平桥接省掉一级 DC-DC 或者 LDO抗干扰能力也更强。第三是 CLC 可配置逻辑单元。这是很多人容易忽略的外设它可以把传感器 ALERT 引脚信号组合成硬件级中断做超温保护用的逻辑路径。软件轮询只是辅助硬件路径才是最可靠的兜底。后面调试部分我会展开讲这个用法。3. 硬件设计I2C 总线上挂两颗温度传感器的关键细节3.1 器件地址怎么分以及地址不够的备用方案两颗同型号传感器挂同一总线上第一件要解决的事就是地址冲突。PJ85718DM 如果有 AD0/AD1 地址引脚通常能组合出至少 4 个或更多地址。我的做法是本地传感器设成 0x48远程传感器设成 0x49PCB LAYOUT 时把地址引脚通过 0Ω 电阻分别接到 VDD 和 GND这样生产线上可以灵活改地址比直接焊死更灵活。如果地址引脚不够用或者同批次器件地址被固定也不要急着换方案。有个土办法用两颗 GPIO 分别控制两颗传感器的供电分时上电。需要读本地温度时给本地传感器供电初始化后读一次然后断电再过一段时间读远程传感器。缺点是每次上电都要重新初始化并等待转换时间轮询周期会被拉长对 HVAC 这种秒级响应的场景完全够用但不适合高速采集。多条 I2C 总线是更干净的方案但 K40 系的 MSSP 硬件模块只有一个。真要多路总线要么用 GPIO 模拟第二路要么把远程传感器单独挂在外部 I2C MUX 后面。以我的经验优先把地址位规划好因为 HVAC 现场线缆是安装工人接的不会替你考虑什么总线拓扑。3.2 上拉电阻计算与远程线缆电容的关系I2C 的 SCL/SDA 都需要外部上拉阻值不是随便选。两个边界公式很关键Rp(min) (VDD - 0.4V) / IOL(max)保证低电平时输出能被拉到标准要求以下。Rp(max) tr / (0.8473 × C_bus)保证上升沿在规定时间内完成。举个例子VDD5VIOL 按常见 3mA 估算Rp(min) ≈ (5-0.4)/0.003 ≈ 1.53kΩ。如果远程线缆把总线电容带到 300pFFast Mode 要求上升时间 300nsRp(max) ≈ 300ns / (0.8473 × 300pF) ≈ 1.18kΩ。你会发现最小值和最大值已经打架了这就是远程 I2C 跑不了 400kHz 的根源。我的经验是远程探头线路尽量控制在 1 米以内总线速率降到 100kHz上拉选 4.7kΩ实测波形稳定。如果探头必须拉到 3~5 米远比如风道深处、冷媒管远端我先试两种方案一是在传感器端加 I2C 总线缓冲器隔离远端电容二是干脆换 RS485 总线方案远端放一颗小 MCU 读传感器再通过 Modbus 协议回传给主控。后者在多探头复杂系统里反而更省心。3.3 供电、电平匹配与远程接口保护K40 可以 5V 供电如果 PJ85718DM 的绝对额定电压覆盖 5V那就统一 5V 供电I2C 开漏上拉也接 5V逻辑电平完全一致这是最省事的组合。如果传感器只能 3.3V 供电就需要双向电平转换PCA9306 这类器件或 BSS138 分立方案都能做但要注意双向转换电路在 400kHz 下边沿会变差优先降到 100kHz 再验证。远程探头的电源也要算压降。3 米细线在传感器 1mA 级别工作电流下不至于造成明显压降但线缆本身的对地电容和屏蔽层接地方式更值得注意。屏蔽层在主控板侧单端接地另一头悬空否则强电区域在屏蔽层上感应出的地环路电流会给整条总线引入噪声读数反而更不稳。接口保护是最后一道防线。远程线缆从主控板出去进风道不可避免会经过压缩机和电机等强电区域感应浪涌不能忽略。我在 SCL/SDA 上各加 100Ω 到 1kΩ 串联电阻并行 1nF 电容到地再在接口处放 TVS 管到 VDD 和 GND。保护元件的寄生电容会影响总线边沿所以阻值别一味求大最终以实测波形为准。4. 固件框架轮询、滤波与超温保护怎么做4.1 MSSP 初始化与温度读取流程K40 系的 MSSP 模块配置成 I2C 主机模式代码框架大致如下// I2C 主机模式初始化目标 100kHz SSP1CON1 0x08; // I2C 主机模式 SSP1ADD ((F_OSC / 4) / 100000); // 分频计算 SSP1CON1bits.SSPEN 1; // 使能 MSSP SSP1CON1bits.CKP 1; // 释放时钟读温度寄存器 0x00 的标准流程是START - 发设备地址加写位 - 写寄存器指针 0x00 - RESTART - 发设备地址加读位 - 读高字节和低字节最后一个字节回 NACK - STOP。int16_t read_temp(uint8_t dev_addr) { uint8_t hi, lo; // 写寄存器指针 I2C_START(); I2C_WRITE(dev_addr 1 | 0); I2C_WRITE(0x00); // 温度寄存器 // 重复起始 I2C_RESTART(); I2C_WRITE(dev_addr 1 | 1); hi I2C_READ(1); // 高字节 lo I2C_READ(0); // 低字节回 NACK I2C_STOP(); return ((int16_t)hi 8) | lo; }温度值换算一定要看规格书里的缩放系数。有的传感器是 0.0625°C/LSB有的是 0.0078°C/LSB还有的是带符号定点数。我的建议是先把裸值打印出来和手持标准温度计对比后再确定换算公式不要默认套网上现成代码这是最容易翻车的一步。4.2 转换时间别阻塞主循环数字温度传感器读取时最容易踩的坑是转换时间。芯片内部做一次温度转换通常需要几十毫秒有的规格书还会写明典型转换时间 15ms、50ms 不等。最笨的写法是触发转换后死等标志位这一等就把主循环卡死了。HVAC 主控里还有风机、报警、通信任务本质上不允许这种阻塞式延时。我平时用状态机调度。主循环每 10ms 切一次状态流程是 IDLE - TRIGGER - WAIT - READ触发转换后不阻塞先跑其他任务到时间再去读结果。温度本身是慢变量几百毫秒刷新一次完全满足温控需求。两颗传感器的读取也按这个思路分时切片避免在同一时刻并发访问 I2C 总线。4.3 滤波和阈值滞回稳定性比灵敏度更重要传感器输出虽然比 NTC 干净但风机启动瞬间气流波动、电机启停干扰还是会造成读数尖峰。我做了两层处理。第一层取连续 3~5 次读数的滑动中值把明显离群的跳变剔除第二层对中值结果做一阶惯性滤波filtered filtered (raw - filtered) * kk 取 0.2 到 0.5折算时间常数在秒级。这样既压掉了毛刺又不会让真实温度变化变得太迟钝。报警阈值必须做滞回。只设一个“超过 60°C 报警低于 60°C 复位”会导致临界点状态反复翻转严重点还会让接触器在几秒内频繁通断。正确做法是设两个阈值比如 60°C 报警55°C 复位中间这 5°C 就是滞回窗口。代码实现用方向判断温度上升穿过上限才置位下降穿过下限才清除。4.4 ALERT 引脚 CLC 的硬件级保护路径软件轮询再快也有延迟所以我一直强调硬件保护通道。PJ85718DM 如果有 ALERT 引脚超限时能直接输出中断信号K40 系的 CLC 可配置逻辑单元可以把两个传感器的 ALERT 信号做逻辑或合成一路中断送到 MCU 的外部中断引脚。这样即使主循环正忙超温信号也能瞬间打断 CPU。实际项目里我把 ALERT 阈值设在软件报警点之上比如软件 60°C 处理风机联动、硬件 70°C 直接切负载。这种分层保护在异常场景下非常有用某次现场调试风扇故障导致盘管温度快速爬升软件还没来得及完成滤波硬件 ALERT 已经通过 CLC 触发中断切掉了负载。事后复盘如果只依赖软件轮询后果不太乐观。5. 现场调试踩坑记录从波形变圆到压缩机干扰5.1 远程 I2C 线 2 米波形直接变圆第一次把远程探头拉到风道里线缆长度大概 2 米400kHz 下读数时有时无。用示波器量 SCL上升沿已经是明显圆弧形连器件的 VIH 门限都压着边过。原因就是线缆电容太大配合上拉电阻形成的 RC 时间常数跟不上总线速率。解决方案很直接速率降到 100kHz上拉电阻从 2.2k 换成 4.7k波形明显改善。这个案例让我总结出一条设计惯例远程 I2C 先按低速设计别一上来就追求 400kHz。能稳定跑到 100kHz在这个场景里的价值远大于传输速率。5.2 压缩机启动瞬间的读数跳变第二个高频问题出现在压缩机启动瞬间温度读数偶发跳变到明显异常值比如 -127、254。排查起来费了点功夫核心原因是强电干扰通过探头线缆耦合进 I2C 数据线SDA 上毛刺导致误码。修复分硬件和软件两层。硬件上SCL/SDA 各加 100Ω 串联电阻和 1nF 对地电容电源引脚加 100nF 和 10μF 电解电容I2C 线重新布线远离功率线软件上仍然保留中值滤波把偶发误码直接过滤掉。这种环境下别指望硬件把干扰完全消灭软硬件双保险是常规做法。5.3 传感器位置带来的自热假象还有一次排查了很久的“温度虚高”问题本地传感器读到的温度比实际环境温度高 2~3°C。一开始怀疑传感器坏了换一颗还是如此。后来才发现传感器安装位置紧挨着 MCU 和继电器板上发热直接加热了传感器加上传感器自身工作时也有轻微自热测出来的自然不是空气温度。这说明一个问题传感器标称精度再高测到的也只是传感器封装所在位置的温度。如果目标是测空气温度传感器一定要放在气流通道里、远离发热元件如果目标本身就是测板温那就接受这个物理位置的温度值在系统标定时把它定义为“板温”参考而不是“环境温度”参考。5.4 ALERT 与 CLC 联动的实战收益前面提到硬件保护路径这里补一个实际使用上的细节。CLC 可以把两颗传感器的 ALERT 引脚做逻辑或直接映射到中断信号而且不需要 CPU 干预配置逻辑。我把这个配置固化在初始化代码里后续基本不动。实际收益是保护响应时间从主循环轮询周期的几十毫秒级降到中断响应微秒级同时不占用任何软件资源。在 HVAC 这种电磁环境复杂的现场多一条硬件保护通道就是多一道保险。6. 系统校准与验收传感器精度不等于系统精度6.1 单点偏移校准与两点增益校准数字传感器出厂精度不错但装到批量的产品上还是要做系统级校准。最轻量的是单点偏移校准把探头和标准温度计放同一个恒温环境比如 25°C记录偏差在 MCU 里加一个 offset 修正值。这个方案对大多数 HVAC 控制器已经足够。如果工作范围很宽比如 -20°C 到 85°C单点 offset 就不够了。需要两点校准在 0°C 和 50°C或者冰水混合和恒温槽两个校准点记录原始读数计算 offset 和 gain然后按校准公式换算。// 两点校准后的温度计算 cal_temp (raw_temp - offset) * gain;建议每颗传感器建立单独校准记录别混合到一块。表格式的记录也方便追溯每次出货前按批次抽查比例保持一致。这里必须用独立标准温度计做仲裁不能拿传感器自己互相验证否则校准数据容易自洽但失真。6.2 探头安装工艺与防凝露现场安装工艺对温度精度的影响有时比传感器本身还大。远程探头贴到被测物表面要用导热硅脂填充缝隙再通过卡箍或扎带固定牢靠保证接触热阻足够小。只把探头随便靠在管壁上读数大概率偏低或者波动大。测气流温度时探头要伸入气流中心不要贴在管壁上还要注意探头护套的导热性。湿度大的场景比如蒸发器盘管附近探头外壳必须做防凝露处理否则结露后线路板短路再好的传感器也白搭。6.3 验收标准按系统测量精度定项目验收的时候不要去谈“传感器标称精度”要谈“系统测量精度”。传感器本体精度只代表芯片封装处的温度精度而系统测量精度包含了探头安装位置、热耦合、线缆、滤波算法、校准误差所有环节的叠加。我常用的验收办法把系统装在目标设备里用标准温度计同时测传感器安装点位的真实温度连续记录 24 小时观察最大偏差和波动幅度。验收线一般按应用需求定HVAC 舒适控制允许 ±1°C 或更宽热保护和性能测试要求会更高。这样定下来的指标才是现场能兑现的指标。7. 从两路到多路的扩展与最后的建议7.1 多路扩展的三种做法对比系统后续要加温度点优先顺序我建议这样排第一种利用 PJ85718DM 本身的地址引脚扩展这是最简单最干净的方式前提是地址够用。第二种用 I2C MUX 芯片做总线扩展一路 I2C 扩展出 8 路甚至更多代价是每次切通道都有一点点时间开销。第三种远程探头数量多、距离远时还是直接上 RS485 总线加远程从站模块每个从站负责抓一路或多路温度主站通过 Modbus 轮询。三种方案的取舍可以归纳成一句话近处、少量、用地址中间规模、用 MUX远处、大量、用串行总线。HVAC 现场多探头分布的情况RS485 方案布线更灵活隔离也更好做。7.2 软件架构表驱动让温度点位可配置温度点位一多代码里满天飞的独立变量就变成灾难。我后来重构过一次固件把所有温度点位抽象成一张配置表每个点位有编号、类型、传感器地址、滤波参数、报警阈值、校准参数主循环统一调度统一更新。新增一个点位就是新增一行表项核心读取函数完全不用动。这个思想是用一次八路温度采集项目换来的教训。三路、四路还能硬编码点位一多硬编码就是给自己挖坑。如果你现在只有两路提前按表驱动的思路写后续扩展会轻松很多。最后说一点个人体会无论本地还是远程温度传感器在整个系统里的角色永远是“参考”不是“真理”。PJ85718DM 标称精度哪怕做到 ±0.5°C最终系统能不能准确反映被测对象温度很大程度还是取决于安装位置和热耦合。我后来写所有方案都把“传感器本体精度”和“系统测量精度”分开表述验收标准也以现场实测为准。做温度监测最怕的不是传感器不够好而是把传感器装在了错误的位置还指望它告诉你真相。