想用一块单片机同时管好设备内部的“体感温度”和远端风道的“环境温度”这事听起来简单真做起来会有不少细节。最近我完成了一个基于 PIC32MX795F512L 与 PJ85718DM 的双区域温度监测方案主要用在嵌入式设备柜和 HVAC 送风回风系统里把本地与远程两路温度一起纳入管理。如果你正在做温控、楼宇自控或者只是想给现有设备加一个稳一点的上报功能这篇内容应该能帮你省掉不少弯路。这个方案不算复杂但涉及的点很杂传感器节点设计、主控最小系统、单总线时序、滤波校准、RS485 远程上报每一环都有坑。下面我按从方案到硬件、再到固件和现场调试的顺序写尽量把我踩过的坑和验证过的方法都列清楚。1. 项目拆解本地与远程温度监测的系统思路1.1 本地与远程到底差在哪里很多朋友一看到“本地与远程温度”第一反应是“温度不都是一个传感器读出来的吗”。实际上这套系统里的“本地”和“远程”有两个完全不同层面的含义。物理层面上本地温度指传感器和主控在同一块板子或者同一个机柜内部比如嵌入式控制器内部的功率芯片附近、电源模块旁边、密闭机箱里的空气温度。这个位置走线短、反馈快但干扰源也近MCU 自身发热、DC-DC 电感辐射、继电器吸合瞬间的尖峰都会叠加到传感器信号上。远程温度则是把探头拉到风道、天花板、冷库或者几米外的设备间里走线长、环境恶劣还可能有变频器、风机电机在旁边制造共模干扰。逻辑层面的差异同样重要。本地温度通常用于自我保护比如机柜内温度超过 75°C 就降频或关断远程温度则用于舒适性控制或能耗管理比如新风温度、回风温度、房间温度。两者用途不同采样周期、滤波时间常数、报警阈值都应该独立配置。把这些先想清楚后面选传感器、画板子、写协议才不会乱。1.2 为什么用 PIC32MX795F512L 搭配 PJ85718DM选型的时候我看过几类方案用简单 8 位单片机加模拟热敏电阻、用一颗带多点采集的总线温度传感器或者直接用带无线功能的模组。最后留下来的是 PIC32MX795F512L 加 PJ85718DM 这个组合原因比较实际。PJ85718DM 是数字式温度传感器内部集成 ADC直接输出数字量一条数据总线上可以挂多个节点非常适合在多处布点。它不像模拟热敏电阻那样需要每个通道分配一个 ADC 引脚也不用担心长线传输时模拟信号衰减。对 HVAC 这种要拉线到风道、天花板、回风口的场景来说接线这根线很省心。PIC32MX795F512L 这边的优势是接口丰富度和计算余量。它有 512KB Flash、128KB RAM主频可以跑到 100MHz 左右还带着以太网 MAC、CAN、USB、多个 UART 和 SPI/I2C。这意味着本地采集可以留一个 GPIO 给温度总线远程上送可以用 UART 接 RS485将来想升级以太网上报也不用换主控。嵌入式系统最怕选型时算得太死预留 30% 到 50% 的资源余量后期会舒服很多。用一个生活化的比喻来说PJ85718DM 是分布在各个楼层的温度计PIC32 是物业中心一根电话线把所有温度计串起来物业中心再通过对外专线把汇总数据递给上级管理平台。温度计只管精准感知汇总、判断、上报这些统筹工作交给主控。1.3 数据流、告警与远程上报的边界整套系统的数据流是这样的PJ85718DM 把物理温度转成数字量通过单总线送到 PIC32MX795F512L主控做滤波、阈值判断驱动本地继电器或风扇同时把处理后的温度值写入 Modbus 寄存器等待远程主机通过 RS485 来读取。远程主机可能是触摸屏、组态上位机、PLC 或者楼宇管理系统BMS。这里有一个很重要的边界决策尽量放在主控本地远程只负责监控和修改参数。这样即使和远程通讯中断本地超温保护依然能工作。很多 HVAC 项目事故就是因为设备过度依赖上位机上位机一卡整个系统就失联了。所以我在实现时把报警、风扇联动、传感器断线检测都放在单片机里Modbus 中断只会报状态不会影响本地控制逻辑。2. 硬件设计传感器、主控与远程接口怎么搭2.1 先搞定 PJ85718DM 传感器节点先把传感器节点处理好后面会少很多麻烦。PJ85718DM 这种数字温度传感器通常只需要三个引脚电源、地、数据。如果总线上传感器数量不多、距离短可以共用一组电源和地数据线统一接在主控的一个 IO 上。数据线上必须接上拉电阻常见做法是 4.7kΩ 左右。上拉太小会让总线负载变重上拉太大则可能因为线缆分布电容导致波形上升沿太慢读取时序出错。供电方式上短距离推荐直接用 3.3V 供电。如果现场总线长度超过一米建议每个传感器节点独立接电源线和地线不要只靠数据线供电不然远端传感器在转换电流较大的瞬间会造成电压跌落读数跳变甚至掉线。现场布线的经验法则是尽量走菊花链也就是一根总线从主控出发依次经过每一个传感器而不是从主控接出好几条分叉。分叉拓扑在传感器数量多、线缆长的时候特别容易出现信号反射表现就是偶尔读错数据、CRC 校验失败。如果工程上实在避免不了星形接法每个分支线尽量控制在 20 厘米以内并且把上拉电阻调到 2.2kΩ 到 3.3kΩ 之间增强驱动能力。注意传感器数据线不要和变频器输出线、继电器线走同一根线槽。如果必须平行走线中间留出至少 5 到 10 厘米间距。温度总线虽然不是高速信号但 HVAC 现场电机启停的干扰非常猛有时候能直接把你总线上的数据打成乱码。2.2 PIC32MX795F512L 最小系统与供电隔离PIC32MX795F512L 是 3.3V 器件电压范围一般可以接受 2.3V 到 3.6V 左右但为了让 ADC、Flash 和内部稳压器稳定工作我习惯把电源做到 3.3V ±1%。板子上主控电源引脚附近放 100nF 陶瓷电容每个电源引脚至少一个再加一颗 10uF 钽电容或者陶瓷电容做低频去耦。复位电路用经典的电阻电容复位即可但要注意上电时间MCU 的复位释放时间要大于电源爬坡时间否则可能出现上电时序不稳定导致偶尔启动失败。时钟部分PIC32MX 系列可以使用外部晶振加 PLL。我用了 8MHz 晶振通过配置 PLL 倍频到 80MHz 或 100MHz。这个主频下做单总线时序、Modbus CRC 运算都绰绰有余。需要提醒的是晶振引脚周围不要走开关电源的电感或脉冲电流路径否则时钟抖动会让 UART 的波特率误差变大RS485 传输偶尔出现乱码。供电和隔离是嵌入式设备柜里的重点。如果控制器外壳里同时有继电器、开关电源和单片机地线电位在继电器动作瞬间可能跳动很大。RS485 远程总线一般建议做电气隔离隔离型 RS485 收发器加隔离 DC-DC或者用数字隔离器把 UART 信号隔开。温度传感器总线如果只在本机柜内可以不隔离但传感器端的地和主控地必须可靠连接不能靠外壳接地勉强凑合。做过几个现场项目之后我的结论是电源和地处理好能解决一半以上的“偶发故障”。很多温度读数飞跳追到根上不是传感器不行而是主控电源纹波太大或者地线环路把电机噪声引入了传感器。2.3 远程通信接口的选型与现场布线远程温度上报我优先选了 RS485 半双工接口因为 HVAC 现场最常见、兼容性最好很多楼宇自控系统的网关都直接支持 RS485 Modbus。RS485 是差分信号抗共模干扰能力强理论传输距离到 1200 米实际工程控制在 800 米以内更稳妥。接线时有几个点容易翻车。第一A/B 两个信号线不要接反接反的直接后果是整个总线上所有设备都通信失败。第二总线两端要接 120Ω 终端电阻而不是每个设备都接。很多设备板上会默认带一个终端电阻如果每个板子都短接等效阻抗会低于 120Ω导致信号反射和通讯距离缩短。第三屏蔽双绞线屏蔽层单端接地不要两端都接大地否则可能形成地环路低频干扰反而更严重。如果把远程上报扩展到以太网PIC32MX795F512L 自带 MAC可以外接以太网 PHY 芯片和网络变压器走 RMII 接口。这样主控可以通过 Modbus TCP 或者 MQTT 上报温度。对 HVAC 这种长期运行设备我建议网络流量尽量小每 5 到 10 秒上报一次足够没必要追求秒级刷新。3. 固件实现单总线驱动、滤波和 Modbus 上报3.1 单总线时序与底层驱动写单总线驱动前一定要把时序图和数据手册放在手边。这类数字温度传感器的通信协议通常基于单总线核心动作只有三个复位、写位、读位。复位时主机拉低总线至少 480 微秒然后释放传感器会在 15 到 60 微秒内拉低总线作为存在脉冲。写位时主机先拉低总线如果要写 0就保持低电平超过 60 微秒要写 1则只保持短暂的低电平后立即释放让上拉电阻把总线拉高。读位时主机拉低总线一小段时间后释放然后在 15 微秒内采样总线电平。这些时间窗口只有几十微秒而且对延时有严格要求。我一开始偷懒用了普通空循环做延时结果不同编译优化级别下读到的温度完全不一样。后来老老实实用定时器做了微秒级延时函数或者用带 volatile 变量的循环来避免被优化掉。下面是一段简化版驱动逻辑上可以直接参考但延时参数必须按实际传感器手册调整#include stdint.h #define OW_LAT LATBbits.LATB8 #define OW_TRIS TRISBbits.TRISB8 #define OW_PORT PORTBbits.RB8 #define CMD_SKIP_ROM 0xCC #define CMD_CONVERT 0x44 #define CMD_READ_SCRATCH 0xBE // 延时函数依赖主频移植时请重新标定 static void ow_delay_us(int us) { volatile int i; while (us-- 0) { for (i 0; i 10; i); } } static uint8_t ow_reset(void) { uint8_t presence; OW_TRIS 0; // 输出模式 OW_LAT 0; // 拉低 ow_delay_us(480); OW_LAT 1; // 释放 OW_TRIS 1; // 输入模式 ow_delay_us(70); presence OW_PORT; // 读取存在脉冲 ow_delay_us(410); return (presence 0) ? 1 : 0; } static void ow_write_bit(uint8_t bit) { OW_TRIS 0; OW_LAT 0; ow_delay_us(8); if (bit) { OW_LAT 1; ow_delay_us(60); } else { ow_delay_us(60); } OW_LAT 1; OW_TRIS 1; ow_delay_us(2); } static uint8_t ow_read_bit(void) { uint8_t bit; OW_TRIS 0; OW_LAT 0; ow_delay_us(2); OW_LAT 1; OW_TRIS 1; ow_delay_us(6); bit OW_PORT; ow_delay_us(55); return bit; } static void ow_write_byte(uint8_t byte) { for (uint8_t i 0; i 8; i) { ow_write_bit((byte i) 0x01); } } static uint8_t ow_read_byte(void) { uint8_t byte 0; for (uint8_t i 0; i 8; i) { if (ow_read_bit()) { byte | (1 i); } } return byte; } float read_local_temperature(void) { uint8_t scratch[9]; int16_t raw; float temp; ow_reset(); ow_write_byte(CMD_SKIP_ROM); ow_write_byte(CMD_CONVERT); ow_delay_us(750); // 等待转换完成 ow_reset(); ow_write_byte(CMD_SKIP_ROM); ow_write_byte(CMD_READ_SCRATCH); for (uint8_t i 0; i 9; i) { scratch[i] ow_read_byte(); } raw (scratch[1] 8) | scratch[0]; temp raw * 0.0625f; return temp; }代码里我用了一颗传感器时的快速读取方式。多传感器场景不能直接跳过 ROM需要先枚举总线上的设备 ID。单总线类数字温度传感器一般都会内置唯一序列号固件在初始化时做一次总线搜索把所有 ID 存到数组里之后轮询每个 ID 读取温度。第一次写总线搜索算法会觉得麻烦但写完之后一劳永逸后续插拔传感器都能自动识别。3.2 多点温度采集与滤波策略HVAC 现场常见需求是挂 2 到 4 个传感器分别是本地机柜温度、送风温度、回风温度、室外温度。多点采集时我建议先发一次全局转换命令然后根据传感器最大转换时间等待再逐个读取。这样比挨个发转换、挨个等待要快得多。采集到原始温度后不要直接把读数拿去报警或上报因为传感器本身会有随机噪声HVAC 现场还有风机引起的温度扰动。我用一阶低通滤波公式很简单filtered filtered * 0.8f current * 0.2f;如果采样周期是 1 秒这个滤波相当于时间常数约 5 秒既不会掩盖设备柜突然过热的趋势又能把风道里风速变化引起的毛刺修平滑。如果采样周期是 500ms可以把系数改成 0.9 和 0.1。想更平滑也可以改成二阶滤波但对温度控制来说没必要响应太慢反而会造成报警滞后。滤波参数放在配置区现场可以通过 Modbus 写寄存器调整。默认给一套稳妥的值运维人员后续可以根据实际环境微调。这个设计在项目验收时特别加分因为现场调试人员往往想自己调灵敏度。除滤波外我还会做传感器断线检测。单总线设备长时间无应答、CRC 校验连续失败三次就标记该通道温度无效同时把故障标志写到 Modbus 寄存器。不要用某个特殊温度值来表示故障比如“-55°C”否则上位机容易把故障和真实低温混淆。3.3 Modbus RTU 从机与寄存器设计远程上报我用了 Modbus RTU 从站协议功能码只开放 04 读输入寄存器最多加一个 03 读保持寄存器保存配置参数。对温度监测来说功能码越少越安全别把不必要的历史数据区暴露给总线。寄存器设计上尽量简单寄存器地址说明数据格式40001本地温度0.1°C有符号40002远程温度0.1°C有符号40003报警状态bit0 本地超温bit1 远程超温40004传感器故障标志bit0 本地传感器断线实际代码里Modbus 通信最重要的是 CRC16 校验。少写了 CRC或者高低字节顺序写反都会导致主站一直报超时。uint16_t modbus_crc16(uint8_t *buf, uint16_t len) { uint16_t crc 0xFFFF; for (uint16_t i 0; i len; i) { crc ^ buf[i]; for (uint8_t j 0; j 8; j) { if (crc 0x0001) { crc (crc 1) ^ 0xA001; } else { crc 1; } } } return crc; }接收帧我用状态机实现第一步匹配从机地址第二步等待功能码第三步累计数据长度第四步校验 CRC。校验通过后解析数据段校验失败直接丢弃。不要在中断里做完整解析可以把接收到的字节缓存起来在主循环里统一处理。中断里做太多计算UART 接收会有概率丢字节。通信参数我默认配置为 9600bps、8 数据位、1 停止位、无校验。这个配置在楼宇自控领域最兼容。如果现场对实时性要求高可以改到 19200bps但总线长度超过 500 米时不建议再往上升速率越高RS485 对线缆质量和终端匹配越敏感。4. 调试记录现场问题、排查与标定4.1 高频问题速查表这套系统现场调试过程中我遇到最多的问题集中在表格里这几种。如果你也碰到类似现象可以直接对照排查。现象可能原因处理建议读不到任何传感器总线上拉电阻缺失、传感器供电异常、接线断路先量传感器两端电压再量数据线和 GND 之间有没有上拉到 3.3V传感器序列号时有时无数据线接触不良、总线星形分叉太长检查端子压接尽量改成菊花链读数一直是上电默认值 85°C 左右只读了暂存器没发转换命令或转换等待时间不够确认固件先发 CONVERT 命令并等待足够时间数据经常 CRC 错误线缆过长、上拉电阻不合适、干扰串入缩短总线、换屏蔽线、调整上拉电阻必要时用隔离方案多个传感器读数互相串跳过 ROM 命令时总线冲突或多个传感器共用一个地址枚举并区分每个传感器 ROM IDModbus 主站无响应从机地址不对、波特率不匹配、A/B 接反、终端电阻问题用串口调试助手直连从机确认设备地址和参数调试的时候我习惯先用一个独立串口把单片机收到的原始单总线数据打印出来确认传感器链路正常再测 Modbus 报文。这样能快速把问题分隔开是采集层有问题还是协议层有问题。如果不分层排查经常会在一个其实没坏的传感器上浪费半天。4.2 温度传感器的两点标定数字温度传感器出厂的绝对精度通常够用但如果项目要求误差在 ±0.5°C 以内或者现场环境导致传感器有固定偏差我会做两点标定。方法很简单准备两个稳定温度源比如冰水混合物大约 0°C以及一个稳定的温水浴大约 40°C 到 60°C。用参考温度计记录实际温度同时读出传感器的原始值然后计算斜率修正和偏移修正。假设参考温度和传感器读数的关系是线性T_actual K * T_sensor B先测两点得到两组值然后计算K (T2_actual - T1_actual) / (T2_sensor - T1_sensor) B T1_actual - K * T1_sensor把 K 和 B 存入 Flash 或 EEPROM每次采集后代入。需要提醒的是校准温度源越接近传感器实际工作范围越好不要在 0°C 校准完直接拿到 80°C 环境用线性误差会让高温段的偏差反而变大。传感器自热是读数偏高的一个隐藏原因。PJ85718DM 这类传感器本体在持续工作时会有轻微温升如果传感器贴在发热元件或密闭不透风的位置即使做了软件校准长期读数也会跟着环境热往上涨。我在安装时尽量让传感器探头与被测物体接触良好同时避免传感器和功率电阻、大电流走线靠太近。4.3 长期运行稳定性的几个细节嵌入式设备一旦投运可能是两年三年不关机。针对长期运行我在固件里加了几个保险措施。单总线操作必须带超时。复位、读位、写位这些操作如果不加超时判断一旦总线被外接故障设备拉死主控会卡在单总线驱动里出不来。一个 100ms 超时保护加进去能保证最坏情况下系统还能重新初始化总线。看门狗要喂但不能盲喂。UART 接收中断里喂狗会导致主循环卡死时设备看起来还挺正常故障迟迟暴露不了。我习惯在主循环末尾喂狗并且给每个周期性任务加执行时间统计超过预期的任务要打日志。这样看门狗复位的记录才能帮你定位问题。现场还有一个非常容易踩的坑手持编程器或者调试器连接上之后总线时序被调试中断打断温度读取偶尔失败。这不是代码问题是调试器占用 CPU 造成的。出现这种情况时先拔掉调试器再测试别在烧录器挂着的时候判断产品稳定性。5. 从测温到控制组网、PID 与 HVAC 联动5.1 多站点组网与云端上报单台设备测温意义有限真正有价值的是一套系统里几十台设备同时上报温度。用 RS485 组网时每个从机设置独立地址上位机按地址轮询。轮询周期不要太短几十台设备每秒轮询一遍会占满总线我一般设置 500ms 到 1s 轮询一次实时温度、5s 同步一次配置即可。如果需要上云RS485 可以先接一个网关把 Modbus RTU 转成 MQTT 或 Modbus TCP。网关只做协议转换不过度处理数据。这样单片机端的固件不用跟着平台换将来换云平台只需要改网关配置。组网之后每台设备唯一的标识建议由硬件拨码和 MAC 地址共同构成避免现场更换设备后云端出现重复 ID。上报数据时把本地温度和远程温度分开作为两个字段。例如 HVAC 场景里本地温度对应“机组电气室温度”远程温度对应“送风管温度”两者在云端的意义完全不同。不要笼统地合并成“温度1、温度2”早期我吃过这个亏运维人员看曲线根本分不清哪条是送风温度后来把所有字段的物理含义写清楚了才好用。5.2 HVAC 联动控制的控制逻辑切入点温度监测最终要服务于控制。在 HVAC 应用里最常见的需求是当送风温度超过设定值加大风机转速或打开冷水阀当回风温度过低减小阀门开度防止过冷。PIC32MX795F512L 有 PWM 输出和丰富定时器资源可以直接输出 0-10V 或 PWM 信号控制模拟设备也可以通过继电器做分步启停。做联动控制时控制策略有一个常见误区直接把两个温度平均后作为反馈。实际上本地温度和远程温度的动态特性完全不同。本地机柜温度对风机动作响应很快远程风道温度响应慢得多两者加权平均会让控制环震荡。我通常的做法是远程温度作为主反馈决定制冷或加热的基准量本地温度作为保护反馈只在超过安全阈值时叠加修正或直接限制输出。通俗说就是“远处管舒适本地管安全”。如果要做 PID采样周期 1 秒就够比例项和积分项可以先用经验值粗糙调定。温度变化慢积分时间不用太短否则容易积分饱和。现场调 PID 时先把 P 调大看震荡然后减半再慢慢加 I这是笨办法但很可靠。6. 最后想分享的几条现场经验6.1 把传感器捏在手里先验证链路调试的时候我特别推荐一个土办法把传感器捏在手指间看着温度曲线有没有立刻往上升。如果读数纹丝不动大概率是时序或接线问题不是传感器坏了。如果数据跳来跳去再查滤波和干扰。这套方式能最快把“采集链路”和“业务逻辑”隔离开。很多时候我在现场折腾半天最后发现是传感器没接牢、接触电阻时大时小手一捏倒是碰巧压紧了问题反而不见了。6.2 精度是否够用要看监测对象做温度监测不需要盲目追求高精度。HVAC 应用的舒适性控制±0.5°C 的重复性比绝对精度重要设备机柜过热保护更看重趋势变化和响应速度偏差一两度也不致命。真正重要的是系统稳定、数据连续、故障能及时暴露。所以我在这个项目里没有堆高精度器件而是把更多精力花在线缆、隔离、滤波、看门狗和断线检测上这些才是长期运行里最影响体验的部分。项目做完回头看硬件和固件都不复杂但每一步都藏着行业经验的取舍。希望这篇内容能帮正在做类似温度监测项目的你少踩几个我已经踩过的坑。
阅读完成 · 觉得有帮助?