做嵌入式的朋友应该都有体会温度监测这种需求看着不起眼真正落地的时候却一点不简单。最近我给一套HVAC控制器做升级核心任务就是把本地机柜温度和远端风管、室外温度一起监测起来主控选了PIC32MX664F064L温度前端用了PJ85718DM。这套组合做完之后本地温度直接挂在I2C总线上读取远程温度走RS485总线轮询多个采集节点整体跑下来相当稳定。这篇文章就把我这套方案的选型思路、硬件连接、固件实现以及踩过的坑都整理出来给正在做嵌入式温度监测或者HVAC控制项目的朋友一个参考。整个项目解决的核心问题很明确温度数据既要读得准还要传得稳。所谓“本地”是指主控板上或机柜内的温度走线短、响应快用于保护逻辑和实时控制所谓“远程”是指几十米甚至上百米外的风管、冷热水管、室外环境温度需要抗干扰、支持长距离传输还要能挂多个测点。如果你也遇到类似的多点测温需求这篇文章可以直接照着改。1. 从项目需求聊聊方案选型1.1 本地温度与远程温度为什么要分开做很多人一开始会想既然都是测温把所有探头都挂一根总线上不就行了实际操作下来本地和远程分开做才是省心的做法。本地温度有几个特点一是测点离主控近信号路径短几乎不存在传输损耗问题二是数据要频繁刷新HVAC控制器里本地温度往往参与PID调节和过温保护延迟一秒钟都可能让控制逻辑走样三是维护方便坏了直接换传感器就行。远程温度则完全不同。现场传感器可能要拉到几十米外的风道里甚至要穿过强电走线槽直接用I2C这种板级总线拉长线时序、电容、干扰都是大问题。所以我把远程通道单独做成RS485总线每个远端采集节点上面放一个PJ85718DM把温度数据先变成数字量再通过Modbus RTU协议回传给主控。两条通道分开之后还有一个额外的好处本地通道和远程通道的校准、报警阈值、故障恢复策略都可以独立配置调试的时候也方便定位问题。1.2 主控为什么选了PIC32MX664F064L选主控的时候我对比过8位机、Cortex-M0和PIC32MX系列最后定了PIC32MX664F064L。首先看资源。PIC32MX664F064L属于中高端型号引脚数量比较充足I/O口能覆盖多个传感器接口、RS485收发器的方向控制引脚、报警输出、状态指示灯和现场调试接口不用为引脚打架发愁。主频在80MHz级别处理温度滤波、Modbus解析、状态机轮询完全够用还留了不少余量给后续扩展。其次看外设。这个型号带多路UART、I2C、SPI还有DMA和输入捕捉尤其适合做“传感器网关”这类角色。一个UART走RS485远程总线一个I2C接本地传感器再留一个UART做调试日志外设数量刚好不需要额外扩展芯片。还有一个实际原因团队对PIC32的开发环境比较熟原厂的配置工具生成初始化代码很方便后面维护固件也省事。选型这事儿性能和生态都得看不能只盯着纸面参数。1.3 温度前端PJ85718DM一颗I2C传感器能解决什么温度传感器我选的是PJ85718DM一颗数字输出的I2C温度传感器。它内部集成了测温单元和模数转换直接输出数字量分辨率做到0.1°C级别典型精度在±0.5°C左右这个指标在HVAC场景里完全够用。选数字传感器而不是NTC热敏电阻最重要的原因是省掉了一堆标定工作。NTC虽然便宜但一致性差、非线性强每一路都得单独做校准表批量生产时很痛苦。PJ85718DM出厂就带校准固件里直接读寄存器换算成温度就行。另外它支持I2C总线寻址同一根总线上可以通过地址引脚区分多个器件扩展测温点很方便。我在这套方案里本地通道用了它远程采集节点上也用了它整个项目下来只维护一种传感器型号备件和BOM都简单。2. 硬件搭建从原理图到PCB的工程细节2.1 供电、去耦与I2C上拉电阻计算温度传感器的供电看起来简单实际坑不少。PJ85718DM的工作电压范围大概在2.7V到3.6V我统一用3.3V供电。每个传感器旁边都放了100nF陶瓷电容做高频去耦同时在主控板的电源入口放了一个10uF的钽电容稳住低频波动。I2C上拉电阻这个参数值得单独说说。I2C总线要求SCL和SDA必须有上拉电阻阻值大小直接影响通信质量和功耗。阻值太大总线上升沿变缓通讯速率上不去阻值太小灌电流太大总线可能拉不高。标准I2C通讯速率是100kHz一般I2C总线上拉电阻取4.7kΩ比较稳妥。如果是长距离走线或者挂多个设备总线上分布电容增加要根据实际情况减小到2.2kΩ甚至1kΩ但要算一下拉低时的电流是否超过器件允许的灌电流。计算公式大概是上拉电阻最小值等于(供电电压 - 器件低电平最大值)除以器件灌电流最大值最大值则由总线最大上升时间和总线电容决定。现场调试时我会先用示波器看SCL上升沿上升沿太缓就适当减小电阻。2.2 本地温度通道设计本地温度通道我放在了主控板上传感器离MCU只有几厘米。这样设计的好处是走线短I2C信号质量几乎没有悬念而且这个温度值可以代表控制板内部环境温度用来监测机柜散热和过温保护。接线很简单VDD接3.3VGND接地SCL、SDA分别连到PIC32MX664F064L的I2C1引脚。PJ85718DM的ALERT报警输出引脚我也没有浪费把它接到MCU的一个外部中断引脚上。这样温度超过阈值时传感器硬件会产生中断信号MCU不用持续轮询也能及时响应。有一点要注意I2C上拉电阻放在哪一端。实践中我把上拉电阻放在MCU端而不是传感器端这样如果传感器被拔掉或者线缆断开总线仍然有确定的电平不会因为浮空导致误读。2.3 远程温度通道的RS485组网设计远程通道是我这次项目里最花心思的部分。远程节点分散在不同位置有的在风管旁边有的在室外防护箱里距离从十几米到上百米不等所以不能直接用I2C拉线我选择了RS485总线。组网拓扑是这样的主控板上用一片RS485收发器把PIC32MX664F064L的UART信号转换成差分信号然后通过屏蔽双绞线串联连接各个远端采集节点。每个远端采集节点由三部分组成RS485收发器、一颗PIC32系列小单片机以及一颗PJ85718DM传感器。远端单片机负责把本地的I2C温度数据打包成Modbus RTU报文再通过RS485总线发回主控。RS485方案的优势很明显差分信号抗共模干扰能力强传输距离可以达到1200米而且支持总线挂载多个节点。代价是每个远端节点都要有电源和单片机系统成本高一些但换来的是稳定性和可扩展性。实际接线时我在总线两端各放了一个120Ω终端电阻。这个电阻是匹配传输线阻抗用的没有它高速信号会在末端反射导致波形畸变。另外RS485的A、B线一定要用双绞线绞合结构能抑制共模干扰。我还在总线入口加了TVS管做浪涌保护HVAC现场经常有接触器、电磁阀动作浪涌和群脉冲很常见不加保护真的会烧芯片。2.4 PCB布局和现场布线的几点经验PCB布局上温度传感器这类模拟前端要特别注意远离干扰源。我踩过的坑是把本地传感器放在了一个继电器驱动电路旁边结果温度读值总是周期性跳变排查了很久才发现是继电器线圈动作时产生的电磁干扰耦合到了传感器的I2C线上。经验是传感器走线尽量短避开继电器、变压器、开关电源的磁场区域I2C和RS485的信号线不要和强电走线做平行长距离布线如果必须交叉尽量垂直交叉模拟地与数字地在PCB上做单点连接避免地环路。现场布线也有一堆讲究。RS485的双绞屏蔽线屏蔽层我选择在现场设备端单点接地而不是两端都接。两端都接地容易形成地环路在电位差大的场合反而会把干扰导入总线。3. 固件实现把温度读稳、传准3.1 初始化外设和读取PJ85718DM固件开发我用了原厂提供的配置工具来生成初始化代码但核心数据处理部分还是自己写更放心。下面这段代码是I2C初始化的一个简化版本我用寄存器操作的方式说明原理。// I2C1初始化目标速率100kHz // 假设外设总线时钟PBCLK 10MHz #define I2C1_BRG 233 // 10MHz / (2*(2331)) ≈ 100kHz void i2c1_init(void) { I2C1CON 0; // 先关闭I2C1模块 I2C1BRG I2C1_BRG; // 设置波特率 I2C1CON 0x8000; // 打开I2C1主模式 }读取PJ85718DM温度寄存器的基本时序是发送起始条件发送器件地址加写位发送温度寄存器地址然后发送重复起始条件发送器件地址加读位读取两个字节的温度数据最后发送停止条件。代码可以抽象成这样uint16_t read_temp_register(uint8_t reg_addr) { uint16_t data 0; i2c1_start(); i2c1_write(PJ85718_ADDR 1); // 地址 写 i2c1_write(reg_addr); // 寄存器地址 i2c1_restart(); i2c1_write((PJ85718_ADDR 1) | 0x01); // 地址 读 data (uint16_t)i2c1_read(1) 8; // 读高字节 data | i2c1_read(0); // 读低字节最后返回NACK i2c1_stop(); return data; }实际工程中建议把I2C读写加上超时处理。我见过很多设备死机就是因为I2C总线卡死读操作一直等不到从机响应整个程序卡在while循环里。给每次I2C操作加一个超时计数超时后强制释放总线并复位I2C外设这是稳定性的底线。3.2 温度数据解析与滤波PJ85718DM输出的原始温度寄存器的格式以常见型号的惯例来看一般是16位有符号数转换系数可能是0.0078125或者0.0625具体要看寄存器是左对齐还是右对齐。我在代码里统一做了一个抽象层屏蔽掉器件差异float temp_raw_to_celsius(uint16_t raw, uint8_t right_aligned) { int16_t signed_raw (int16_t)raw; if (right_aligned) { return (float)signed_raw * 0.0625f; } else { return (float)signed_raw * 0.0078125f; } }温度值是读回来了但直接用原始读数往往不够稳定。HVAC环境温度变化本身很慢但传感器在强干扰环境下偶尔会读出跳变的坏值。我采用了两级滤波先做一次中值滤波去掉突发干扰再做滑动平均平滑曲线。中值滤波我取了最近5个采样值排序取中间值这样做能有效剔除偶尔出现的异常点。滑动平均窗口取8个点窗口太大响应变慢窗口太小滤波效果不好8点是我实测下来响应和稳定性的平衡点。采样周期设在500ms到1s之间HVAC的温度控制对这个刷新率完全够。3.3 用状态机管理远程温度节点远程温度通道和本地通道不一样本地是直接读远程是轮询多个节点而且每个节点都可能掉线。如果主程序线性地一个一个节点去读某节点无响应时就会阻塞整个流程。所以远程通道我用了一个简单的状态机typedef enum { NODE_IDLE, NODE_SEND_REQ, NODE_WAIT_RESP, NODE_PARSE, NODE_ERROR } node_state_t;主循环里定时器每500ms触发一次调度取出当前节点号状态机进入NODE_SEND_REQ通过UART发送Modbus RTU读寄存器的请求帧。然后状态进入NODE_WAIT_RESP等待接收中断填满缓冲区同时启动一个超时定时器。如果超时还没收到应答就进入NODE_ERROR记录该节点的通信错误计数然后跳到下一个节点继续轮询。这样设计的核心思想就是不能因为没有收到某个节点的回复就让整台控制器停在那里。掉线节点通过错误计数和状态位汇报给上层现场维护人员能知道是哪一个探头出了问题。3.4 报警、看门狗与异常恢复温度监测的最终目的是报警和保护。我设置了两个报警层级软件阈值报警和硬件中断报警。软件阈值报警是在主循环里比较滤波后的温度值超过设定值就把报警位置位并通过UART上报给上位机或者触摸屏。硬件中断报警是用PJ85718DM的ALERT引脚它在内部检测到温度超过寄存器配置的上限时会主动拉低ALERT引脚。MCU收到外部中断后进入报警处理这样即使主循环正好被其他任务占着也不会漏掉温度越限。看门狗这块我有一点体会喂狗要放在主循环的一个固定位置绝对不要在中断服务函数里喂。否则一旦主循环卡死在某个死等操作里中断仍然会持续喂狗系统永远不会复位问题反而被掩盖了。正确的做法是主循环完成一个完整调度周期后喂一次保证如果流程卡住看门狗会自动把MCU复位。4. 温度校准与误差问题4.1 数字传感器也要做系统校准有人会觉得PJ85718DM出厂精度都有±0.5°C了还需要校准吗单看传感器确实够用但装上系统之后误差来源就变了。首先是传感器的自热误差。传感器工作时本身会消耗电流、产生热量如果周围散热条件差测出来的温度会比环境温度高一点点。其次是PCB热传导传感器贴着电路板而电路板上可能有电源芯片、驱动芯片这些热源它们的热量会通过铜箔和焊盘传导到传感器上。所以我做了系统级的两点校准。做法是准备两个恒温点一个低温一个高温把装了传感器的PCB放进恒温槽中等温度稳定后用参考温度计读取实际温度记录传感器读数和参考读数的偏差然后计算出线性补偿系数写进固件的配置参数里。这套校准不能在普通环境下用体温计凑合必须让传感器和电路板整体达到热平衡读值稳定至少几分钟后才记录数据。恒温槽如果没有用冰水混合物做0°C点和用恒温箱做高温点也是可行的关键是稳定和准确。4.2 自热、散热和探头安装的坑探头安装对测温结果的影响经常被新手忽略。HVAC现场测温探头如果不和被测介质充分接触中间隔着空气层温度响应就会很慢读数也会偏低。风管测温时探头插进风管后要在外面用保温材料封堵防止风管内外空气对流影响测量。传感器自热的问题除了靠校准修正还可以从功耗上控制。PJ85718DM支持关断模式我让它在两次转换之间进入低功耗状态只有需要读取时才对传感器唤醒并触发一次温度转换。这样的话传感器的平均工作电流大大降低自热效应也小了很多。另外传感器不要放在紧贴大功率器件或者阳光直射的位置。我之前有一个室外温度测点读数白天总是偏高后来发现是探头装在了金属防护罩上太阳把防护罩晒热了热量直接传给了传感器。后来加了隔热支架读数立刻正常了。5. 实测问题排查与经验速查5.1 读数跳动的排查思路温度读数跳动的现象我遇到过几回。第一次排查方向错了以为是传感器坏了后来用示波器看I2C波形才发现是走线离继电器太近继电器动作瞬间总线上出现了一长串毛刺数据位被干扰跳变。处理办法分几层先从硬件上缩短传感器走线、远离干扰源、增加去耦电容再从通讯上降低I2C速率有时候100kHz降到50kHz信号质量立刻好转最后从软件上加强滤波剔除异常跳变。这三板斧下来大部分跳动问题都能解决。5.2 I2C总线卡死与恢复I2C卡死是嵌入式项目里的经典问题表现是SDA一直被拉低SCL还能正常翻转后续所有I2C操作全部失败。原因通常是从机异常、时序错误、或者总线竞争导致从机状态机进入了错误状态。我现在的处理方式是在每次I2C操作前检查总线忙状态操作中增加超时超时后执行总线恢复序列把SCL翻转9次让可能处于错误状态的从机复位然后发送停止条件释放总线。如果恢复失败再复位I2C外设。这个操作看起来简单但在现场维护中救过我好几次。要知道HVAC设备一旦跑起来可能要连续运行好几个月中间不能有人天天守着去断电重启。5.3 远程通讯不稳定怎么查远程RS485读数时好时坏排查顺序很重要。第一是看波形用示波器或者差分探头看A-B之间的波形正常情况下应该是干净的两个电平状态如果波形边缘振铃严重大概率是终端电阻没接或者接得太多。第二是看接地RS485总线两端设备如果地电位差太大共模电压会超过收发器的承受范围。这种情况光靠A/B两根线是救不回来的需要把各个节点的参考地连接起来或者使用隔离型RS485收发器。第三是检查软件里的帧间隔和超时设定。Modbus RTU规定一帧数据内部字符间隔不能超过1.5个字符时间发送完成后要等足够时间再切换收发器方向否则刚发完就切到接收会把自己发送的最后一个字节也收回来导致帧解析混乱。5.4 一张表总结症状、原因与处理办法症状常见原因处理办法温度读数周期性跳变传感器走线靠近继电器、开关电源等干扰源重新布线、远离干扰源、增加去耦电容读值偏高且长时间不变传感器自热太大或探头隔热不良降低转换频率、使用关断模式、改善探头接触I2C总线卡死SDA一直低从机时序错误、总线竞争增加操作超时、执行9脉冲总线恢复、复位I2C远程读数时好时坏RS485终端电阻、接地、共模电压问题检查波形、单端接地、使用隔离收发器远程节点掉线通讯超时太短、节点供电不足拉长超时、检查节点电源、增加错误重试次数低温端误差大两点校准没覆盖到低温区增加低温校准点、检查恒温槽稳定性5.5 现场维护的小技巧最后分享一个现场维护的小技巧在上电自检阶段让主控读一遍所有温度节点的设备型号寄存器并和配置表比对。如果有节点型号不匹配或者读不到就点亮对应的故障指示灯。这样设备装到现场后即使接线接错了也能在几分钟内定位不用拿着万用表一个个量线头。这个项目做完之后我个人最大的体会是测温这件事核心不是传感器有多高级而是从硬件布线、通讯协议、软件状态机到校准修正每一个环节都要踏踏实实处理。本地温度和远程温度分开管理主控压力分配清晰出问题时也容易隔离。如果你接下来也要做类似的温度监测系统我建议先别急着上复杂功能把一路本地温度从头到尾读准、读稳再复制到远程节点上。架构不变扩展个十几路测点并不是什么难事。
阅读完成 · 觉得有帮助?