多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

基于PJ85718DM与PIC32MZ的嵌入式HVAC温度监测系统设计与实现

基于PJ85718DM与PIC32MZ的嵌入式HVAC温度监测系统设计与实现 1. 项目缘起与整体设计思路嵌入式温度监测这个方向看起来简单真做起来坑不少。我接手过好几个涉及本地温度采集加远程温度上报的项目从工业控制柜到商用空调控制器都有最头疼的从来不是传感器本身而是怎么把本地采集和远程传输这两件事在同一个系统里做稳。这次要聊的方案核心是用 PJ85718DM 做本地温度采集用 PIC32MZ1024EFK144 做数据处理和远程通信调度面向嵌入式和 HVAC 场景。先说清楚这个组合解决什么问题。HVAC 系统里温度监测通常分两层一层是设备本体的本地温度比如压缩机排气温度、换热器表面温度、风道温度另一层是远程温度可能是远端房间的温感探头也可能是通过通信总线从其他节点获取的温度数据。本地采集要求响应快、精度稳远程传输要求协议可靠、抗干扰强。PJ85718DM 是一颗红外温度传感器信号调理芯片配合热电堆传感器使用输出数字信号适合做非接触式本地温度采集。PIC32MZ1024EFK144 是 Microchip 的 32 位 MCU200MHz 主频1MB Flash512KB RAM带以太网、CAN、UART、SPI、I2C 等丰富外设拿来做 HVAC 控制器的主控非常合适。为什么选这个组合而不是其他方案我对比过几种常见做法。第一种是用 NTC 热敏电阻加运放加 ADC成本低但精度和线性度差尤其在高低温两端误差大而且需要校准。第二种是用数字温度传感器比如 DS18B20 这类单总线接口简单但测温范围有限响应速度也一般做非接触测量更是不可能。第三种就是 PJ85718DM 加热电堆的方案非接触、响应快、量程宽配合 PIC32MZ 的浮点运算能力做温度补偿和线性化处理整体精度可以做到正负 0.5 度以内。HVAC 场景里风道温度、换热器表面温度这些位置接触式传感器安装困难或者容易受污染非接触方案优势明显。整体设计思路是这样的PJ85718DM 负责把热电堆传感器的微弱模拟信号转换成数字温度值通过 I2C 或 SPI 接口传给 PIC32MZ1024EFK144。PIC32MZ 做三件事第一对本地温度数据做滤波、补偿、校准第二通过 RS485 或 CAN 总线采集远程温度节点的数据第三把本地和远程温度汇总后通过以太网或无线模块上报给上位机或云平台。整个系统的时间基准用 MCU 的内部定时器加外部晶振保证采样周期可以根据应用需求在 100ms 到 1s 之间调整。这里有个关键设计决策需要解释为什么不让 PJ85718DM 直接驱动通信而是必须经过 MCU原因是 PJ85718DM 本质上是传感器信号调理芯片它的输出是温度数据不具备协议栈处理能力。HVAC 系统里远程通信往往需要 Modbus、BACnet 或者自定义协议这些必须由 MCU 来完成。另外多路温度采集时MCU 可以做轮询调度和数据融合单靠传感器芯片做不到。所以这个分工是合理的也是行业里比较成熟的架构。2. 核心器件解析与选型考量2.1 PJ85718DM 的工作机制与关键参数PJ85718DM 这颗芯片资料不算特别多但用熟了会发现它在非接触测温领域很实用。它的核心功能是配合热电堆传感器工作热电堆输出的是微伏级别的电压信号跟目标温度和环境温度之间的差值成比例。PJ85718DM 内部集成了低噪声放大器、高精度 ADC、环境温度传感器和数字信号处理单元直接输出校准后的温度值。关键参数我列一下这些在实际选型和调试时都要关注参数项典型值说明测温范围-20 到 300 摄氏度取决于外接热电堆型号分辨率0.02 摄氏度内部 ADC 位数决定接口I2C / SPI可配置默认 I2C供电电压3.3V典型功耗约 1.5mA刷新率最高 64Hz可配置HVAC 场景 4-10Hz 足够精度正负 0.5 摄氏度配合校准后可达这里要重点说的是刷新率和精度的取舍。HVAC 系统里温度变化本身很慢风道温度从 20 度升到 30 度可能要几分钟所以采样率不需要太高。我一般设成 4Hz 或者 8Hz这样既能保证响应速度又能降低功耗和通信负载。如果你设成 64Hz数据跳动反而更明显因为热电堆本身的噪声带宽就那么大采太快只是把噪声也采进来了。2.2 PIC32MZ1024EFK144 的资源分配PIC32MZ1024EFK144 这颗 MCU 在 HVAC 控制器里算是高配了。200MHz 主频带浮点运算单元做温度补偿算法绰绰有余。1MB Flash 和 512KB RAM 意味着你可以跑 RTOS也可以把协议栈、数据缓存、日志存储都塞进去。我在这个项目里的资源分配是这样的I2C 外设接 PJ85718DM速率设 400kHz用 DMA 传输减少 CPU 占用UART 或 CAN接远程温度节点RS485 用 UART 加外部收发器CAN 直接用内置 CAN 控制器以太网接上位机或路由器跑 Modbus TCP 或自定义 TCP 协议定时器系统滴答用 Timer1采样触发用 Timer2通信超时检测用 Timer3GPIO状态指示灯、继电器控制、报警输出ADC备用可以接 NTC 做冗余本地温度监测为什么用 DMA 传 I2C因为温度采集是周期性的如果每次都用中断或者轮询CPU 会被频繁打断。用 DMA 之后MCU 可以在这段时间处理通信协议或者控制逻辑整体效率高很多。实测下来用 DMA 比不用 DMACPU 占用率从 15% 降到 5% 左右。2.3 本地与远程温度的协同逻辑本地温度和远程温度在系统里的角色不一样。本地温度是设备自身的状态比如压缩机壳温、电控箱内温、出风口温度这些数据用来做设备保护和控制决策。远程温度是环境或者远端节点的数据用来做区域调节或者系统级联动。协同逻辑我一般这样设计本地温度优先级高采样周期短比如 250ms 一次远程温度优先级低采样周期长比如 2s 一次。MCU 内部维护两个数据队列本地队列深度 16远程队列深度 8。当本地温度超过阈值时立即触发保护动作不等远程数据。当远程温度异常时先做数据有效性检查确认不是通信误码后再做处理。这里有个细节远程温度数据必须带时间戳和校验。我遇到过 RS485 总线上某个节点故障发出来的温度值是 0xFFFF如果不做校验直接当 -1 度处理系统就会误判。所以协议里必须加 CRC 校验和范围检查超出合理范围的直接丢弃。3. 硬件连接与实操要点3.1 最小系统搭建先说一下最小系统的搭建。PIC32MZ1024EFK144 是 144 引脚封装手工焊接难度不小建议直接用官方评估板或者自己画四层板。核心电路包括3.3V 电源、外部 24MHz 晶振、复位电路、调试接口ICSP 或者 JTAG、去耦电容。电源部分要特别注意。PIC32MZ 的内核电压是 1.8V 左右需要内部 LDO 或者外部供电具体看型号后缀。我一般用 3.3V 单电源MCU 内部有稳压器。去耦电容每对电源引脚配一个 100nF另外在电源入口放一个 10uF 钽电容。HVAC 环境里电源纹波可能比较大建议再加一个 LC 滤波。PJ85718DM 的连接相对简单VCC 接 3.3VGND 接地SCL 和 SDA 接 MCU 的 I2C 引脚另外热电堆传感器的正负输出接到 PJ85718DM 的差分输入端。热电堆的安装位置很关键必须正对被测目标中间不能有遮挡镜头或者窗口要定期清洁。3.2 I2C 总线的上拉电阻选择I2C 总线的上拉电阻是个老生常谈的问题但实际调试时经常出问题。PJ85718DM 支持标准模式和快速模式400kHz 时上拉电阻一般选 2.2k 到 4.7k。电阻太小功耗大电阻太大上升沿变缓通信误码率上升。我的经验是总线长度小于 10cm 时用 4.7k10cm 到 30cm 用 2.2k超过 30cm 建议用 I2C 缓冲器或者降低速率到 100kHz。HVAC 控制器内部走线一般不长4.7k 够用。但如果你的板子上 I2C 挂了多个器件要算一下总电容超过 400pF 就要调整。注意PJ85718DM 的 I2C 地址可以通过引脚配置默认地址是 0x48 左右具体看数据手册。如果总线上有多个同型号芯片必须改地址否则会冲突。3.3 远程通信接口的硬件设计远程温度节点我一般用 RS485因为抗干扰能力强传输距离远HVAC 现场电磁环境复杂RS485 比 I2C 或者 SPI 靠谱得多。PIC32MZ 的 UART 接一个 RS485 收发器比如常见的半双工收发器DE 和 RE 引脚用 GPIO 控制方向。RS485 总线的终端电阻不能忘。总线两端各接一个 120 欧姆电阻中间节点不接。如果总线长度超过 100 米建议加隔离用光耦或者磁隔离器把 MCU 侧和总线侧隔开。我踩过一次坑没加隔离雷雨天气感应雷把收发器打坏了连 MCU 都换了。后来加了隔离模块再没出过问题。CAN 总线在 HVAC 里也常用尤其是汽车空调或者大型楼宇系统。PIC32MZ 内置 CAN 控制器外面接一个 CAN 收发器就行。CAN 的终端电阻也是 120 欧姆总线上所有节点速率必须一致我一般用 125kbps 或者 250kbps兼顾距离和速率。4. 软件架构与核心代码实现4.1 温度采集任务的设计软件架构我采用前后台加定时器调度的方式没有上 RTOS因为任务不算多前后台够用。如果你要跑 Modbus TCP 加多个远程节点轮询建议上 FreeRTOS任务划分更清晰。温度采集任务的核心流程是这样的// 伪代码示意基于常见实践 void TemperatureTask(void) { static uint32_t lastLocalTick 0; static uint32_t lastRemoteTick 0; uint32_t now GetSysTick(); // 本地温度采集250ms 一次 if (now - lastLocalTick 250) { lastLocalTick now; float localTemp PJ85718DM_ReadTemperature(); if (IsValidTemperature(localTemp)) { LocalTempQueue_Push(localTemp); LocalTempFilter_Update(localTemp); } } // 远程温度采集2s 一次 if (now - lastRemoteTick 2000) { lastRemoteTick now; RemoteNode_PollAll(); } }这里的关键是数据有效性检查。PJ85718DM 读出来的原始值可能是 0xFFFF 或者超出量程的值必须过滤。我一般设一个合理范围比如 -40 到 150 度超出范围的直接丢弃用上一次的有效值代替。4.2 温度滤波与补偿算法热电堆传感器的原始数据噪声比较大必须滤波。我用的是滑动平均加中值滤波的组合。滑动平均窗口取 8 个点中值滤波取 5 个点。先做中值滤波去掉突发噪声再做滑动平均平滑数据。补偿算法主要是环境温度补偿。热电堆输出的是目标温度和环境温度的差值所以必须知道环境温度才能算出目标温度。PJ85718DM 内部有环境温度传感器读出来之后代入公式目标温度 环境温度 差值电压 / 灵敏度系数灵敏度系数跟热电堆型号有关一般在数据手册里给出典型值是 50uV/K 左右。实际使用时要校准我一般用黑体炉或者冰水混合物做两点校准算出实际的灵敏度系数和偏移量。float CompensateTemperature(float rawTemp, float ambientTemp) { // rawTemp 是 PJ85718DM 输出的未补偿温度 // ambientTemp 是环境温度 // 基于常见实践的补偿公式 float sensitivity 50.0f; // uV/K需根据实际校准 float offset 0.0f; // 校准偏移 float compensated rawTemp (ambientTemp - 25.0f) * 0.02f offset; return compensated; }这个补偿系数 0.02 是经验值不同热电堆不一样必须实测。我一般会在恒温箱里做三个温度点10 度、25 度、40 度记录原始值和标准值然后拟合出补偿曲线。4.3 远程通信协议的设计远程温度节点我用的自定义协议基于 RS485 半双工。协议格式很简单帧头 2 字节地址 1 字节命令 1 字节数据长度 1 字节数据 N 字节CRC16 校验 2 字节。帧头用 0xAA 0x55地址范围 1 到 247命令 0x01 读温度0x02 读状态。为什么不用 ModbusModbus 当然可以但自定义协议更轻量解析速度快而且我可以针对温度数据做优化。比如温度值用 2 字节表示高字节整数部分低字节小数部分精度 0.1 度够用了。轮询策略是这样的MCU 依次向每个远程节点发读温度命令等待响应超时时间设 100ms。如果某个节点连续 3 次超时标记为故障跳过它继续轮询其他节点。故障节点每隔 30 秒重试一次恢复正常后重新加入轮询队列。void RemoteNode_PollAll(void) { for (int i 0; i nodeCount; i) { if (nodes[i].status NODE_FAULT) { if (GetSysTick() - nodes[i].lastRetry 30000) { continue; } nodes[i].lastRetry GetSysTick(); } SendReadCommand(nodes[i].address); if (WaitResponse(nodes[i].address, 100) RESP_OK) { nodes[i].status NODE_OK; nodes[i].failCount 0; RemoteTempQueue_Push(nodes[i].temperature); } else { nodes[i].failCount; if (nodes[i].failCount 3) { nodes[i].status NODE_FAULT; } } } }4.4 数据上报与上位机对接数据上报我一般用以太网跑 TCP 或者 UDP。TCP 可靠但开销大UDP 快但可能丢包。HVAC 系统里温度数据不是特别关键丢一两个包没关系所以我倾向用 UDP周期上报每秒一次。上报的数据格式用 JSON 或者二进制都行。JSON 可读性好调试方便但解析慢。二进制紧凑解析快但调试麻烦。我一般调试阶段用 JSON量产用二进制。下面是一个 JSON 示例{ device_id: HVAC_001, timestamp: 1234567890, local_temps: [ {channel: 0, value: 25.3}, {channel: 1, value: 26.1} ], remote_temps: [ {node: 1, value: 24.8}, {node: 2, value: 25.5} ] }上位机那边用 Python 或者 Node.js 写个接收服务存数据库或者直接展示。如果要做云平台对接再加一个 MQTT 客户端转发就行。5. 常见问题与排查技巧实录5.1 温度读数跳动大怎么办这是最常见的问题。原因通常有三个电源噪声、热电堆安装不当、滤波参数不合理。先查电源。用示波器看 PJ85718DM 的 VCC 引脚纹波应该小于 10mV。如果纹波大加 LC 滤波或者换 LDO。我遇到过开关电源给 MCU 供电纹波 50mV温度读数跳动正负 2 度换了 LDO 之后降到正负 0.3 度。再查热电堆安装。热电堆的视场角要覆盖目标不能有遮挡。如果目标表面反射率高比如金属表面读数会偏低因为反射了环境辐射。解决办法是在目标表面贴一块黑色胶带或者涂黑漆提高发射率。最后调滤波参数。滑动平均窗口从 8 加到 16中值滤波从 5 加到 9跳动会明显减小但响应速度会变慢。HVAC 场景对响应速度要求不高可以接受。5.2 I2C 通信失败怎么排查I2C 通信失败先看硬件上拉电阻有没有阻值对不对SCL 和 SDA 有没有接反。然后用示波器看波形时钟频率是不是 400kHz上升沿是不是太缓。如果硬件没问题查软件I2C 初始化对不对地址对不对时序对不对。PIC32MZ 的 I2C 外设配置有点复杂时钟分频系数要算对。我一般用官方库函数少踩坑。还有一个隐蔽问题I2C 总线死锁。如果从机在传输过程中复位可能会把 SDA 拉低导致总线死锁。解决办法是在初始化时发 9 个时钟脉冲让从机释放总线。5.3 远程节点通信不稳定RS485 通信不稳定先查终端电阻。总线两端各 120 欧姆中间节点不能接。如果终端电阻不对信号反射会导致误码。再查共地。RS485 是差分信号但共地还是要的。如果节点之间地电位差太大收发器可能损坏。解决办法是用隔离收发器或者加共模电感。最后查轮询策略。如果轮询太快节点来不及响应就会超时。我一般设 100ms 超时轮询间隔 200ms给节点足够的处理时间。5.4 常见问题速查表问题现象可能原因排查方法解决方案温度读数跳动大电源纹波大示波器看 VCC加 LC 滤波或换 LDO温度读数偏低目标发射率低检查目标表面贴黑色胶带或涂黑漆I2C 通信失败上拉电阻缺失万用表测阻值加 4.7k 上拉电阻I2C 总线死锁从机复位拉低 SDA示波器看波形初始化发 9 个时钟脉冲RS485 误码率高终端电阻不对万用表测阻值两端各接 120 欧姆远程节点超时轮询太快逻辑分析仪看时序增加超时和轮询间隔温度补偿不准灵敏度系数错误恒温箱校准重新拟合补偿曲线6. 实操心得与经验分享6.1 校准是精度保证的关键PJ85718DM 加热电堆的方案不校准的话精度可能只有正负 2 到 3 度校准后能做到正负 0.5 度。校准方法我推荐两点校准用一个已知温度的黑体源比如 30 度和 60 度记录原始读数算出斜率和截距写入 MCU 的 Flash。校准的时候要注意环境温度稳定。如果环境温度变化大补偿系数会漂移。我一般在校准前让设备在恒温环境里放 30 分钟等热平衡后再开始。6.2 采样周期不是越短越好前面提过HVAC 场景温度变化慢采样周期 250ms 到 1s 足够。我试过 50ms 采样数据跳动反而更大因为热电堆的噪声带宽有限采太快只是把噪声也采进来了。而且采样快意味着通信负载大远程节点轮询不过来。我的建议是本地温度 250ms 到 500ms远程温度 1s 到 2s。如果要做快速保护比如压缩机排气温度保护可以单独设一个快速通道100ms 采样但只做阈值判断不做数据上报。6.3 数据有效性检查不能省远程温度数据必须做有效性检查。我遇到过 RS485 总线受干扰某个节点发出来的温度值是 0x7FFF如果不检查直接当 3276.7 度处理系统就疯了。检查方法很简单温度值必须在合理范围内比如 -40 到 150 度超出范围的直接丢弃用上一次的有效值代替。另外CRC 校验必须做。自定义协议里加 CRC16Modbus 里自带 CRC不管哪种校验不过的数据一律丢弃。我一般还会加一个变化率检查如果温度值在 1 秒内变化超过 10 度大概率是误码丢弃。6.4 电磁兼容性设计要提前考虑HVAC 现场电磁环境复杂变频器、接触器、电机都在旁边电磁兼容性设计不能省。我一般做这几件事电源入口加共模电感加 TVS 管通信接口加隔离PCB 布局时模拟部分和数字部分分开地平面完整。有一次偷懒没加隔离RS485 收发器在客户现场连续烧了三个后来加了隔离模块再没出过问题。隔离模块成本不高但能省很多售后麻烦。6.5 固件升级功能要预留产品出货后难免要改bug或者加功能固件升级功能一定要预留。我一般用 UART 或者以太网做升级接口MCU 的 Flash 分两个区一个跑应用程序一个跑 Bootloader。升级时先擦除应用程序区写入新固件校验通过后跳转。升级过程中要防止断电导致变砖。我的做法是 Bootloader 区永不擦除升级失败后自动回滚到旧固件。另外升级前要备份当前固件万一新固件有问题可以回退。7. 方案扩展与场景延伸7.1 多路温度采集的扩展PIC32MZ1024EFK144 的 I2C 总线可以挂多个 PJ85718DM只要地址不冲突。我做过 4 路本地温度采集用 4 颗 PJ85718DM分别监测压缩机、换热器、出风口、电控箱。MCU 轮询读取每路 250ms 一次4 路总共 1s 一轮完全来得及。如果路数更多比如 8 路或者 16 路I2C 总线负载会变大建议用 I2C 多路复用器或者改用 SPI 接口。PJ85718DM 支持 SPI速率比 I2C 快适合多路高速采集。7.2 无线远程温度节点的实现有些场景布线困难远程温度节点可以用无线。我一般用 LoRa 或者 ZigbeeLoRa 距离远穿透力强适合楼宇 HVACZigbee 组网方便适合家庭或者小型商用。无线节点用低功耗 MCU 加无线模块加温度传感器电池供电休眠唤醒周期 10s 一次。数据通过无线网关汇聚到主控 PIC32MZ再统一上报。无线方案要注意抗干扰WiFi 和蓝牙在 HVAC 现场干扰大LoRa 和 Zigbee 相对好一些。7.3 与楼宇自控系统的对接HVAC 系统最终要接入楼宇自控系统常见协议是 BACnet 或者 Modbus。PIC32MZ 跑 BACnet 协议栈有点吃力建议用 Modbus TCP 转 BACnet 网关。或者直接用支持 BACnet 的通信模块通过 UART 跟 MCU 对接。对接的时候要注意数据点映射。楼宇自控系统里每个温度点都有对应的对象标识符MCU 上报的数据要跟这些标识符对应上。我一般做一个配置表存在 Flash 里升级的时候可以改。7.4 数据记录与故障追溯HVAC 系统出故障时温度数据是重要的排查依据。我一般会在 MCU 的 Flash 或者外挂 SPI Flash 里做数据记录每分钟存一次本地和远程温度循环覆盖。Flash 容量 1MB 的话可以存好几天的数据。数据记录格式用二进制紧凑省空间。每条记录包含时间戳、本地温度、远程温度、状态标志。读取的时候通过通信接口导出用上位机软件解析成曲线故障排查很方便。这个方案我从最早的单点采集做到现在的多路加远程加无线踩过的坑不少但整体架构是稳的。PJ85718DM 加 PIC32MZ1024EFK144 这个组合在嵌入式和 HVAC 温度监测场景里性价比和可靠性都经得起考验。如果你正在做类似的项目建议先从单路本地采集做起跑通了再加远程和无线一步步来别一上来就搞大而全。
返回列表