
做暖通空调控制器的那阵子我对“温度监测”这四个字有了完全不一样的理解。空调箱、新风机组、冷冻水管、送回风道……测温点分布在几十米甚至上百米的现场控制器要求各测点之间能有 0.5°C 以内的一致性还要能长期稳定运行。早期方案是每路传感器都拉模拟信号线结果线缆成本高、信号衰减和干扰问题一个接一个。后来我把采集架构整个改成“数字传感器 低功耗 MCU”本地回风温度用 PJ85718DM 直接放在控制器主板上远程房间温度挂在 RS-485 总线上由多个 PJ85718DM 从站节点采集最终统一汇聚到一颗 STM32L162ZE 主控。这套组合跑下来硬件调试量少了一大截数据一致性也终于稳定在需求范围内。这篇文章就把这套方案的选型逻辑、电路要点、软件流程和现场踩过的坑完整写出来。1. 方案设计为什么是“本地采集 远程汇聚”而不是全部拉线1.1 STM32L162ZE 在 HVAC 控制板里到底能省多少事很多做嵌入式控温的同事一上来就选 STM32F103 这类通用 MCU性能是够但做 HVAC 控制器这种“长期通电、可能停电、要求低功耗待机”的设备F1 系列并不算舒服。STM32L162ZE 属于 STM32L1 超低功耗系列Cortex-M3 内核最高主频 32MHzFlash 有 512KBSRAM 约 80KB。单看性能确实不亮眼但 HVAC 控制逻辑、Modbus 协议栈、LCD 显示、温度采集这几块任务放在 32MHz 下完全够用而且这颗芯片有大量低功耗模式从 Sleep 到 Stop 再到 Standby功耗能压到微安级别。对需要“断电保持 RTC、来电恢复运行”的温控器来说这个特性非常关键。另一个明显优势是片上外设齐全多个 USART 可以分别接 RS-485 远程总线和调试串口I2C 直连 PJ85718DM内置 12 位 ADC 用来做模拟量备份输入还有段码 LCD 控制器温控器面板上的数码管可以直接驱动省掉一颗外部显示驱动芯片。我在项目里去掉独立 RTC 芯片和外部 EEPROM因为 STM32L162ZE 自带 RTC 和真正的 EEPROM 区域校准参数和出厂标定值都能本地存放物料清单少了一串料故障点也相应减少。选这颗料还有一个现实原因供货稳定、封装选择多。LQFP144 封装在中小型控制板上焊起来不算难引脚间距足够常规产线贴片。对 HVAC 这类出货量大、生命周期长的设备MCU 的长期供货和可替代性比纸面性能重要得多。STM32L1 系列生命周期长代码从早期原型到量产不用大改这能省下不少维护成本。1.2 PJ85718DM 作为本地温度传感器的关键优势PJ85718DM 在这套方案里承担“本地温度”采集任务。所谓本地就是控制器自身的回风温度、面板环境温度或靠近风阀位置的温度。它是个数字输出型温度传感器I2C 接口测量范围覆盖 -40°C 到 125°C典型精度能做到 ±0.3°C 左右分辨率 0.01°C。这个精度对 HVAC 控制逻辑来说已经富余制冷/制热控制一般只要求 0.5°C 的精度和重复性真正麻烦的是传感器之间的一致性而数字传感器出厂校准能保证一致性比模拟 NTC 热敏电阻需要逐台校准要省事得多。当时我在 PJ85718DM 和另一款常见的数字温度传感器之间做了对比。另一款虽然用得更普遍但单总线协议对时序要求严苛在长线上容易受干扰而且地址扩展麻烦一条总线带多个器件时每个都要额外处理。PJ85718DM 用标准 I2C 协议主控侧可以用硬件 I2C 或者模拟 I2C速率 100kHz 到 400kHz 都能稳定跑。它还有可配置地址引脚理论上一条 I2C 总线上可以挂多个同类器件这为以后扩展测点留了余地。传感器本身功耗也很低。正常测量转换期间电流在几百微安级别空闲待机时基本在微安以下。这在电池供电的无线温控器上同样适用只是我们项目是 24V 交流供电低功耗不是为了省电而是为了降低整机温升。一个持续运行的传感器如果自热大测出来的温度会比环境实际温度高 0.3°C 到 0.8°C这在 HVAC 控制里是很讨厌的误差来源。PJ85718DM 这类数字传感器的功耗控制让自热效应小很多下面调试部分我还会专门讲这个坑。1.3 本地与远程温度的“边界”怎么划分项目标题里的“本地与远程温度”我理解不是指一个传感器测两个温度而是系统里同时存在“本地测点”和“远程测点”。本地测点是控制器所在位置的温度比如控制柜内部温度、回风温度远程测点是布置在现场远处测点的温度比如空调房间、风管末端、冷却塔进出水温度。为什么要把温度分成本地和远程两块来做因为传输方式完全不同。本地测点就在主控附近用 I2C 短距离连接走线不超过几十厘米传感器可以由主控直接供电数据读取简单可靠。远程测点动辄几十米上百米不能直接拉 I2C必须转成抗干扰的差分信号工业上最通用的就是 RS-485。我让每个远程测点做成一个带独立 MCU 的小节点节点上同样用 PJ85718DM 采样然后通过 RS-485 总线把温度值以 Modbus RTU 协议上报给主控 STM32L162ZE。这样远程节点坏了只影响单点不会拖垮整条总线而且后续加测点只要挂节点、改配置就行。这种分层的架构也方便后续扩展成无线方案。如果某些测点实在拉不了线可以把 RS-485 节点换成无线采集器主控这边仍然是同样的“轮询读取”逻辑数据源在逻辑上没变。把温度监测从传感器直接拉线改成“本地 I2C 远程总线”之后系统边界清晰每个环节可以独立测试这是我最看重的一点。2. 硬件电路与现场可靠性设计2.1 PJ85718DM 的接口电路细节PJ85718DM 和 STM32L162ZE 的连接非常常规SDA 和 SCL 两根线分别接 MCU 的 I2C 引脚数据线各加上拉电阻到 3.3V。很多工程师做 I2C 电路时会忽略上拉电阻大小默认抄 4.7kΩ。实际上在 HVAC 控制板上I2C 走线不长时 4.7kΩ 没问题但如果传感器通过排线连接寄生电容变大上拉电阻不变的话会导致边沿变缓严重时通信不稳定。我在这个项目里用 2.2kΩ 上拉电阻并把传感器尽量靠近 MCU 放置实测 100kHz 模式下波形很干净。如果你用的是 400kHz 高速模式建议上拉再降到 1kΩ 左右具体要按总线电容算。传感器供电我用了独立的 3.3V 电源并在传感器电源引脚旁边放一颗 0.1µF 陶瓷电容靠近芯片引脚。这颗电容的作用是滤除 MCU 数字电路开关带来的高频噪声。温度传感器属于模拟敏感器件电源噪声会影响内部 ADC 的参考电压导致读数跳变。我在第一版 PCB 上就吃过没加去耦电容的亏温度数据偶尔波动 ±0.1°C看起来不多但 PID 调节时就会导致输出抖动。还有传感器的地址引脚。如果需要一条 I2C 总线上挂两个 PJ85718DM地址引脚必须做不同的电平配置。我的方案里本地只挂一颗所以地址引脚直接接到 GND固定为一个地址。注意不能让它悬空悬空时内部逻辑状态不确定有时能读有时不能读非常折腾。HVAC 设备量产时要考虑 ESD传感器如果放在可接触到外部风道的探头位置I2C 线上要加小阻值串联电阻和 TVS防止静电打坏 MCU 引脚。如果是风管内的传感器我建议用独立探头壳通过排线连接到主板而不是把传感器直接裸露在风道里。2.2 RS-485 远程温度总线的靠谱做法RS-485 是远程测点的核心也是最容易出问题的地方。主控 STM32L162ZE 的 USART 接一颗 RS-485 收发芯片收发方向控制脚由 MCU 的 GPIO 管理。这里有个细节方向切换必须加延时不能数据发完立刻切回接收。我用的收发器切换时间为纳秒级但 MCU 串口发送完成标志置位时移位寄存器的最后一位可能还没发送完如果立刻拉低方向脚会截掉停止位导致对端收到错误帧。我的做法是在串口发送空中断里等待 3 到 5 个字节时间的延时再切回接收模式或者用一个足够长的总线空闲判断。实测下来丢帧率明显下降。总线两端要接 120Ω 终端电阻这是老生常谈但很多现场问题恰恰是没接终端电阻或接错位置。RS-485 总线如果只有一台主控和几个远程节点或者节点数小于 10终端电阻接在最远两端即可。我习惯在主控板上做个跳线远程最远节点的板子上也留个焊盘位现场根据实际布线决定焊不焊。还有个容易忽略的点RS-485 的 A/B 线之间可以加 120Ω 电阻同时 A 上拉到 5VB 下拉到 GND保证总线空闲时处于确定状态防止接收器输出乱跳。我们曾经因为没做偏置总线空闲时主控偶尔收到 0x00 或 0xFF 的杂波浪费了很多调试时间。远程节点供电是另一个问题。HVAC 现场往往只有 24V AC 或 24V DC远程节点需要稳压到 3.3V。我建议每个节点独立加一颗低功耗 LDO不要直接从总线上拉很长的电源线因为长距离电源压降和线间干扰会让节点复位。如果节点数多最好分区供电并在节点入口加 TVS 和保险丝。RS-485 通信线和电源线分开走不要捆在一起至少保持一定间距否则继电器、压缩机的启停干扰会直接串进通信线导致 Modbus 报文偶发错误。2.3 低功耗电源与去耦设计STM32L162ZE 的电源设计不算复杂但不能马虎。HVAC 设备通常有 24V AC 输入经过整流、滤波、开关电源得到 5V再 LDO 得到 3.3V。数字部分和模拟部分我共用了 3.3V但注意给 MCU 的电源引脚每边放 100nF 电容并集中放一颗 10µF 钽电容。传感器和 RS-485 收发器分别加 LC 滤波避免它们之间互相干扰。低功耗模式下LDO 自身静态电流可能比 MCU 还大我选了一颗静态电流几微安的 LDO这样整体待机电流才压得下来。如果你要做电池供电版本建议用 DC-DC 降压而不是 LDO效率差很多但这台设备是 24V 供电LDO 够用且安静。还要注意 MCU 未使用的引脚不能悬空。悬空引脚在低功耗模式下会引入不确定的漏电流导致 Stop 模式电流从理论上的 1µA 涨到几十微安。我把所有未使用的 GPIO 在初始化时配置为模拟输入模式ANALOG INPUT或者带下拉输入这样内部没有上拉/下拉通路也不会有输出翻转损耗。LCD 如果不显示时也要关闭段码驱动否则即使不亮LCD 驱动时钟也会耗掉不少电流。这些细节在实验室测试时未必看得出来但放到现场电池供电的无线版本上就会非常明显。3. 软件与算法让测量结果经得起现场折腾3.1 传感器驱动与数据读取时序PJ85718DM 的驱动流程我总结成三步初始化、触发测量、读取结果。初始化时先让 I2C 总线复位防止传感器处于异常状态导致总线一直拉低。然后读取产品 ID 确认器件在线这一步非常重要硬件连错了能在上电第一时间发现而不是等到读温度失败才开始查线。触发测量后传感器需要一小段转换时间。我在代码里用HAL_Delay等待足够的转换时间再进行单次读取。这里不建议读取前不做等待直接读因为有些传感器读出来的可能还是上一次的旧数据。HVAC 控制不需要极快的刷新率我把采样周期设为 1 秒。温度本身是慢变量1 秒刷新足够响应风管温度变化还能减少不必要的传感器连续工作降低自热。读取时我按高字节、低字节顺序读回原始数据并做格式转换。温度分辨率 0.01°C实际数据是整数形式。比如原始值 2500 就表示 25.00°C。这里我建议在驱动层就统一用整数运算不用浮点数MCU 是 Cortex-M3有 FPU 的型号不多即便有整数运算在传输和比较时也更可靠。显示时再统一转成带小数点的字符串这样固件体积和运行时间都更友好。代码示意如下/* 假设在 100kHz I2C1 上挂载 PJ85718DM地址为 0x48 */ #define PJ85718DM_I2C_ADDR (0x48 1) #define PJ85718DM_CMD_TRIGGER 0x10 #define PJ85718DM_CMD_READ 0x20 #define PJ85718DM_MEAS_TIME_MS 12 int16_t pj85718dm_read_temperature(void) { uint8_t tmp[3]; uint8_t cmd; /* 1. 触发测量 */ cmd PJ85718DM_CMD_TRIGGER; HAL_I2C_Master_Transmit(hi2c1, PJ85718DM_I2C_ADDR, cmd, 1, 10); /* 2. 等待转换完成 */ HAL_Delay(PJ85718DM_MEAS_TIME_MS); /* 3. 读取结果 */ cmd PJ85718DM_CMD_READ; HAL_I2C_Master_Transmit(hi2c1, PJ85718DM_I2C_ADDR, cmd, 1, 10); HAL_I2C_Master_Receive(hi2c1, PJ85718DM_I2C_ADDR, tmp, 2, 10); /* 4. 组合为整数温度原始值除以100表示摄氏度 */ return (int16_t)((tmp[0] 8) | tmp[1]); }这段代码是完整可运行的思路。实际项目中我还加了延时上限保护如果 I2C 等待超时或返回错误就把本次数据标记为无效不进入滤波队列。这是为了避免把异常值当作真实温度去调节压缩机和风阀。3.2 滤波、标定与误差补偿HVAC 现场的温度数据不是干净的。压缩机启停、风阀动作、门开关都会造成温度瞬间波动或者传感器附近有热风直吹单次采样值跳动明显。我采用“中值滤波 滑动平均”两级处理先对最近 5 个原始数据取中值剔除明显的毛刺再对中值结果做 4 次滑动平均抑制低频波动。这个组合比单纯取平均更能抵抗突发干扰实测 PID 输出的稳定性有了明显改善。标定是温度监测系统绕不开的一步。虽然 PJ85718DM 出厂就有校准但实际安装位置、传感器线缆、外壳热阻都会带来系统偏差。我做了两点校准冰水混合物的 0°C 点和 45°C 恒温水浴点读出两个原始值后计算斜率和截距。公式很简单真实温度 原始温度 × 斜率 截距 斜率 (T2 - T1) / (Raw2 - Raw1) 截距 T1 - Raw1 × 斜率标定后的斜率和截距我用 STM32L162ZE 的内部 EEPROM 保存量产时每台设备写入自己的校准参数。这里有个经验标定时必须让传感器完全达到热平衡探头要浸入液体足够深至少等 3 到 5 分钟再读数否则标定本身就是错的。我们有一次标定结果批量偏差 0.2°C反复查是因探头没有完全插入恒温槽导致热传导路径不对。还有自热补偿。传感器在工作时会发热尤其连续转换模式下功耗达到几百微安时自热升温可能到 0.2°C 左右。我在代码里做了固定补偿传感器连续工作时间越长补偿值越大。更稳妥的算法是每次测量前让传感器先进入休眠需要测量时再唤醒最大程度减少持续发热。PJ85718DM 功耗本身不高我最终采用了“测量 12ms休眠 988ms”的 1 秒周期策略把自热影响降到很低。3.3 远程温度轮询与故障超时机制远程温度读取采用主从模式STM32L162ZE 作为 Modbus RTU 主站周期轮询各个远程节点。轮询周期我设为 2 秒因为 HVAC 温度变化慢2 秒已经足够。每个远程节点的地址在这套设计里对应一个房间或测点通过板载拨码开关配置。主站发送读保持寄存器命令从站返回温度值。这里的核心是超时和异常处理。RS-485 总线在工业现场总会遇到节点掉线、线路短路、从站程序跑飞等情况。如果不设超时主站会一直阻塞等待响应其他测点全部瘫痪。我实现了“单点超时 200ms、整轮扫描最多容忍一个节点失败”的策略。某个节点超时后标记该测点无效但继续轮询下一个节点连续 3 次超时判定该节点离线并上报故障信息。温度显示界面上对应通道显示“---”方便现场排查。Modbus 报文的 CRC 校验一定要做不能偷懒。很多“偶发错误”都是 CRC 不收造成的。我在代码里实现了标准 CRC16-Modbus 算法每帧报文发送前计算接收后校验。虽然会增加一点 CPU 开销但 STM32L162ZE 在 32MHz 下算 CRC 毫无压力。远程节点读回来的温度同样进入前面的滤波和标定流程只是标定参数需要按测点分别存储因为每个远程节点的传感器偏移可能不一样。远程通信还有一个非常重要的细节485 总线上收发的机械结构有时会松动导致接触电阻变大波形变形但仍有部分数据通过。我在代码里统计了 CRC 错误计数和通信重试次数把这些诊断参数作为设备状态的一部分上报这样在还没完全断连时就能提前发现总线接触不良避免现场彻底失效后才被动维修。3.4 低功耗调度与数据上报STM32L162ZE 低功耗调度的核心思想是“按需工作、长时间睡”。温度采集和数据上报是周期任务不需要连续占用 CPU所以主流程用 RTC 唤醒的 STOP 模式运行。正常工作时序大致是RTC 唤醒 → 启动本地测量 → 读取本地温度 → 轮询远程温度 → 刷新 LCD → 通过串口/总线向外上报 → 进入 STOP 等待下一个周期。这里有个坑STOP 模式唤醒后外设时钟不会自动恢复。如果用了 HAL 库需要在唤醒后调用恢复时钟和重新配置外设的函数。我曾因为漏了这一步唤醒后 I2C 读传感器直接卡死查了半天才发现是时钟树的问题。更稳妥的做法是只在需要通信时开外设任务结束后立即关闭这样既省电又减少外设间干扰。如果设备通过 RS-485 与上位机通信上位机可能随时下发命令不能完全睡眠。我设计了“睡眠窗口”机制默认每 100ms 醒来一次短暂检查串口是否有数据有数据则进入完整处理流程无数据则立即回到 STOP。这样待机电流还能保持在个位数微安级别响应时间也在可接受范围。对于 HVAC 这种常供电设备低功耗的意义更多在于降低发热、延长电容寿命但在很多电池供电的恒温器产品里这套调度可以直接复用。4. 现场调试实录与问题速查4.1 典型坑一传感器过度自热导致本地温度偏高第一版样机测试时本地回风温度比标准水银温度计读数高了约 0.6°C产品经理直接找过来问是不是传感器选错了。我排查了传感器安装位置、PCB 发热元件、供电电压最后发现是 PJ85718DM 连续转换导致的自热累积。数据手册上单次转换功耗不高但如果让传感器一直处于连续测量模式热量积累不可小觑尤其传感器放在靠近 MCU 大电流区域时误差更加明显。解决方案有两层软件上改成周期测量1 秒内只工作 12ms其余时间关闭传感器电源或让传感器进低功耗模式硬件上把传感器从 MCU 发热区移开并在 PCB 上做局部开槽减少热量传导。最终校正后本地温度显示与标准温度计偏差控制在 0.2°C 以内。这里也给同样做嵌入式测温的朋友提个醒数字传感器标称精度高只代表芯片本身的测量能力实际系统精度会被安装结构和热环境大幅影响必须当作系统问题来对待。4.2 典型坑二远程读数偶尔报 0xFFFF 或 FF远程节点调试时主控偶尔会读到 0xFFFF造成温度显示成 -0.01°C 或者异常值。一开始我怀疑是传感器坏了但换一个仍有问题。后来用示波器抓 RS-485 A/B 波形发现总线在空闲时电平不确定接收器偶尔输出随机数据。这是因为总线没有加偏置电阻当所有节点都不驱动总线时电平接近阈值接收端就会“自由发挥”。我在总线上加了 A 线上拉、B 线下拉的偏置网络并检查终端电阻位置正确后0xFFFF 现象消失。另外我在软件里也加了数据合理性判断温度超出 -40°C 到 125°C 范围的数据直接丢弃并记一次通信异常。物理层问题和软件防御同时处理才让系统在真实项目里足够稳。4.3 标定与误差排查表格现象可能原因排查方法解决手段本地温度整体偏高 0.5°C传感器靠近发热器件或自热用热成像仪查看 PCB 温度分布关闭发热器件测试移开传感器位置软件周期测量远程温度波动大总线干扰、屏蔽层接地不良示波器观察 A/B 波形检查屏蔽层是否单端接地改单端接地加磁环降低波特率读数偶尔为 0xFFFF485 总线空闲电平不确定测量 A/B 之间静态电压A 上拉B 下拉加终端电阻传感器 I2C 有时无响应上拉电阻过大、走线过长抓 I2C 波形看边沿斜率减小上拉电阻到 2.2kΩ标定后仍然偏差探头热平衡不充分重新对比恒温槽读数延长热平衡时间到 5 分钟低功耗待机电流偏高GPIO 悬空、外设未关闭逐一断开外设测量电流将未用 GPIO 设为模拟输入这张表是我在这个项目里反复用到的排查清单基本能覆盖 90% 的现场温度测量问题。排查顺序建议从物理层开始先确认电源、地在连接上没问题再抓波形最后才怀疑协议和软件。很多人一上来就改代码浪费大量时间结果发现是某根线松了或者初始值没设置对。4.4 关于 HVAC 温度监测的几条经验总结就我个人经验来说HVAC 温度监测项目的成败往往不在 MCU 选型和传感器精度而在系统层面的“一致性”和“可维护性”。本地温度用 I2C 数字传感器直连远程温度用 RS-485 总线集中轮询这套架构最大的优点是每级都可独立测试传感器驱动在单板上验证远程节点单独跑再用主控统一采集问题定位非常快。相比以前模拟 NTC 一锅端的做法现场调试时间至少省了一半。最后再分享一个小技巧在固件里给每个温度通道加一个“数据新鲜度”时间戳任何通道超过 5 秒没更新就显示异常并报警。这比单纯读温度值更有用因为现场最怕的不是温度不准而是温度数据“看起来正常但其实是旧值”。加了时间戳后节点掉线、传感器故障、通信拥塞都能第一时间暴露这套机制后来也被用到了其他项目上。