最近在捣鼓一个嵌入式温控项目,核心任务很明确:基于 PJ85718DM 这颗数字温度传感器,配合 STM32F415ZG 做主控,把本地和远端的多点温度实时采集上来,再通过 RS485 总线上报到上位机。项目场景是嵌入式和 HVAC(暖通空调)设备,这类设备对温度监测的依赖度极高,精度、稳定性、抗干扰能力一样都不能马虎。
这篇文章就围绕这个项目展开,从器件选型、硬件设计、单总线驱动、远程通信到工程化排障,完整记录一遍踩坑和落地的全过程。如果你也在做类似的温控系统、楼宇自控、机房环境监测,或者只是好奇单总线传感器怎么在工业现场稳定工作,这篇内容应该能给你一些可直接抄作业的参考。
1. 先拆标题:这个项目到底在解决什么问题
1.1 三个关键词背后的真实需求
“嵌入式”和“HVAC”这两个词,定义了芯片的生存环境。嵌入式意味着资源有限、实时性要求高;而 HVAC 场景更麻烦,传感器往往分布在风管、冷水管、回风口、室外机组等位置,走线长、干扰大、温差跨度大,普通模拟温度传感器在这种现场很容易被干扰得乱七八糟。
再看“本地与远程温度”,这是需求方的核心诉求:本地温度通常指控制器安装位置附近的温度,比如控制柜内的环境温度、回风温度;远程温度则是分布在几十米甚至几百米外的管道温度、房间温度。设备不仅要自己在本地做显示和控制逻辑,还要把数据传送给中心监控系统,供后台统一调度。
我用到的两个器件刚好各司其职:PJ85718DM 负责把物理温度变成数字信号;STM32F415ZG 负责读取这些数据、做运算处理、驱动显示、跑通信协议。一个采集端,一个控制端,分工明确。
1.2 系统架构:从传感器到上位机的完整链路
整条数据链路是这样的:PJ85718DM 温度传感器通过单总线接口接到 STM32 的 GPIO 上,主控按照单总线协议逐个读取所有挂载传感器的温度值;读取结果经过滤波、标定、故障判断之后,一方面送到本地的显示屏/数码管做界面展示,另一方面打包成 Modbus RTU 数据帧,经 RS485 收发器发到远端的上位机。
这里有一个容易被忽略的点:题目里说的“本地与远程”,在实际项目里不只是“一个传感器放在近处,一个放在远处”,更常见的是“本地需要显示和控制,远程需要监控和记录”这两个层次。所以系统设计时,通信模块和显示模块都是标配,不能因为“远程”就砍掉本地界面,也不能因为“本地”就不考虑数据上传。
1.3 方案选型时怎么思考的
先说 PJ85718DM 这颗传感器。它是一款数字温度传感器,走单总线协议,一颗芯片上同时集成测温电路、A/D 转换、存储器和唯一的 64 位序列号。这意味着不需要外接运放、不需要 A/D 采样电路,一根数据线就能从主控引出去,串联几十个传感器节点,这在 HVAC 现场是非常实用的特性。
再说 STM32F415ZG。这颗芯片属于 STM32F4 系列,Cortex-M4F 内核,主频能跑 168MHz,带 FPU、1MB Flash、192KB RAM,还内置了以太网 MAC 控制器。做 HVAC 控制器来说,这个配置算得上有余量——它不仅要处理温度采集,还要跑控制算法、人机交互、通信协议,CPU 资源紧张是嵌入式项目最常见的坑,选一颗性能冗余一点的芯片,后面开发会舒服很多。
2. 器件选型与硬件设计:不止是把芯片连起来
2.1 PJ85718DM 的特性梳理
PJ85718DM 这类数字温度传感器,核心优势是“信号数字化”这件事在芯片内部就完成了。它直接把温度转换成数字量存进寄存器,主控只要按协议把数据读出来就行,不需要关心 ADC 参考电压、信号衰减、阻抗匹配这些问题。
实际用下来,这类传感器的几个关键参数要特别关注:测温分辨率可配置,最高到 12 位(0.0625°C 步进),最低可以降到 9 位来换取更快的转换时间;测温范围覆盖 -55°C 到 +125°C,HVAC 场景的 -20°C~+60°C 温区完全够用;转换时间在 12 位模式下大约是 750ms,这个时间决定了采集周期的最短下限。
另一个特点是每颗芯片都有 64 位唯一 ID。如果总线上只挂一颗传感器,这个 ID 基本没用;但如果一根总线上挂多颗传感器,就必须靠这个 ID 来做 ROM 搜索和地址匹配。项目里我在水管温度和风管温度两个点各放了一颗传感器,寻址就是通过读 ROM 完成的,后面展开说。
2.2 STM32F415ZG 的资源配置
选择 STM32F415ZG 的原因,除了上面说的算力,还有几个很实在的考虑。第一,它的 GPIO 耐压是 5V 容忍的,PJ85718DM 在外部供电模式下数据线电平是 3.3V 还是 5V 需要匹配,这颗芯片能比较从容地处理;第二,它有 5 个 UART,RS485 通信占一个,调试串口占一个,剩下的还能留给外部扩展;第三,内置以太网 MAC,后续如果项目要从 RS485 升级到以太网通信,不需要换主控。
Flash 和 RAM 的余量也很重要。HVAC 设备往往要求一次性写完功能,后期维护升级很少,1MB Flash 足以把 Modbus 协议栈、LCD 驱动、控制逻辑、Bootloader 全部装进去;192KB RAM 跑浮点运算、多帧缓存也不紧张。说实话,用这颗芯片做单纯的温度采集有点大材小用,但做整个 HVAC 控制器,它是够格的。
2.3 硬件连接与现场保护
硬件连接不复杂,但细节多。传感器数据线接主控一个 GPIO,同时通过一个 4.7kΩ 电阻上拉到 3.3V 电源。这里要注意上拉电阻的选择:阻值太小,总线拉低时电流太大,传感器和 GPIO 都有可能过载;阻值太大,总线释放时上升沿太慢,高速时序下容易出错。4.7kΩ 在 3.3V 供电、线长 1-2 米的情况下是比较稳的中点值。
供电方面,我强烈建议用外部供电而不是寄生供电。所谓寄生供电,就是靠数据线在高电平时的上拉电流给传感器供电,省一根线,但多点采集、长线传输时电流不够,经常出现读数漂移甚至掉线。HVAC 现场布线已经够麻烦了,不差一根 VCC 线,稳定压倒一切。
还要注意接口保护。现场走线经过电控柜、线槽,旁边可能有大功率接触器、变频器的动力线,空间辐射和传导干扰都不小。我在数据线上加了 TVS 管,电源入口加了反接保护二极管和 100nF 去耦电容,让整个采集电路在电磁环境恶劣的现场也能正常工作。
2.4 对比一下备选方案
在方案评审阶段,其实还考虑过用模拟温度传感器加 ADC 的方案。模拟传感器比如 NTC 热敏电阻,成本更低,但问题是:精度靠电阻分压和 ADC 基准源保证,后者在宽温度范围下会有漂移;信号长距离传输时压降和干扰很难处理;而且每个传感器都要占用一路 ADC 或一个多路开关,传感器一多,板子面积和成本就上去了。
相比之下,数字传感器通过单总线串联,几十个点也就一根线加三个引脚,这个优势在分布式 HVAC 场景里是决定性的。如果这个项目只是测单片机旁边的一个点,我可能就用 NTC 了;但要测多点、远程传输、抗干扰,数字传感器是正确选择。
3. 核心驱动实现:把单总线时序吃透
3.1 单总线协议的关键:时序是命根子
单总线协议虽然只有一根线,但时序要求非常苛刻。所有的读、写、复位操作都靠数据线上的高低电平跳变和延时长度来区分。简单打个比方,这根数据线就像一个摩斯电码通道,发送方和接收方必须用完全相同的时间基准来解析每一个电码,差几十微秒就可能把“1”理解成“0”。
单总线时序分三类:复位时序、写时序、读时序。复位时序是主控拉低总线 480μs 以上,然后释放,传感器在 15-60μs 后拉低总线约 120μs 作为应答信号;写时序分写“1”和写“0”,写“0”是拉低总线 60μs 以上,写“1”则是短暂拉低 1-15μs 后释放,让上拉电阻把总线拉高到剩余时间结束;读时序也是主控发起一个短暂拉低,然后释放,在极短时间后采样总线电平,传感器通过控制总线状态来返回“0”或“1”。
这三个时序里,最容易翻车的是读时序的采样点位置。读时序由主控拉低 1-6μs,释放后传感器如果要写“0”,会自己把总线拉低继续维持;如果写“1”,则总线会被上拉电阻拉高。主控必须在释放后的 15μs 内完成采样,采样太晚,一旦总线电容效应导致波形钝化,读回来可能全是“1”。
3.2 微秒级延时的实现
写驱动之前,必须解决一个基础问题:微秒级延时。HAL 库的 HAL_Delay 是毫秒级的,完全不能用。我采用的是 DWT 内核周期计数器来做延时,精度高且不依赖定时器资源。
void delay_us_init(void) { CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CYCCNT = 0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; } void delay_us(uint32_t us) { uint32_t start = DWT->CYCCNT; uint32_t ticks = us * (SystemCoreClock / 1000000); while ((DWT->CYCCNT - start) < ticks); }这里有个关键点:编译器的优化级别会影响循环延时的实际长度。用 DWT 计数方式的好处是延时不依赖循环指令周期,只要 CPU 主频稳定,时间就是准的。否则你 Debug 模式下调试得好好的,一开 -O2 优化,全部时序错乱,传感器直接不响应。
3.3 底层读写函数
有了精确延时之后,写底层驱动就顺理成章了。三个核心函数:复位检测、写一个字节、读一个字节。GPIO 拉低与释放之间,严格控制延时。
uint8_t ds_bus_reset(GPIO_TypeDef *port, uint16_t pin) { uint8_t presence = 0; GPIO_InitTypeDef gpio_init = {0}; // 配置为输出模式 gpio_init.Mode = GPIO_MODE_OUTPUT_PP; gpio_init.Pull = GPIO_NOPULL; gpio_init.Speed = GPIO_SPEED_FREQ_HIGH; gpio_init.Pin = pin; HAL_GPIO_Init(port, &gpio_init); HAL_GPIO_WritePin(port, pin, GPIO_PIN_RESET); delay_us(500); // 复位脉冲:拉低 480~960μs HAL_GPIO_WritePin(port, pin, GPIO_PIN_SET); delay_us(30); // 等待传感器应答窗口 // 切换为输入模式,读取总线状态 gpio_init.Mode = GPIO_MODE_INPUT; gpio_init.Pull = GPIO_PULLUP; gpio_init.Pin = pin; HAL_GPIO_Init(port, &gpio_init); if (!HAL_GPIO_ReadPin(port, pin)) { presence = 1; // 总线被拉低,表示传感器存在 } delay_us(450); // 等应答结束 // 恢复到输出模式高电平 gpio_init.Mode = GPIO_MODE_OUTPUT_PP; gpio_init.Pull = GPIO_NOPULL; gpio_init.Speed = GPIO_SPEED_FREQ_HIGH; gpio_init.Pin = pin; HAL_GPIO_Init(port, &gpio_init); HAL_GPIO_WritePin(port, pin, GPIO_PIN_SET); return presence; }读一个字节、写一个字节的函数类似,注意每一位之间的数据线状态恢复。这里我不建议把函数封装得太花哨,单总线时序底层的每一微秒都要直接可控,越简单越好。
void ds_write_byte(GPIO_TypeDef *port, uint16_t pin, uint8_t data) { for (int i = 0; i < 8; i++) { HAL_GPIO_WritePin(port, pin, GPIO_PIN_RESET); delay_us(2); if (data & 0x01) { HAL_GPIO_WritePin(port, pin, GPIO_PIN_SET); delay_us(60); } else { delay_us(60); HAL_GPIO_WritePin(port, pin, GPIO_PIN_SET); delay_us(10); } data >>= 1; } } uint8_t ds_read_byte(GPIO_TypeDef *port, uint16_t pin) { uint8_t data = 0; for (int i = 0; i < 8; i++) { HAL_GPIO_WritePin(port, pin, GPIO_PIN_RESET); delay_us(2); HAL_GPIO_WritePin(port, pin, GPIO_PIN_SET); delay_us(8); if (HAL_GPIO_ReadPin(port, pin)) { data |= (0x01 << i); } delay_us(50); } return data; }3.4 完整读取流程与 CRC 校验
单总线传感器的读取流程一般是固定的:复位 → 跳过 ROM 或匹配 ROM → 发温度转换命令(0x44)→ 等待转换完成 → 复位 → 跳过 ROM/匹配 ROM → 发读暂存器命令(0xBE)→ 连读 9 个字节 → 关闭总线。
9 个字节的数据里,前两个字节是温度值,第三到第八字节是报警和配置寄存器,第九字节是 CRC 校验。温度数据是 16 位补码格式,低 12 位有效。拼接和换算逻辑简单:温度 = (原始值 & 0x0FFF) / 16.0,当最高位为 1 时表示负温度,需要先取补码再换算。
CRC 校验这一步绝对不能省。项目里大多数“温度为 0 或者 85”的怪问题,其实就是数据传输时被干扰,没做校验照样把坏数据当有效数据用。CRC 校验函数用标准多项式算法实现,或者直接查表,查表速度更快。我在驱动里加了校验失败自动重读 3 次的机制,三次都失败才判定传感器故障,实践证明这个策略在工业现场能显著降低误报率。
3.5 多点传感器挂载与 ROM 搜索
回到项目里的“本地和远程”需求,我总共挂了 4 颗传感器:1 颗测控制柜内环境温度(本地),1 颗测回风管道温度(近端),2 颗测不同楼层的供水管温度(远程)。四颗传感器共用一条总线,靠 ROM 地址区分。
为了拿到每颗传感器的 ROM 地址,需要做一次总线枚举。最简做法是逐个拔插传感器,每次只挂一颗,复位后发 0x33 读 ROM 命令,把 64 位地址读出来存好。这个办法在传感器数量不超过 10 颗、安装位置基本固定的场景下完全够用。
如果传感器数量多、需要自动识别,那就得写 ROM 搜索算法。核心思路是先读每一位的两次状态,判断总线上传感器的数量冲突,再逐位选定唯一地址。这个算法逻辑不难,但位操作很容易写错,需要耐心验证。多数 HVAC 项目里传感器位置固定、编号固定,提前写好地址表更实在。
4. 远程温度监测:Modbus RTU 与 RS485 的工程细节
4.1 传输介质选择:RS485 在现场依然是主流
HVAC 现场数据要上传到几十甚至上百米外的中控室,可靠且常用的物理层方案就是 RS485。差分信号传输,抗共模干扰能力强,通讯距离能到 1200 米,理论挂载节点数 32 个(用中继还能更多),成本低、调试成熟。
也有设想用以太网方案,毕竟 STM32F415ZG 自带 MAC,外接一个 PHY 芯片就能实现,但它带来的好处在这个项目里不明显——现场没有现成的以太网布线,打 485 两芯屏蔽线的成本远低于重新跑网线。所以我最终对外,还是选择了 RS485 加 Modbus RTU。这套组合在工控领域的地位,相当于水电装修里的标准插座,谁都会接,哪儿都有。
4.2 Modbus RTU 报文设计
Modbus RTU 的报文格式非常紧凑:从机地址 + 功能码 + 数据 + CRC16。温度上报我用的是 03 功能码(读保持寄存器),把 4 路温度值放在连续的 4 个寄存器里,每个寄存器占 2 字节。主机发送查询帧:
从机地址 功能码 起始寄存器高 低 寄存器数量高 低 CRC(2字节) 02 03 00 00 00 04 CRC从机收到后回复:
从机地址 功能码 字节数 寄存器数据... CRC 02 03 08 xx xx xx xx ... CRC这里有个常规坑:Modbus RTU 的 CRC 是低字节在前,字节序搞错的话,主机永远报 CRC 错误。我因为这个浪费了半天时间。CRC 算法是标准的 CRC16-Modbus(多项式 0xA001),差一个字节顺序,收到的校验就全乱了。
CRC16 计算代码可以直接照这个写:
uint16_t modbus_crc16(uint8_t *data, uint16_t len) { uint16_t crc = 0xFFFF; while (len--) { crc ^= *data++; for (int i = 0; i < 8; i++) { if (crc & 0x0001) { crc = (crc >> 1) ^ 0xA001; } else { crc >>= 1; } } } return crc; }注意发送时先发 CRC 低字节,再发高字节。
4.3 主从结构与地址规划
我在这个系统里,STM32F415ZG 这一端是 Modbus 从机,上位机是主机。从机地址设置成 02,底下的 4 个传感器分别映射到保持寄存器地址 0x0000~0x0003。上位机只要知道这个协议表,就能把数据读走。
主从结构需要考虑的一个点是:如果一台 HVAC 机组有多块控制板,每块控制板都要上报温度,那么不同板子的从机地址必须不同。常见做法是板子上做一个拨码开关,现场安装时按设备编号拨地址。别想着“通过软件自动分配地址”,现场维护人员会觉得这是为难他们。
4.4 485 方向切换与发送时序
STM32 的 UART 是单端信号,RS485 收发器负责把 TTL 电平转成差分信号。收发器中有一个 DE/RE 引脚,高电平使能发送,低电平使能接收。用 STM32 的另一个 GPIO 来控制这个方向引脚。
有一个经验教训:串口发送函数返回后,数据不一定已经全部发完了,因为串口外设还有移位寄存器在慢慢“吐”数据。如果发完立刻切回接收模式,发送缓冲区的最后几个字节会被截断,对端就会收到一帧残缺数据,CRC 永远过不去。正确做法是等发送完成标志位置位后再切方向,或者干脆延时几个字节的发送时间。
HAL_GPIO_WritePin(RS485_DIR_PORT, RS485_DIR_PIN, GPIO_PIN_SET); // 切换为发送 HAL_UART_Transmit(&huart2, (uint8_t *)tx_buf, tx_len, 100); // 发送 while (!(huart2.Instance->SR & UART_FLAG_TC)); // 等待发送完成 HAL_GPIO_WritePin(RS485_DIR_PORT, RS485_DIR_PIN, GPIO_PIN_RESET); // 切换回接收4.5 波特率选择和现场稳定性
波特率我选的是 9600bps,这是 Modbus RTU 现场最常见的速率,很多 PLC 串口默认也是 9600 或 19200。9600bps 在这个距离上最稳,虽然速度慢了点,但一帧报文只带 4 组温度数据,30ms 传完,完全够用。跑 115200 在实验室没问题,到了现场线缆一长、干扰一大,误码率立刻上来。
中控室的上位机软件要配置成一样的参数:9600、8 数据位、无校验、1 停止位(8N1)。Modbus RTU 协议自带 CRC,所以数据位校验其实可以不用,但 1 停止位是标准。
5. 工程化经验:滤波、诊断与常见问题排查
5.1 温度滤波:滑动平均 + 去极值
温度传感器读回来的原始值,不直接拿来用。工业现场存在各种瞬时干扰,可能导致单次读数跳变。我用了“五点去极值平均”策略:连续取 5 个温度值,去掉最大值和最小值,对剩下的 3 个求平均。这个算法计算量小,内存需求低,对脉冲型干扰的抑制效果很好。
要注意的是过滤波之后的温度响应会变慢。HVAC 温度本身变化就慢,管道温度在正常工况下每分钟变化不过零点几度,滤波引入的滞后时间完全可接受。但如果哪个系统要求实时性非常高,滤波窗口就要相应缩短,不要一刀切。
另外一个很容易被忽视的点:传感器本身的物理时间常数。PJ85718DM 这类传感器如果封装在防水探头里,套管和导热硅胶的存在会让温度响应变慢,读数的“惯性”可能长达数十秒。此时滤波算法算得再快也没用,物理层才是瓶颈。
5.2 软件诊断与故障状态
工程上不能只读“正常温度”,还得能识别“传感器坏了”。我在数据帧里为每个传感器预留一个状态字节,状态包括:
- 0x00:正常
- 0x01:传感器未应答(总线上找不到器件)
- 0x02:CRC 校验错误次数超限
- 0x03:温度超出合理量程(比如低于 -55°C 或高于 +125°C)
- 0x04:通信超时
上位机看到的不只是一堆温度值,还能快速定位是哪一路传感器出了问题。这个设计让现场调试效率高了很多。以前排查故障要拿万用表挨个量,现在上位机上直接能看到状态码。
5.3 调试中遇到过的那些坑
下面直接列一版“价值千元”的踩坑清单,每一条都是我实际遇到过并解决了的。
第一个坑是编译器优化导致时序错乱。前面讲过用 DWT 延时能规避,但也要检查 GPIO 初始化的时钟是否已使能。时序问题往往是“时好时坏”,冷启动正常、跑一会儿报错,大概率是延时不准或者中断把时序打断。单总线的时序操作期间必须关闭同级或高优先级中断,否则中断一来,读时序的采样点就错位了。
第二个坑是总线释放后电平不稳。如果上拉电阻缺失或虚焊,总线释放后是浮空的,读回来要么全 1 要么全是乱码。排查方法很简单:示波器量数据线,静止时应该稳定在高电平;如果不是,先查上拉电阻。
第三个坑是防水探头的导热问题。有些传感器装在金属套管里,里面填满了密封胶,外面还套了热缩管,结果测到的永远比实际温度滞后很多。解决办法是在探头和被测物之间加导热硅脂,或者用卡簧把探头压紧在管道表面。这个属于“软件调不好只能靠硬件”的典型。
第四个坑是 RS485 接线极性接反。A/B 两线接反以后,数据完全不通,但主机端不一定报“无响应”,更多是报 CRC 错误,因为干扰信号也能触发接收。排查时先量 485 接口的静态电平,A 线要比 B 线高一点点(约 200mV),反了就交换接线。
第五个坑是 485 方向切换时序。前面说过,发送完成后必须等 TC 标志位。没做这一步之前,设备偶发性不上报,查了很久才发现是最后一个字节丢失。
第六个坑是 485 终端电阻。我的系统里传感器节点在楼层配电间,主控在控制柜,超过 100 米后,如果总线上没有终端电阻,信号反射会导致波形过冲。我在主控端加了一个 120Ω 终端电阻,信号质量立刻改善。注意是只在总线两端加,不能每个节点都加。
第七个坑是电源地线。有人说“数字传感器就三根线,VCC 和 GND 拉过去就行”,但工程现场地电位差会让数据通信变得不可靠。我的做法是远程传感器的电源地和主控地之间采用单点接地,同时数据线上加 TVS,把共模尖峰钳位掉。
第八个坑是看门狗复位。采集数据时如果总线上传感器应答超时,驱动代码可能会陷入死循环等待,这时候如果开了看门狗,系统会被反复复位。处理方式是在所有等待循环里加超时计数,超过规定时间就退出并报错,绝对不做无期限的阻塞等待。
5.4 常见问题排查速查表
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 读回温度全部是 85°C | 传感器上电默认值,ROM 匹配失败或未完成转换 | 检查 ROM 地址、等待时间是否够 750ms |
| 读回温度都是 0°C | 数据线短路到地或时序读回全 0 | 量数据线电压,检查读时序采样点 |
| 温度值跳变 0.5°C 以上 | 干扰串入、滤波未开、电源不稳 | 检查数据线屏蔽接地、TVS 管、滤波算法 |
| CRC 错误但数据看似正常 | 数据线干扰、485 极性反、字节顺序错 | 用示波器看波形,核对 CRC 发送顺序 |
| 485 从不响应 | 地址不对、接线错误、波特率不一致 | 先确认地址,再量静态电平,逐项排除 |
| 数据偶尔丢一帧 | 方向切换过早、磁干扰、终端电阻缺失 | 等 TC 标志,检查 120Ω 终端电阻 |
| 温度响应极慢 | 探头套管导热不良、滤波窗口太大 | 改善导热硅脂接触,缩短滤波窗口 |
| 只有一颗能读、其余全失败 | 多颗传感器 ROM 未匹配/总线短路 | 单独挂传感器逐个读 ROM,确认地址列表 |
5.5 采集策略与主循环设计
温度采集不能全放在一个 while 循环里“读完一个再读一个”,因为 12 位转换要等 750ms,如果每个传感器都阻塞等待,4 颗传感器一个周期就要 3 秒多。
我的做法是做一个简单的状态机:主循环每一轮启动一颗传感器的温度转换命令,然后不去等它,继续做显示、通信等别的事;1 秒后再回来读结果、启动下一颗。这样 4 颗传感器分布在 4 个周期里完成,整体采集周期是 1 秒而不是 3 秒,实时性更好。
如果想更快,可以一次性启动所有传感器的转换,等待后再逐个读结果。但要注意,单总线同时转换的命令只在所有传感器共用一条总线且都支持广播命令时才好使。HVAC 这种多点场景,我更看重的是数据稳定,而不是毫秒级的速度。
另外,主控的定时器还要承担 Modbus 超时计时。标准 Modbus RTU 要求帧间间隔至少 3.5 个字符时间,超过这个间隔,接收方就认为是新帧开始。我用一个定时器做字符超时判断,收到第一个字节后启动计时,如果在规定时间内没有收到后续字节,就按一帧完整报文处理。波特率 9600bps 时,3.5 字符时间大约是 4ms,帧超时限制可以设 200ms,避免把两帧粘在一起解析。
6. 一些个人体会
做这个项目最大的感受是,单总线温度采集看似简单,真正放到 HVAC 现场,要考虑的问题一点都不少:时序要精确到微秒、多点寻址要规划好、远程通信要讲究物理层可靠性、光有精度还不够还得有故障诊断能力。PJ85718DM 把温度到数字信号的转换过程简化了,但剩下的工程问题,芯片本身帮不了你太多,得靠系统设计一个个去磨。
如果后续还要扩展,这个平台的潜力还是很大的。STM32F415ZG 的资源绰绰有余,可以往上加 PID 温控逻辑、报警联动、数据记录等功能;通信方面也能从 RS485 延伸到以太网,把数据通过网络上传到服务器做远程运维。不过底层的这套采集、滤波、诊断机制,大概率是不会变的。
最后说一个实用的小技巧:给每路传感器做编号贴纸,拨码地址、传感器物理位置、Modbus 寄存器地址三者一对一对齐,写进调试文档里。现场维护人员拿着一张表就能查问题,省下的沟通成本远超做这张表花的时间。