资讯详情

资讯详情

STM32F415RG双路温度采集:本地PJ85718DM与远程Modbus RTU实战

用一颗 STM32F415RG 把本地和远程温度同时管起来做嵌入式或者暖通空调HVAC控制的朋友应该都有过这种经历现场节点既要采集控制板附近的温度又要实时掌握分布在几个楼层的远端传感器数据两路温度如果不同步要么控制逻辑打架要么系统误报。我之前在做一个楼宇环境监测节点时选型阶段把主控定在 STM32F415RG本地温度交给 PJ85718DM 这颗数字传感器远程温度通过 Modbus RTU 走 RS-485 总线从远端节点拉数据。整套方案跑下来比较顺也踩了不少坑。这篇文章就围绕这个组合把从硬件设计到软件实现的完整思路捋一遍重点讲清楚本地温度传感器怎么调、远程温度帧怎么解析、温度数据怎么做滤波和标定以及那些手册里不会写的问题。这套内容适合正在选型嵌入式温度采集方案、做 HVAC 控制器、或者刚接触 Modbus 温度采集的开发者。无论你用的是不是同型号的单片机和传感器里面涉及的接口匹配、抗干扰处理、协议解析和数据处理思路都是可以直接迁移的。1. 先界定清楚本地温度和远程温度到底是啥不少人对本地温度和远程温度的理解比较模糊搞混了会导致整个方案架构都出问题。这里先把这个基础概念掰开揉碎。我们说的本地温度是指传感器在主控板附近、通过板上走线直接连接到 MCU 接口采集的温度也就是 MCU 最容易够到的那一路。远程温度则是指传感器挂在外部总线上、物理距离可能几十米甚至上百米、通过通信协议比如 Modbus、CAN、以太网把温度数据传给主控的那一路。两者在实现上的差别非常大。1.1 本地远程的本质差异在数据链路本地温度采集的数据链路很短一般就是从传感器到 MCU 的 I2C/SPI/单总线几个厘米最多几十厘米信号完整性压力很小驱动代码几条命令就能读完。远程温度就完全不一样数据要经过收发器、长线缆、连接端子中间还可能并行动力线噪声和压降都很现实。所以在方案设计时本地温度要把重心放在采样精度和滤波上远程温度则要把重心放在通信协议的可靠性和帧校验上。我见过有人把远程温度直接用 GPIO 拉一根长线去读单总线传感器结果线稍微走长一点就读不出来最后还要花力气去做总线时序补偿。正确思路是远程一律走标准通信协议把物理层和链路层交给成熟的收发器和协议栈去处理MCU 只管应用层数据。1.2 STM32F415RG 在这个场景里的匹配度STM32F415RG 是 Cortex-M4 内核、主频 168MHz、带硬件浮点和 DSP 指令的单片机1MB Flash、192KB RAM板上还有多个 I2C、USART以及一整套硬件加密单元。在温度监测这个负载下主频和存储其实是绰绰有余的选它更大的价值在于外设丰富和可靠性定位。具体到方案上本地温度用 I2C 接口接 PJ85718DM远程温度用 USART 外接 RS-485 收发器跑 Modbus RTU这两个外设 STM32F415RG 都有现成的硬件支持。而且对于 HVAC 这种需要长时间运行的场景MCU 的温度范围、ESD 性能、时钟稳定性都要重点考虑F4 系列在这些项目上普遍经得起用。2. PJ85718DM 这颗传感器先摸透再动手PJ85718DM 这个型号可能很多人不熟悉它是一款数字温度传感器支持 I2C 接口测量精度在 -10°C 到 85°C 范围内典型值可以做到 ±0.5°C分辨率通过配置寄存器可调最高能到 0.0625°C。在 HVAC 这种对绝对精度要求不算极高但要求长期稳定性的场合这个参数是够用的。我这里说的参数是我手头手册里的数据你用的批次如果有差异一定以你手里的数据手册为准。2.1 接口与寄存器搞明白才能读对数据PJ85718DM 的 I2C 地址由芯片的 ADDR 引脚电平决定一般可以设置成 0x48 到 0x4F 区间这也是常见温度传感器的惯例。一个总线上如果挂了多个同型号传感器靠硬件地址区分是非常方便的。寄存器方面核心就是温度寄存器16 位和配置寄存器8 位或者 16 位视版本而定。温度寄存器高字节是整数部分低字节是小数部分配合分辨率设置读取后左移或者处理后转换成浮点数。读温度的关键步骤如下先写一个字节的寄存器指针指向温度寄存器然后发起重复起始信号连续读两个字节。如果一次性想把配置也读出来就连续读三个字节。我刚开始调试的时候把寄存器指针写成了读操作结果芯片一直返回 0xFF白白浪费了半天时间。这个坑后面在常见问题里再展开讲。2.2 分辨率与转换时间的取舍PJ85718DM 支持通过配置寄存器选择 9 到 14 位分辨率也就是 0.5°C 到 0.0625°C 的步进。分辨率越高内部 ADC 转换时间越长。HVAC 场景一般对实时性要求不高一秒读一次已经很快所以直接用最高的 14 位分辨率没有压力。但如果是做电机保护这类需要快速响应的场景就要在分辨率和转换时间之间找平衡。我实测下来14 位分辨率下转换时间大约在 100ms 量级读取频率不超过 5Hz 就完全没必要降分辨率。如果你的系统里 I2C 总线还挂了其他器件适当的做法是用 12 位分辨率误差完全在 HVAC 接受范围内还能减少总线占用。2.3 上电时序和地址冲突数字传感器上电后需要一小段时间稳定然后才能正常响应 I2C 命令。STM32F415RG 上电后如果立刻去读传感器可能会收到 NACK 或者错误数据。我通常在 MCU 初始化阶段加一个 50ms 到 100ms 的延时再开始第一次读操作。这个细节在很多项目里被忽略结果就是偶发性上电失败。多个 PJ85718DM 挂在同一条 I2C 总线上时地址冲突的问题就会冒出来。解决办法要么是给每颗芯片设置不同的 ADDR 引脚电平要么就用一个 I2C 交换机TCA9548A 之类分通道接。在 HVAC 项目中我建议优先用分通道方式因为现场维护时不用关心传感器到底接在哪根线上单独通道还可以快速定位断线。3. 硬件设计这些细节直接影响测量结果硬件设计这块很多开发者习惯直接按开发板布局画板子温度采集项目里这样容易翻车。温度传感器的测量结果对电源噪声、接地处理和走线寄生热阻都非常敏感这几个点如果不处理好软件层面做多少滤波都补不回来。3.1 电源去耦与参考地处理PJ85718DM 对电源噪声的敏感度比很多人想象中要高。I2C 数字接口虽然本身是电平信号但内部 ADC 的参考电压一般就是电源电压电源上的纹波会直接耦合进转换结果。我做过对比实验同样的传感器电源脚放 100nF 陶瓷电容和 10μF 电解电容的组合比只放一个 100nF 电容的时候长时间运行的温度波动能明显低一个台阶。本地传感器的地线也要单独走不要跟 MCU 的 IO 地混在一条细线上。如果板子上有功率器件比如控制风机的继电器或者 MOS 管地线回流路径和传感器地线离得太近温度数据会周期性地出现尖峰。最稳的做法是传感器地线在 MCU 的模拟地基准点单点接地。3.2 走线布局与热隔离温度传感器如果贴着发热元件放测出来的就不是环境温度了而是局部热点的温度。在 HVAC 控制器里电源芯片、主控 MCU、通信收发器都是热源传感器 PCB 布局要跟这些保持距离。有一个常用技巧就是优先把传感器放在 PCB 边缘、远离功率器件的位置并且传感器下方的地层做挖空处理减少热量通过铜皮传导到传感器。如果是往外接的本地探头也就是传感器不在主板上、通过线缆连接的情况线缆屏蔽层要单端接地在传感器端的屏蔽层悬空或者串一个磁珠再接地这能有效抑制共模干扰。我之前处理过一个现场温度显示始终偏高 3°C排查到后来发现是传感器探头被固定在了设备散热风口旁边挪个位置就恢复正常了。3.3 远程温度通信总线的物理层加固远程温度走 RS-485 时物理层的匹配电阻和偏置电阻是必要的。总线两端各放一个 120Ω 终端电阻两端的意思是物理链路的两端不是 PCB 上两个接口。偏置电阻的作用是在总线空闲时把 A、B 之间的电平拉到一个确定状态否则接收端的电平不确定很容易收到乱码。偏置电阻的阻值可以按总线节点数量和收发器芯片的输入阻抗来算一般 560Ω 到 680Ω 对常见负载都是可行的。总线线缆建议使用屏蔽双绞线屏蔽层在控制端单点接地。如果现场和变频器、接触器这些设备共用电缆桥架那干扰问题基本跑不掉。真的遇到这种情况除了走线远离还要考虑在 RS-485 收发器的 A/B 线上加 TVS 管并把失效保护设计加上确保总线开路、短路时收发器输出到一个确定电平。4. 软件实现驱动与协议都按工程化思路写硬件就位后软件就是整个方案的核心。温度数据最终要稳定、可靠、可标定驱动代码、通信解析、数据处理三个层次都要认真写。下面按从底到上的顺序说。4.1 PJ85718DM 的驱动封装用 STM32 HAL 库读取 PJ85718DM核心就是一个读温度函数。这里把关键操作逐一说明。首先要做的是初始化 I2C配置好时钟和引脚后调用函数。读取流程是先读温度寄存器然后做符号扩展和分辨率换算。#define PJ_ADDR (0x48 1) // 根据硬件地址修改 #define PJ_REG_TEMP 0x00 #define PJ_RESOLUTION 14 // 使用的分辨率位数 uint8_t PJ_ReadTemp(float* temp) { uint8_t reg PJ_REG_TEMP; uint8_t buf[2]; int16_t raw; if (HAL_I2C_Master_Transmit(hi2c1, PJ_ADDR, reg, 1, 50) ! HAL_OK) return 0; if (HAL_I2C_Master_Receive(hi2c1, PJ_ADDR, buf, 2, 50) ! HAL_OK) return 0; raw ((int16_t)buf[0] 8) | buf[1]; // 符号扩展温度可能为负 if (raw 0x8000) raw | 0x8000; // 14位分辨率对应步进为 0.0625°C *temp raw * 0.0625f; return 1; }这个函数里最容易出错的有两个地方一是发送寄存器指针时一定要注意是当前任务的工作模式不是重复起始信号很多总线异常都是在这里埋下的。二是符号扩展如果环境温度低于 0°C寄存器低字节的最高位是符号位不处理的话读出来的数据会变成巨大的正数。HVAC 项目里冬天测室外机负温是必然出现的符号扩展一定要写对。配置寄存器同理先写寄存器指针再用当前操作模式完成写入然后等待一个转换时间确保新配置生效。不要写完配置立刻读温度有相当大概率读到上一轮的旧数据。4.2 远程温度 Modbus RTU 帧解析远程温度采用 Modbus RTU 协议MCU 作为主站主动查询从站。从站一般是挂载在总线上的温度采集模块或者带 RS-485 接口的传感器每个从站有独立的地址。读温度一般用功能码 0x04读输入寄存器或者 0x03读保持寄存器具体响应从站手册。我远程温度这一路用的功能码是 0x04请求帧格式如下地址 | 功能码 | 起始寄存器地址(高) | 起始寄存器地址(低) | 寄存器数量(高) | 寄存器数量(低) | 校验(高) | 校验(低)请求读地址为 1 的从站、从寄存器 0x0000 开始、读 2 个寄存器4 字节温度数据原始十六进制帧就是01 04 00 00 00 02 71 CBCRC 校验的算法这里不过多展开网上有成熟查表法用查表法算出的 CRC 填入帧尾即可。需要注意大小端问题Modbus RTU 是 Big Endian 传输高字节在前和 STM32 默认的小端存储器序不同。在组合温度数据时要手动交换字节很多开发者第一次调通信就是在这里出错。响应帧解析时重点做好三个防护第一从站地址必须等于我们发送的地址否则可能收到别的模块的帧第二帧长度和功能码必须匹配第三CRC 校验必须通过再使用数据。任何一个不满足直接丢弃这帧进入下一个轮询周期。我一般在代码里会加一个坏帧计数器方便现场定位总线质量。4.3 温度数据的滤波与标定逻辑本地温度和远程温度进入应用层之前都应该经过滤波。温度是一个大惯性物理量对实时带宽要求极低常见的滑动平均滤波就能取得很好的效果。窗口大小取 8 到 16 次采样比较合适再大响应变慢再小抑制毛刺能力不足。除了滑动平均还要加一个关键的限幅滤波。如果相邻两次采样差值超过 2°C这个阈值可以根据实际环境调基本可以认为是异常跳变。远程数据尤其需要加这个限幅因为总线上某一次误码导致的数据错误可能瞬间跳动几十度这时候单纯的平均滤波会被污染限幅滤波可以把这个野值直接剔除。标定方面几乎所有温度传感器都有个体偏差。如果现场需要绝对精度我建议做一个两点标定用冰水混合物和已知沸水或者高精度温度计做参考测出两组传感器读数和标准值的差然后线性拟合偏移量。HVAC 项目里通常只需要零点校准就够了在软件里用一个校准参数cal_offset读取温度后统一加上去。float acc_temp 0.0f; if (PJ_ReadTemp(acc_temp)) { // 限幅滤波 if (fabsf(acc_temp - last_local_temp) 2.0f) { acc_temp last_local_temp; } else { last_local_temp acc_temp; } // 均值滤波 local_buffer[local_index] acc_temp cal_offset; local_index 0x0F; // 计算滑动平均 local_temp_filtered MeanOfBuffer(local_buffer, LOCAL_BUFFER_SIZE); }标定时不要随便找一个室温参考来对齐那个参考本身误差就很大。有条件的用标准油槽或者高精度数字温度计没条件至少用冰水混合物做零点这是最便宜又稳定的参考点。5. 实测过程与关键步骤记录方案在测试阶段出现的问题非常典型这里把完整的实测流程和遇到的问题记录下来。项目是一个嵌入式和 HVAC 应用场景的验证板板上 MCU 为 STM32F415RG本地传感器为 PJ85718DM远程端是两块带 RS-485 接口的 PT100 温度变送器模拟两路远程温度。主控通过轮询方式每 500ms 读一次本地温度每 1s 轮流读两路远程温度数据同时打印到调试串口。5.1 测试环境和基础调试验证先把本地温度读取跑通。上电后延时 200ms初始化 I2C然后每秒读一次 PJ85718DM与实验室水银温度计对比。初始阶段读数基本稳定在 25.5°C水银温度计是 25.2°C偏差约 0.3°C在手册标称的精差范围内软件上把校准系数设为 0.3 之后和参考值偏差基本消失本地通道的数据较稳定。远程温度测试需要先配置两块变送器的地址。我按 1 和 2 配置接到 RS-485 总线上然后把主控的 USART2 配置成 9600 波特率、8 数据位、无校验、1 停止位。手动发送 Modbus 请求帧期望收到响应帧。这一步调试时用串口助手直接看总线数据比一个字节一个字节查寄存器直观很多。5.2 远程读取的完整轮询流程主控的轮询逻辑比较简单维护一个状态机先查地址为 1 的变送器收到合法响应后更新远程温度 1下一次轮到地址为 2 的变送器。每轮之间间隔 100ms给从站足够的处理时间。现场实测总线 9600 波特率下单帧请求和响应合起来也就是几十毫秒1s 轮询两路远程数据完全够用。实际调试中遇到了一个很典型的时序问题发送完请求帧后立刻切换 USART 为接收模式结果收不到任何响应。原因是 RS-485 收发器的方向控制引脚还停留在发送状态。正确的做法是请求帧最后一个字节发送完成后等待发送完成中断标志置位再延时一个帧间隙至少 3.5 个字符时间最后才把收发器切换到接收模式。这个方向切换的时机问题是 RS-485 调试中最常见的坑没有之一。5.3 读到的原始数据如何转成最终温度变送器返回 Modbus 响应帧假设返回寄存器内容是0x01 0x2C十进制 300。很多 PT100 变送器的输出分辨率是 0.1°C那么实际温度就是 300 × 0.1 30.0°C。也有变送器用 0.01°C 分辨率那就看手册。我这边用的变送器固化了 0.1°C 的分辨率所以转换统一为温度 寄存器值 x 0.1。如果寄存器值是有符号数比如负温注意符号扩展。不要直接转成无符号再乘会变成个非常大的数值。ST 的 HAL 库开发环境本身就支持浮点直接用 float 计算是最省心的。最终每条温度通道都经过限幅滤波和滑动平均处理后存入结构体上层逻辑统一读取。6. 常见问题与排查技巧6.1 本地温度跳变和读数异常本地温度读数如果出现规律性尖峰可以先看一下是不是读取频率和传感器转换时间冲突。PJ85718DM 如果上一次转换还没完成立刻去读寄存器会读到不完整数据表现就是某个偶尔的读数跳变。解决办法是两次读操作之间加一个延时确保间隔大于传感器转换时间最好是转换完成后才读。可以在初始化配置寄存器的返回数据里看到转换完成标志位调试时这几个标志就更直观。另外一个容易忽略的是 I2C 总线的上拉电阻。PJ85718DM 挂在 STM32F415RG 的 I2C1 上如果上拉电阻太大比如 10kΩ总线电容也大SCL 和 SDA 的上升沿会变得很钝。距离稍长一点主机开始收 NACK。我实测下来 4.7kΩ 对板内传感器是可靠的如果传感器通过排线延长到 30cm 以上建议上拉到 2.2kΩ。6.2 远程温度通信时好时坏远程通信问题现场里十有八九是物理层和切换时序问题。先检查 RS-485 的 A/B 线有没有接反再接上终端电阻然后用示波器看总线波形。如果波形振幅偏低可能是终端电阻太靠近驱动端或者偏置电阻阻值不对。如果总线空闲时电平不确定那就是偏置电阻缺失或者阻值过大。时序问题就是前面说的方向切换。还有一种容易踩的坑是主站发送完了最后一个字节但缓存没有清空导致下一轮查询时把残留数据当响应解析。代码里建议每个轮询周期都清一下接收缓冲区。6.3 负温度读数变成很大的正数这个问题在本地和远程都可能出现。负温度时温度寄存器或者 Modbus 返回值是有符号数代码如果用uint16_t直接转浮点负数会变成 65536 附近的值。排查方法很简单直接用调试器看原始寄存器值。如果寄存器值是 0xF12C但实际温度是 -11.6°C 附近那就说明符号扩展没处理。把原始值先转成int16_t再做浮点运算就正常了。这个坑在项目调试的头一天我就踩过一次现象是室内温度降到 -2°C 时显示突然变成一个很大的数。后来加了符号扩展数据就平滑了。可以说这是温度监测项目最经典也最容易犯的错写代码时一定要养成习惯先看寄存器是不是有符号再决定用哪种类型做运算。6.4 校准值的保存与恢复校准偏移量比如前面说的 0.3在调试时可以直接写在代码里但量产时最好固化到掉电不丢的存储区。STM32F415RG 自带 Flash可以用一个专门的页来存校准参数。注意写 Flash 前要擦除整页不能单独改一行。校验机制也要加比如存两个位置读取时对比是否一致不一致就退回默认值。这个细节看起来不起眼但设备出厂前如果校准值丢了现场就会多出一堆温度不对的工单。7. 一些实操中的额外心得这套方案最终跑下来硬件和软件上的主要风险和坑都处理完毕。再补充几个小建议对你做类似温度项目会非常有帮助。第一给每个传感器通道都加一个独立的健康状态标志。不要等到温度值明显不对了才上报故障。合理做法是持续 N 秒读不到合法数据就把这条通道标记为离线让应用层可以单独处理而不是用旧值继续参与控制逻辑。HVAC 系统如果用了错误的温度值去启停风机那造成的舒适度影响就不是一条报警能挽回的。第二I2C 和 RS-485 总线上的通信不要盲信一端。开发调试阶段尽量用逻辑分析仪或者串口抓包去验证领导可能只看最终结果但你要对数据链路中间每一步都有把握。运行日志里记录原始帧和解析后的值的对比对远程排查系统问题作用很大。第三关于测试环境一定要做好温度梯度测试。不仅要在 25°C 的恒温里测还要在高温和低温边界跑一下。温度传感器在极限温区的表现往往和常温不一样比如低温下的精度、电源的低温特性、总线电平阈值等这些都会在不同温度点上暴露出来。HVAC 设备的使用环境跨度大在实验室里多测一种温度条件现场少跑一趟。最后再说说选型思路。STM32F415RG 和 PJ85718DM 这个组合在 HVAC 中低成本的节点场景里是挺平衡的一颗主流 MCU一颗简单可靠的数字温度传感器加上成熟的 RS-485 Modbus 总线既能满足本地高精度采集又能覆盖远程多点轮询。如果你手头的项目对温度路数要求不多但分布范围广、环境干扰大这套架构可以原封不动地复用如果你需要更多本地温度点把 PJ85718DM 挂在同一条 I2C 总线上分地址读取或者加 TCA9548A 分通道也都是简单扩展就能实现的。在项目收尾回头复盘时我最深的体会是这种看似简单的温度采集方案真正花时间的从来不是那几行读写代码而是藏在硬件布局、总线时序、数据可信度判断里的这些细节。把每一个环节吃透踩过的坑才真正变成了你写进下一个项目里的经验。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →