做嵌入式这些年,接的最多的一类活儿就是“把温度测准,再送出去”。标题里这套系统,是我前阵子给某商用HVAC机组做的温度监测方案,主控用的是 STM32F756ZG,本地温度交给 PJ85718DM 这颗数字传感器,远程温度则是通过 RS485 挂了几路子表。整套东西跑下来已经稳定运行了几个月,中间踩的坑和摸索出的经验,值得整理成一篇帖子。这篇文章适合正在做环境监测、暖通设备控制、或者想搞明白“本地+远程双路温度采集”架构的兄弟参考。
先从需求说起。所谓本地温度,指的是主控板附近、风机盘管进出风口这些位置的测温点;远程温度则是分散在几个风道、回风井或者机房不同角落的测温模块。差异在哪?本地走 I2C,一两厘米的走线,数据直接读;远程走总线,十几米甚至几十米的线缆,干扰、压降、地电位差全来了。所以这套系统表面上是“两个温度传感器”,本质上是两种完全不同的采集链路,放在一颗高性能 MCU 上统一处理。
当时选 STM32F756ZG,很多人觉得浪费,测个温度用 8 位机就够了。但真做起来就知道,这颗 Cortex-M7 内核、216M 主频的 MCU 带来了极大的冗余度:跑个实时调度、同时维护 Modbus 通讯、做滤波和告警逻辑、预留联网接口,CPU 占用依然很低。这意味着后续想加功能、升级协议栈,都不用推倒重来。
1. 需求拆解与整体方案设计
1.1 到底要解决哪些问题
一套 HVAC 机组的温度监测,听上去就是“单片机读传感器,然后把值显示出来”,实际上拆开有四个硬需求。
第一是精度与一致性。本地传感器和远程传感器虽然物理上不同,但上报到上位机之后数据要能放在一起比较、运算。这就要求两端都做好校准,远程那边用的模块也必须是同一量级精度的传感器,不能一个 0.5°C 精度、一个 2°C 精度,否则风道两侧温差 3°C 到底算不算异常根本说不清。
第二是通信可靠性。远程温度模块分布在几十米外的风道里,现场环境少不了变频器、风机马达这些电磁干扰源。最开始我试过用 I2C 线直接拉长距离,结果在压缩机启动瞬间数据直接乱掉,这个方向很快就毙了。工业上远程测温最成熟的做法还是 RS485 总线加 Modbus 协议,抗干扰能力强,节点扩展简单。
第三是本地与远程的时钟与调度差异。本地传感器可以在主循环里随时读,远程模块一次查询要等从机响应,最坏情况下一轮轮询要几百毫秒。系统里所有温度数据的采集时间戳必须对齐到同一帧逻辑里,不能让本地温度是这一秒的值、远程温度是上一秒的值,否则后续算温差毫无意义。
第四是报警与联动。温度不是采回来就完事,超过阈值要能够触发继电器动作,控制加热或制冷设备,并且要把告警信息通过 RS485 转发给上位机。这就需要在固件里设计好阈值比较、回差控制、告警去抖,避免温度在临界点抖动时继电器反复通断。
1.2 整体方案骨架
最终方案的架构可以分成三层来理解。
采集层有两个分支:本地那路是 PJ85718DM 直接挂在 STM32F756ZG 的 I2C1 总线上,一颗芯片就够,如果以后要加点位,凭 A0/A1/A2 地址线的组合可以在同一根总线上挂 8 颗,扩容很简单。远程那路是 3 个 RS485 温度采集模块,走 Modbus RTU 协议,挂在同一条 485 总线上,从机地址分别设为 1、2、3。
主控层负责把两路的原始温度值读回来,经过软件滤波后,换算成统一精度的数据,同时做阈值判断、告警输出、数据打包。
输出层预留了两种通道:一路是 RS485 连上位机,走 Modbus 从机模式,让上位机可以随时读取当前温度与设备状态;另一路是板载的以太网接口,留作以后做 Web 访问和云平台对接。STM32F756ZG 自带以太网 MAC,硬件上直接省掉一颗外部 MAC 芯片,这也是选它时的一个重要加分项。
1.3 器件选型的逻辑,不是只看参数
为什么本地传感器选 PJ85718DM,而不是热敏电阻加 ADC,也不是 DS18B20?我是从替换性和批量采购的角度考虑的。PJ85718DM 这类芯片的封装、引脚定义和寄存器结构基本兼容传统的 LM75/TMP75 规范,也就是说硬件和驱动都有成熟参考,万一这颗料缺货,可以无缝换用其他兼容芯片,固件不用大改。这一点对长期做产品的兄弟来说太重要了。
DS18B20 虽然单总线很省引脚,但时序要求苛刻,且一次转换时间最长到 750ms,在多路采集的调度里很被动。PJ85718DM 的 I2C 接口则是标准总线,SCL 时钟可以跑到 400kHz,一次转换在 12 位分辨率下也就几十到上百毫秒级别,远快于 DS18B20。
STM32F756ZG 的选择也考虑过降级方案,比如 STM32F103 或者 GD32F103。但从整个系统看,我需要 216MHz 的主频来处理后续可能增加的加密通信和协议栈,需要硬件 FPU 来做滤波算法,需要足够大的 RAM 来跑 FreeRTOS 和 Modbus 数据缓冲。F756ZG 的 1MB Flash 和 256KB RAM 让整个项目几乎不用操心资源问题,代码也写得比较放手。
2. 硬件电路设计与关键落地细节
2.1 PJ85718DM 本地采集电路的接法与坑点
PJ85718DM 的典型接法不复杂,但越简单的电路越容易在细节上翻车。下面是核心连接关系:
- VCC 接 3.3V,旁边放一颗 0.1uF 去耦电容,芯片最好离 MCU 近一点。
- SDA、SCL 分别用 4.7kΩ 电阻上拉到 3.3V。
- A0、A1、A2 地址线根据实际拨码全部接地,得到 0x48 这个从机地址。
- 芯片背面有暴露焊盘,PCB 上一定要打通孔到地平面,帮助散热,也能减少自热误差。
这里有两个容易犯的错误。第一个是上拉电阻选的过小,有些参考设计直接放 1kΩ,在 3.3V 供电下静态电流偏大,而且会加重 MCU I2C 引脚驱动负担,导致边沿变缓;但选得过大也不行,比如 10kΩ 在总线电容较大的时候拉不起来。我实测下来,3.3V 系统、总线长度不超过 10cm 的场合,4.7kΩ 是最稳的。
第二个坑是芯片自热。PJ85718DM 这类贴片传感器对自身功耗引起的小幅温升很敏感,如果旁边就是 DC-DC 电感和 LDO,读到的温度会比环境温度高出 1°C 到 2°C。第一次做样板时我没注意,把传感器放到了电源转换器件正下方,结果无论如何校准都差 1.5°C,挪开 3cm 之后恢复正常。所以布局时一定要把它当成一个精密模拟器件对待。
注意:本地传感器不要放在 PCB 边缘或者风口直吹的位置,板边缘的热容小,受环境波动影响大,测出来的温度代表不了机箱内部真实温度。
2.2 远程温度网点怎么接入:走 RS485 加 Modbus 是最稳的选择
远程温度模块的物理链路用 RS485 是早就定下来的。RS485 是差分传输,两条线 A、B 上的电压差代表逻辑值,共模干扰会被接收器抑制掉,所以非常适合几十米长线、靠近变频器的现场环境。
电路上要处理好四个环节。首先是收发器选型,常规的 MAX485 这类芯片就可以,但要注意它的 A、B 端要加上下拉偏置电阻。很多人在总线上只接了终端电阻,却不加偏置,导致总线空闲时电平不确定,从机会收到乱码。我的做法是主控端 A 线上拉 5.1kΩ 到 3.3V,B 线下拉 5.1kΩ 到 GND,这样空闲态被稳定拉在逻辑 1 上。
然后是终端匹配电阻。只有当总线长度超过大约 10 米,或者波特率高于 9600 时才需要加终端电阻。HVAC 现场走线通常有二三十米,所以我在总线最远端的从机模块上并联了 120Ω 电阻,主控端的收发器 A/B 之间也并联 120Ω。两头各一个终端电阻,中间节点不加。
再就是防护。现场线缆从风机房走线槽,可能会碰到大功率器件启停带来的浪涌,所以在 A/B 线上要放 TVS 管和 PTC 自恢复保险,最好再串两颗 10Ω 电阻做限流。这部分电路虽然不复杂,但省掉之后基本都会在某次雷击或者电机启动瞬间烧掉收发器,故障率很高。
最后是供电问题。远程模块如果直接从主控板拉电源,长线压降会导致模块供电不稳,特别是 485 总线收发瞬间需要较大电流。我这里的远程模块统一使用 24V 供电,模块内部再转成 3.3V,总线电源和 485 信号分开走。如果模块数量多,还会在两个电源节点之间加磁珠隔离。
2.3 MCU 最小系统、供电与隔离设计
STM32F756ZG 的工作电压是 3.3V,但 HVAC 设备现场提供的是 24V 直流电源,所以板级电源链路需要两级转换。
24V 先经过防反接二极管和保险丝,进入一颗隔离 DC-DC 模块,输出 5V 隔离电压;再通过低噪声 LDO 转成 3.3V 给 MCU 和传感器供电。为什么这里要求隔离?因为 RS485 总线直接面对外部环境,如果外部网段出现地电位差,会通过 485 收发器灌到主控板,再串到 MCU 上,轻则复位、重则烧引脚。加了隔离 DC-DC 之后,MCU 的地和 485 总线的地完全隔开,抗干扰能力上一个档次。
MCU 最小系统里容易被忽略的是晶振的选择。F756ZG 需要使用 25MHz 外部晶振来驱动以太网 PLL,如果以后要用到以太网功能,晶振必须配 25MHz,别只图省事放 8MHz,后面联网功能开不出来还得改板。同时给晶振两个负载电容,我习惯用 6.8pF 到 12pF 之间,具体要看晶振规格书推荐的 CL 值。
复位和启动配置也要处理。BOOT0 引脚通过 10kΩ 下拉到地,确保从 Flash 启动;NRST 接一颗 100nF 电容到地,防止上电瞬间干扰导致误复位。调试接口 SWD 的 SWDIO、SWCLK 上预留排针,方便产线烧录和在线调试。
2.4 PCB 布局上容易翻车的地方
第一版 PCB 画完后,硬件评审时我发现了三个隐患,这里直接分享出来。
第一,485 收发器的 A/B 差分线要从收发器出来就并行走线,中间不要打过孔换层,保持相同长度,避免差分阻抗突变。第二,I2C 的 SDA、SCL 虽然是数字信号,但它们是漏极开路结构,边沿由外部上拉电阻决定,如果走线过长或者途经电源区域,很容易被耦合噪声拉出多余毛刺,导致传感器响应异常。因此 I2C 走线应该短、粗、远离 24V 电源走线。第三,本地传感器芯片的电源引脚和接地引脚之间必须就近放去耦电容,这个电容不是随便放的,它要尽量靠近芯片引脚,路径越短越好,否则高频噪声滤不掉。
还有一个建议,就是板上测试点要留足。I2C 总线上留 SDA/SCL 测试点,485 的 A/B 测试点。调试的时候逻辑分析仪和万用表都要夹,没有测试点去刮阻焊层很痛苦,还会刮坏板子。
3. 固件开发:从寄存器到能用的温度值
3.1 先读写 PJ85718DM:I2C 时序与寄存器操作
固件开发的第一步,是让主控能稳定的从 PJ85718DM 读到一个温度值。这颗芯片的寄存器结构不算复杂,核心寄存器有三个:温度寄存器(指针 0x00)、配置寄存器(指针 0x01)、阈值寄存器(指针 0x02 和 0x03)。
一个标准的读取流程是:先发一个写命令把指针指向 0x00,然后重新发送起始条件,发读命令,连续读取两个字节,得到 16 位温度数据。下面是我在实际项目里用标准库写的读取函数片段,用的是硬件 I2C:
uint16_t PJ85_ReadTemp(void) { uint8_t buf[2] = {0}; uint8_t reg = 0x00; // 指针指向温度寄存器 HAL_I2C_Master_Transmit(&hi2c1, 0x48 << 1, ®, 1, 100); // 连续读两个字节 HAL_I2C_Master_Receive(&hi2c1, 0x48 << 1, buf, 2, 100); return (uint16_t)((buf[0] << 8) | buf[1]); }读回来的两个字节不能直接拿来用。PJ85718DM 的 12 位温度数据在寄存器里是左对齐的,高 12 位有效,低 4 位是符号扩展位或者空位。处理方法是把 16 位数据右移 4 位,取有符号整型再乘以分辨率。分辨率在默认配置下是 0.0625°C,也就是 1/16°C。
如果读出来的数据一直是 0x7FFF 或者 0xFFFF,多半是 I2C 地址不对或者上拉电阻失效。我当时犯的错误是忽略了芯片地址左移一位的问题,HAL 库的寻址参数需要把 7 位地址左移一位填入,也就是 0x48 要变成 0x90,这个问题在排查阶段浪费了不少时间。
3.2 温度数据格式与换算:为什么读回来要右移四位
PJ85718DM 的温度数据格式是二进制补码,这一点要特别注意。以实际项目中读到的数据举例:如果读回 0x1A00,右移 4 位得到 0x01A0,也就是十进制 416,乘以 0.0625 后得到 26.0°C。这个计算过程看着简单,但负温度处理最容易出错。
当温度低于 0°C 时,寄存器里的值以补码形式存在。比如 -10°C,对应的是 0x05A0 取反加一后的补码表示。在 C 语言里如果先右移再做有符号转换,就可能因为符号位扩展问题得到错误结果。我的建议是先把 16 位数据强制转换为 int16_t,再右移,这样符号位能正确保留:
int16_t raw = (int16_t)PJ85_ReadTemp(); float temperature = (float)(raw >> 4) * 0.0625f;这个细节看起来小,但在做系统联调时,负数温度如果不处理对,冷库场景下的数据会完全不可信。
配置寄存器方面,PJ85718DM 支持设置转换分辨率。默认上电状态通常是 12 位分辨率,这也是我推荐的状态,因为 0.5°C 以上的精度在这种场景够用,而且转换时间要比 9 位模式稍长,但数据稳定性更好。如果需要更快的转换周期,可以把分辨率降为 9 位,但对应的量化误差会变大约 0.5°C,HVAC 温度控制一般不推荐。
提示:每次读完数据后要注意是否有 I2C 总线仲裁错误。在一片传感器和 MCU 之间一般不会冲突,但如果你后期在同一总线上挂多片 PJ85718DM,软件上建议每次通信后做一次总线状态检查,必要时调用 HAL_I2C_Reset 恢复总线状态。
3.3 Modbus 多路从机数据聚合协议设计
远程温度的读取,我采用了主控作为 Modbus 主机、远程模块作为从机的模式。每个远程模块内部也有一个温度传感器,负责采集所在区域的空气温度,把数据存到保持寄存器里,等待主控查询。
主控的轮询逻辑比较简单:逐一发送 03H 功能码读保持寄存器请求,从机返回对应的温度值。请求帧的格式是:从机地址、功能码、起始寄存器高字节、起始寄存器低字节、寄存器数量高字节、寄存器数量低字节、CRC16 低字节、CRC16 高字节。
整个协议栈里最容易写错的就是 CRC 校验。Modbus RTU 的 CRC 是多项式 0xA001 的循环冗余校验,初始值为 0xFFFF,每个字节先与 CRC 低字节异或,然后右移 8 次,遇到最低位为 1 就与 0xA001 异或。我贴一下验证过的计算函数:
uint16_t Modbus_CRC16(const uint8_t *data, uint16_t len) { uint16_t crc = 0xFFFF; uint16_t i; uint8_t j; for (i = 0; i < len; i++) { crc ^= data[i]; for (j = 0; j < 8; j++) { if (crc & 0x0001) crc = (crc >> 1) ^ 0xA001; else crc = crc >> 1; } } return crc; }远程设备数量我目前接了 3 个,轮询周期设定为 500ms 轮一圈。如果站点增加到 10 个以上,就要考虑把响应超时时间调短、失败重试次数限制在 2 次以内,否则某个从机掉线会拖慢整个轮询周期。现场最怕的不是所有从机全挂,而是那一两个偶尔掉线的节点,所以协议层要有超时记录和自动恢复机制,而不是硬等。
3.4 把任务调度组织起来:裸机轮询加查询标志
有人会问,这颗 MCU 这么强,为什么不用 FreeRTOS 管理任务?其实我用的是裸机主循环加状态机的简化方式。原因很直接:温度采集的逻辑本身是顺序性的,本地读取、远程读写、滤波、告警判断,每一环之间没有强并行需求,用 RTOS 引入任务切换反而增加调试复杂度。
主循环大致是这个节奏:
- 每 100ms 读一次本地 PJ85718DM。
- 每 500ms 轮询一次远程三路模块。
- 每次采集完成之后,调用滤波函数更新当前温度。
- 每 200ms 做一次阈值比较和告警输出。
- 每 1s 更新一次 RS485 从机模式下的数据寄存器,供上位机读取。
这个调度用系统 tick 去记录各个事件的上一次执行时间,在循环里判断是否到期,代码非常简单、直观、易排查。如果以后功能多到需要并发处理,再移植 RTOS 也不迟,F756ZG 的资源完全扛得住。
4. 滤波算法、阈值告警与系统联动
4.1 为什么需要对温度处理,而不是直接拿原始值上报
直接读出来的温度值是会抖的。尤其远程温度模块,数据经过长线传输、电磁干扰和传感器自身噪声影响,相邻两次读到的值可能差 0.3°C 到 0.5°C。如果把这个原始值直接用于告警判断,就会出现温度在临界点附近抖动时,告警一会儿触发、一会儿消失,这在现场会被当成设备故障。
我采用的是一阶低通滤波和滑动平均结合的方案。滑动平均取最近 5 次的平均值,能有效平滑脉冲干扰;一阶低通滤波公式用于时间常数的精细调整:
filtered = filtered + (new_value - filtered) * alphaalpha 取 0.3 左右,既保证响应速度,又不会太迟钝。本地传感器离主控近,噪声小,alpha 可以取 0.5;远程链路噪声大,取 0.2 效果更好。
滤波效果可以用一个简单实验验证:拿一个正常工作的传感器,人为在读取函数里注入一个偏差 5°C 的尖峰,如果滤波后输出值的变化被限制在 1°C 以内,说明参数合适。
4.2 阈值告警与回差控制,避免继电器频繁跳动
HVAC 控制里有一个核心概念:回差。假设你设置高温告警阈值是 30°C,当温度升到 30.2°C 就触发继电器断开;但温度自然会在这个值附近小幅波动,如果不加回差,继电机会在 29.8°C 和 30.2°C 之间反复通断,几个小时内触点和继电器线圈就会烧坏。
我的处理是给每个阈值设置回差区间。比如上限 30°C,回差 2°C,那么:温度大于 30°C 时触发告警,温度低于 28°C 时才解除告警。这样形成一个滞环,告警不会因为一个瞬时波动就反复切换。
具体到代码实现,不只是做一次阈值比较,还要记录当前的告警状态:
if (temp > UPPER_THRESHOLD) relay_state = ACTIVE; else if (temp < (UPPER_THRESHOLD - HYSTERESIS)) relay_state = INACTIVE;告警输出方面,我用 STM32 的一个定时器通道输出 PWM 来控制继电器,同时把告警状态记录到 Modbus 保持寄存器,上位机可以读得到。继电器驱动用了光耦隔离和单独的继电器电源,避免触点动作时的反电动势干扰 MCU。
4.3 系统联动与数据上云预留
既然是 HVAC 系统,单点温度监测只是一个基础能力,最终还是要服务于控制逻辑。在这个项目里,本地温度用于风机的启停控制逻辑,当进风口温度低于某个值且持续 10 秒,关闭风机;远程温度用于送回风温差判断,如果多个风道温度差值超过设定范围,系统会认为存在风道堵塞或风机运行异常。
这些联动逻辑看似简单,但涉及到一个优先级问题:告警、控制、数据上报不能互相阻塞。比如在向 RS485 发送一条较长的数据帧期间,恰好触发了一个告警,如果代码是同步发送,那么继电器动作会被延后几十毫秒,这在工业场景下是隐患。所以我的实现里,所有的控制动作都在中断回调或者高优先级函数里直接置位,不让 RS485 发送流程阻塞它们。
至于云平台预留在目前阶段只是把温度数据打包成结构体,存入一段独立的 RAM 缓冲区,同时预留了 MQTT 协议栈的接口位置。等现场需要接入平台时,只需要把缓冲区数据交给网络任务发送即可,应用层无需改动。
5. 调试历程与现场问题实录
5.1 上电不读数的头号嫌疑:I2C 上拉与地址错误
每次新板子拿到手,第一步都是确认传感器能不能正常通信。烧录一个简单的扫描程序,遍历 0x48 到 0x4F 地址,看总线上能不能扫到设备。这个项目第一次扫描就什么都扫不到,万用表量 SCL、SDA 电压,发现 SDA 一直被拉低。
查了半天发现焊盘虚焊导致 SCL 引脚悬空,总线时钟无法产生,后续所有通信自然全部卡死。补焊后恢复正常。这类问题在手工焊接样板时非常常见,特别是贴片传感器引脚本来就小,建议焊完用放大镜检查一遍,或者用万用表二极管档测一下引脚与 MCU 引脚之间的通断。
排除硬件问题后,下一个容易出错的点是地址。如果你在单片机上把地址写成 0x48,而没有在 HAL 库参数里左移一位,I2C 通信会一直收不到 ACK。这个点我在上面也提过,这里再强调一次,因为它真的是排查时间最长的坑。
5.2 RS485 长线通信乱码
远程模块接入后,第一个问题就是主控收上来的数据 CRC 校验失败率很高,大约三分之一的数据帧要重发。用示波器观察 A/B 差分波形,发现总线空闲时电平不稳定,在 0V 附近漂移。
问题根源是我只加了终端电阻,没加偏置电阻。总线空闲时没有设备驱动,电平会反射到不确定状态,接收端随机读到的电平会被解析成数据位。在 A 和 B 上分别加上下拉偏置电阻后,空闲电平稳定在 -200mV 以下,乱码立刻消失。
此后我又加了一个软件策略:在 Modbus 从机响应帧的接收过程中,利用硬件 UART 的空闲中断来判断一帧数据是否结束,而不是使用固定长度的字节超时。这样即使个别字节因为干扰丢失,也不会把整帧解析错位。
5.3 温度跳变、采集不一致的排查
本地传感器偶尔读到一个异常值,比如从 25°C 突然跳到 -40°C,然后又跳回来。我最初以为是滤波算法的参数问题,后来发现是 I2C 传输被中断打断,导致读到的两个字节来自两次不同的转换周期,组合出来的数据就乱套了。
解决办法有两个:第一,在 I2C 读取期间关闭更高优先级的中断,或者使用 I2C 的 DMA 模式;第二,在软件里做合理性判断,如果两次相邻读数差值超过 5°C,就判定为无效数据,丢弃并重新读取。 我实际采用的是后者,成本最低,效果也很好,因为在 HVAC 环境里温度变化不可能超过这个速率。
本地与远程的温度值不一致是另一个常见咨询。两个传感器本身的精度不一致、安装环境不一样,都可能造成差异。特别是远程模块装在风道中央,空气流动快,温度响应快;本地传感器贴装在 PCB 上,有板温影响,二者出现 1°C 到 2°C 偏差是正常现象。处理方式不是在软件里强行修正匹配,而是在上位机里增加传感器偏差补偿字段,让现场安装人员在调试阶段填入偏移量。
5.4 问题排查速查表
我把这次项目中遇到的几个典型问题整理成一张表,方便以后直接对照排查。
| 现象 | 最常见原因 | 检查与处理方法 |
|---|---|---|
| I2C 扫描不到设备 | 焊盘虚焊、上拉电阻缺失、地址参数错误 | 先量引脚通断,再检查 SDA/SCL 对 3.3V 的电压,确认上拉是否正常;软件里确认地址是否左移一位 |
| 温度读到满量程值 | 芯片通信失败、读到的数据未右移 | 检查 I2C 时序,用逻辑分析仪确认两个字节的读取;处理补码右移 |
| 485 乱码、CRC 错误高 | 缺少偏置电阻、终端电阻匹配不当 | 加偏置电阻,总线两端加 120Ω 终端电阻 |
| 温度偶发跳变 | I2C 中断打断、电源噪声 | 读取期间屏蔽中断、数据合理性判断过滤 |
| 传感器温度整体偏高 | 传感器自热、靠近发热器件 | PCB 布局避开发热源,检查自热影响 |
| 485 收发器损坏 | 缺少 TVS/限流保护 | 添加 TVS、PTC 和串阻 |
| 继电器频繁通断 | 阈值没有回差 | 加入滞环控制,告警与解除采用不同阈值 |
6. 一些实操中的体会与惯用技巧
做完这个项目,一些以前没太在意的细节变得特别刻骨铭心。第一个体会是,温度监测系统的瓶颈往往不在 MCU 或者传感器本身,而在总线和电源这两个“配角”上。I2C 上拉、RS485 偏置、隔离电源,这些东西单独看都很不起眼,但出了问题都是最难查的,因为它们的影响是概率性的,不是一上电就挂。
第二个体会是,写代码时要为现场调试留后门。我在固件里加了一个调试模式,通过 Modbus 读一个特定寄存器就能把本地和远程的原始值、滤波值、告警状态全部打出来,现场排查的时候不用抱着烧录器来回跑,很大程度上提高了效率。这个习惯我现在每个项目都会保留。
第三个建议是,上位机的轮询逻辑一定要做好超时处理。主控作为 Modbus 从机时,如果上位机用很短的超时时间去读数据,一旦主控正在处理远程轮询或者写入 Flash,响应就会超时。我的办法是协议层单独划分响应优先级,上位机的读取请求放在主循环里最高优先级处理,宁可让本地采集延后几毫秒,也要保证对外通信不被阻塞。
这个项目后续的扩展方向,我打算在远程模块里增加湿度传感器,把风道温湿度一起上报;同时利用 F756ZG 的以太网接口直接内置一个简易 Web 服务器,现场维护人员用浏览器就能查看温度曲线,不用带电脑和设备管理软件。 现在算下来,这套从选型、硬件、固件到调试的流程已经比较完整,兄弟们如果也在做类似的东西,希望这篇记录能帮你们少走点弯路。