news 2026/10/22 17:01:04

STM32F107VC单总线温度传感器多点监测设计与LwIP远程上报

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32F107VC单总线温度传感器多点监测设计与LwIP远程上报

搞过HVAC项目或者做过嵌入式环境监测的兄弟应该都有同感:温度测点又多又分散,回风口、送风管、室外新风、室内几个房间,每个点都拉一堆模拟量线回来,调试起来简直想骂人。最近我在做一个空调机组的温度监测改造,方案上选了PJ85718DM这颗单总线数字温度传感器,搭配STM32F107VC做主控,把本地显示和远程网络上报一次做完了。

这套组合解决的核心问题有两个:一个是就地侧,主控板旁边挂几个传感器,OLED直接把所有温度打出来,现场调试不用开电脑;另一个是远程侧,传感器通过一根双绞线分布在几十米外的风管和房间里,全部温度汇总到MCU后,再走以太网发给上位机。也就是说,本地温度和远程温度都纳入了同一套监测体系。

如果你是做嵌入式设备、楼宇自控或者暖通配套控制的,这篇文章可以直接当参考笔记用。我不打算只贴代码,而是把选型逻辑、硬件设计、单总线驱动、LwIP网络上报、调试现场踩过的坑从头到尾说透,项目里遇到同类需求可以直接抄作业。

1. 需求拆解与方案选型:为什么是单总线传感器加F107

1.1 HVAC场景下温度监测的真实需求

先说现场需求。暖通空调的温度监测点和普通消费电子不太一样,测点不但多,而且位置极其分散。一个典型的空调机组,回风温度传感器在机组回风口,送风温度在盘管后风道内,防冻开关旁边还要有一个低温保护测点,室外新风温度探头得拉到屋外,室内侧可能还分布在好几个房间。这些点离控制器的距离短则两三米,长则三五十米。

本地监测和远程监测是同时存在的需求。本地指设备机柜就地能看温度,远程指把温度送到楼宇中控或者值班室电脑上。以前的做法很传统:每个测点用一只NTC热敏电阻加一路模拟量输入,测温范围窄、非线性还要查表校准,最麻烦的是长距离传输时导线电阻会直接影响精度。后来改PT100加变送器,精度上去了,但调理电路和变送器成本也跟着上去了,一个点就是大几十块,十几个点成本就很可观。

对比之后,PJ85718DM这类单总线数字传感器优势很明显。温度值直接在传感器内部完成ADC转换,通过单总线协议以数字方式输出,全程不受线缆电阻和模拟干扰影响。一条总线上可以挂多个器件,因为每个器件出厂有唯一的ROM序列号。这样HVAC现场常见的多点分散测温和长线传输问题,一根双绞线就解决了,不用每个点都单独拉一堆模拟线。

1.2 器件选型逻辑:为什么不是普通单片机加模拟量处理

PJ85718DM属于单总线数字温度传感器这一类,工作电压范围覆盖3.0V到5.5V,测温范围覆盖常见HVAC场景的-55℃到+125℃,分辨率可以通过配置寄存器选择,默认精度在±0.5℃左右。这些参数对于机房、风管、室内环境监测完全是够用的。这里要提醒一句,不同厂商的单总线温度芯片在时序细节上多多少少有差异,拿到实物先对一下器件手册,我下面讲的代码逻辑是基于最常见的单总线协议来写的,只要你手头的PJ85718DM遵循同类协议,基本可以通用。

主控选STM32F107VC,最核心的原因就是它自带以太网MAC控制器。当时也纠结过用F103和F407,F103便宜但内置MAC都没有,要联网就必须外挂SPI转以太网芯片,多一颗芯片意味着多一份BOM成本,还要把SPI口和中断引脚占掉。F407性能过剩,用在温度采集这种低频场景有点浪费。F107VC这颗芯片是Cortex-M3内核,主频72MHz,内部有256KB Flash和64KB SRAM,带以太网MAC、CAN、USB OTG和多路串口。对于HVAC这类既要跑本地逻辑又要走网络协议的场景,它的定位就是刚好合适。

做HVAC设备还有一个现实问题:工业现场电源环境并不干净,变频压缩机启停、电磁阀动作都会带来干扰。F107的工作温度范围和抗干扰能力在同类MCU里属于比较稳的,这也是工业类产品选型时的一个重要考量。

1.3 整体架构:本地温度和远程温度是如何组织在一起的

项目里我把“本地”和“远程”拆成了两个维度,这样容易说清楚。

空间维度的远程,指传感器不在主控板上,而是通过长线分布在远端。我用两条独立的总线:第一条总线放本地传感器,挂在控制器的PCB端子座上,测机柜环境温度和箱体进风温度;第二条总线通过一个接插件引出,用一根屏蔽双绞线拉到几十米外的风道和房间里,挂上六到八个传感器。两条总线由MCU的两个不同GPIO引脚驱动,互不干扰,某一条总线被干扰时另一条还能正常工作。

信息维度的远程,指数据从设备端通过网络上传。F107内置以太网MAC,外接一颗PHY芯片就能跑LwIP协议栈,我在板子上实现了TCP Server,上位机通过网络调试工具或者自写的Python脚本发起连接,就能读取所有传感器的实时温度。相当于每个节点本身是一台小服务器,上位机随时可以拉数据。

整体数据流向是这样的:MCU轮询两条总线上的所有传感器,把温度值存到一个结构体数组里,OLED本地循环显示,同时TCP服务线程监听以太网端口,收到上位机的读取指令后把整个温度数组打包发送出去。本地显示和远程读取用的是同一份数据源,不需要额外同步。

2. 硬件搭建要点:总线、接口与外围电路

2.1 单总线传感器接入电路:上拉电阻不是随便选的

单总线传感器的电气接口非常简单,核心就是一根数据线DQ加上电源和地。数据线必须接一个上拉电阻到VCC,这是因为器件工作在开漏模式,没有总线主机拉高的时候,数据线要靠上拉电阻维持高电平。

上拉电阻的取值是第一个跳跃点。短距离、传感器少的时候,4.7kΩ是标准值,稳定可靠。但是HVAC现场动不动就是三五十米的长线,线缆分布电容和电阻都会影响信号上升沿。线越长,分布电容越大,上升沿就越缓,时序上就容易超时。我在远程那条总线上实测,30米双绞线配4.7k上拉,偶尔出现读不到应答的情况,换成2.2k上拉后问题就消失了,因为电阻变小,充电电流变大,上升沿变快,时序裕量被找回来了。

这里有个反直觉的坑:不要在总线上并太大的电容。很多人习惯在电源引脚旁边加个100nF退耦电容,这没错,但如果把这颗电容直接并到DQ线上,它会和上拉电阻形成RC延迟,让上升沿变得更慢,反而把时序搞坏。DQ线上的ESD保护或者滤波,建议只保留寄生电容级别,我一般不加额外的电容,靠屏蔽线的分布电容就够。

供电方式上,PJ85718DM支持外部供电和寄生供电两种模式。实际项目里我毫不犹豫选了外部供电,每个传感器单独接VDD和GND,DQ走数据。寄生供电看着省一根线,但在长线场景下问题非常多:传感器做温度转换时需要从DQ线上窃取电流,总线电压会被拉低,主机侧如果上拉能力不够强,轻则转换超时,重则直接导致复位失败。HVAC现场变频器一启动,电源波动本来就不小,别在这种地方省一根线。

线缆选择上,我用的屏蔽双绞线,屏蔽层单端接地。普通平行线我在调试中发现,附近有继电器吸合时偶尔会出现CRC校验错误,换屏蔽线后这类问题明显减少。

2.2 STM32F107VC最小系统与外置PHY芯片

STM32F107VC的最小系统部分属于常规操作,但还是有几个点值得说。MCU使用8MHz无源晶振,配合两个20pF到22pF的负载电容,通过PLL倍频到72MHz运行。注意晶振布局要尽量靠近MCU的OSC_IN和OSC_OUT引脚,负载电容的地要短而粗地回到MCU的GND引脚,这个细节直接影响主时钟的稳定性,以太网通信的时钟源又对稳定性敏感,不能马虎。

以太网部分,F107内置的MAC控制器不能直接接RJ45,外面必须配一颗以太网PHY芯片。接口模式我选了RMII,因为RMII相比MII少了一半引脚,而且信号速率固定,100Mbps模式下只需要50MHz的参考时钟。RMII的引线要求是等长处理,特别是TX_EN、TXD0、TXD1这些信号,长度差控制得越小越好,我用的是两层板,布线时尽量让这些信号走同一层且路径接近,实测通信稳定。

RMII参考时钟有几种来源:用外部50MHz有源晶振直供PHY、由PHY内部倍频后输出、或者由MCU的MCO引脚输出50MHz。我用的是外部50MHz无源晶振配合PHY内部的振荡电路,这样PHY和MAC能在同一时钟源下工作,省去时钟不同步的麻烦。上电后调试的第一步,一定要能正确读到PHY芯片的寄存器ID,不然后面所有网络调试都是白费力气。

RJ45我用了带网络变压器的集成座,内部有隔离变压器,这是以太网物理层的标配,不要省。隔离变压器的中心抽头要按PHY芯片手册要求接偏置电压,接法错了会出现能连接但无法通信的诡异问题。

2.3 本地显示与交互接口设计

本地显示选用了一块0.96英寸的I2C接口OLED,4个引脚就搞定,对于显示多个温度点完全够用。I2C地址一般是0x3C或0x3D,买到的模块不确定时可以在初始化时扫描一下地址,这个习惯能省不少排查时间。

按键交互设计了三键方案:一个模式切换键,用于在“本地点选”和“远端点选”画面之间切换;两个阈值调整键,用于调整本地报警上限和下限阈值。报警执行部分是一个有源蜂鸣器加一个双色LED,超上限报警时亮红灯,低于下限报警时亮黄灯,蜂鸣器通过三极管驱动,GPIO直接驱动蜂鸣器的电流不够,容易把引脚烧坏。蜂鸣器驱动引脚还要并联一个续流二极管,不然断电瞬间的反向电动势会打坏三极管。

GPIO分配可以给个参考,我直接列在下面的表里:

功能MCU引脚说明
本地总线DQPA0开漏输出,外接4.7k上拉
远程总线DQPA1开漏输出,外接2.2k上拉
OLED SDAPB7I2C数据线
OLED SCLPB6I2C时钟线
蜂鸣器PB0经三极管驱动
报警LEDPB1双色灯
模式键PA4内部上拉
阈值加/减键PA5、PA6内部上拉
ETH RMIIPD0-PD5F107专用引脚
ETH MDIO/MDCPA2、PC1PHY管理接口

按键全部使用内部上拉,外部不用再放上拉电阻,省一点BOM。OLED和蜂鸣器都是3.3V供电,与MCU电平一致,不需要电平转换。

3. 软件驱动与通信协议实现

3.1 用GPIO模拟单总线时序:关中断是必须的

单总线协议的基石就是精确的时序。整个通信过程是一系列特定时间长度的电平跳变,对HAL库这种经过多层封装的函数来说,延时精度太差,必须用寄存器级别操作加空循环延时来实现。

先定义总线结构体,这样两条总线可以复用同一套驱动代码:

typedef struct { GPIO_TypeDef *port; uint16_t pin; } ow_bus_t; #define OW_BUS_LOCAL {GPIOA, GPIO_PIN_0} #define OW_BUS_REMOTE {GPIOA, GPIO_PIN_1}

GPIO配置成开漏输出模式。开漏模式下写0就是把引脚拉低,写1就是把引脚释放,由外部上拉电阻拉高,完美契合单总线协议的电平要求。

复位时序是整个通信的起点:主机拉低总线至少480us,然后释放,等待传感器回应。传感器上电后会主动拉低总线60us到240us作为存在脉冲。代码实现:

uint8_t ow_reset(ow_bus_t *bus) { uint8_t presence = 0; __disable_irq(); /* 拉低总线 520us */ GPIO_ResetBits(bus->port, bus->pin); delay_us(520); /* 释放总线 */ GPIO_SetBits(bus->port, bus->pin); delay_us(40); /* 读取存在脉冲 */ presence = !GPIO_ReadInputDataBit(bus->port, bus->pin); __enable_irq(); delay_us(200); return presence; }

读写一位时序有严格区分。写0时隙和写1时隙都是60us到120us,区别在于低电平持续时间。写0要求整个时隙都保持低电平;写1则是先拉低1到15us,然后释放总线让上拉电阻拉高。读时隙稍微复杂一点,主机先拉低1到6us,然后释放,在释放后的15us窗口内读取引脚电平,因为传感器如果返回0,会在这段时间内把总线拉低。

uint8_t ow_read_bit(ow_bus_t *bus) { uint8_t bit = 0; __disable_irq(); GPIO_ResetBits(bus->port, bus->pin); delay_us(5); GPIO_SetBits(bus->port, bus->pin); delay_us(9); bit = GPIO_ReadInputDataBit(bus->port, bus->pin); __enable_irq(); delay_us(60); return bit; }

我刻意在时序操作前后调用__disable_irq()关闭全局中断,这是非常重要的一步。如果不关中断,延时过程中一旦有定时器中断或者串口中断插入,时序就会超时,单总线通信当场失败。这也是为什么我不用HAL_Delay,HAL延时依赖系统滴答定时器,但滴答定时器中断本身就会打乱时序。

3.2 多传感器ROM枚举与温度数据读取

单总线传感器每个器件在出厂时都有一个64位的唯一ROM序列号,这个设计让多个传感器可以在同一条总线上共存。读取流程分两条路线:

如果一条总线上只挂一个传感器,主机可以发跳过ROM指令(0xCC),直接进入温度转换或者读取暂存器操作,简单快速。但我要的是多点采集,所以必须先把总线上所有传感器的ROM码读出来,存到数组里,后续通信用匹配ROM指令(0x55)逐个指定访问。

ROM搜索算法是单总线协议最经典的一段逻辑,思路是逐位读取并记录分支:先读第一位两次,如果两次读到的值不同,说明当前总线上只有一个器件在该位是0或1,可以确定方向;如果两次都读到0,说明有分叉,需要记录选择路径。这个算法说起来简单,但在位级别上做回溯还是容易绕晕,我实现时把搜索过程放在了温度采集初始化阶段,设备上电后执行一次,之后传感器位置固定,ROM码不会变,直接缓存使用。

读取温度的核心流程是这样的:

  1. 复位总线
  2. 发送匹配ROM指令(0x55),然后发送该传感器的64位ROM码
  3. 发送温度转换指令(0x44)
  4. 等待转换完成,12位分辨率下典型转换时间在数百毫秒量级,我配置成12位模式后等待了约800ms
  5. 再次复位总线,发送匹配ROM指令
  6. 发送读暂存器指令(0xBE),连续读取9个字节

完整读取一个传感器的关键代码:

int16_t ow_read_temperature(ow_bus_t *bus, uint64_t rom) { uint8_t data[9]; uint8_t crc = 0; int16_t raw = 0; if (!ow_reset(bus)) return TEMP_READ_ERR; ow_write_byte(bus, 0x55); /* 匹配ROM */ for (int i = 0; i < 8; i++) ow_write_byte(bus, (uint8_t)(rom >> (i * 8))); ow_write_byte(bus, 0x44); /* 启动温度转换 */ delay_ms(800); if (!ow_reset(bus)) return TEMP_READ_ERR; ow_write_byte(bus, 0x55); for (int i = 0; i < 8; i++) ow_write_byte(bus, (uint8_t)(rom >> (i * 8))); ow_write_byte(bus, 0xBE); /* 读暂存器 */ for (int i = 0; i < 9; i++) data[i] = ow_read_byte(bus); crc = ow_crc8(data, 8); if (crc != data[8]) return TEMP_READ_ERR; raw = (data[1] << 8) | data[0]; return (int16_t)raw; }

CRC校验必须做。单总线传感器返回的9个字节中,最后一个字节是前8字节的CRC8校验值,多项式是X^8+X^5+X^4+1。在长线传输和高频干扰环境下,CRC偶尔会报错,程序里对返回错误的情况做一次重试,重试三次仍失败就丢弃该测点本次数据并做故障标记,上层逻辑就不会把错误温度显示出来了。

3.3 本地数据处理:滤波、报警与OLED显示

直接从传感器读到的温度虽然经过了CRC校验,但还是偶尔会有毛刺,尤其是电机启停的瞬间。我在显示和上报之前加了一道滤波,方案是中值滤波加滑动平均。

中值滤波的做法是连续读取5次温度值,取中间的第三个值作为有效值。这个方法对付单点尖峰特别有效,因为哪怕五次里有一两次读到异常值,排序后异常值都会被排在两端,不会进入最终结果。滑动平均则是在中值滤波的基础上再做一次加权平均,让曲线更平滑,避免画面上的温度跳变太快。

滤波的代码如下:

float temp_filtered(float new_value) { static float buffer[5]; static uint8_t idx = 0; float temp[5], sum = 0; buffer[idx] = new_value; idx = (idx + 1) % 5; for (int i = 0; i < 5; i++) temp[i] = buffer[i]; /* 简单冒泡排序,取中值 */ for (int i = 0; i < 5; i++) for (int j = i + 1; j < 5; j++) if (temp[j] < temp[i]) { float t = temp[i]; temp[i] = temp[j]; temp[j] = t; } for (int i = 1; i < 4; i++) sum += temp[i]; return sum / 3.0f; }

浮点运算是有点浪费MCU资源,但这个场景下72MHz的Cortex-M3跑起来毫无压力,而且温度采集频率不高,不用过度优化。

本地报警逻辑放在滤波之后。系统每个采样周期把当前温度与预设阈值比较,超上限时置位报警标志,OLED画面温度数字变红,蜂鸣器以2Hz频率鸣响,直到温度回落并进入回差区间才解除报警。回差很重要,没有回差的话,温度在阈值附近波动会导致报警频繁通断,现场听起来非常烦人。

OLED驱动部分要注意,0.96寸OLED一屏最多能显示多少个字符要提前规划好。我的界面是这样布局的:第一行显示“LOCAL”加上本地温度,第二行显示远端总线上前三个测点温度,如果远端超过三个点,通过按键切换到下一页。显示格式固定为xx.x℃,避免浮点转字符串时占用过多时间。

3.4 基于LwIP的以太网远程温度上报

STM32F107VC移植LwIP协议栈,用无操作系统的RAW API就可以跑起来。F107有64KB SRAM,跑一个TCP Server绰绰有余,但LwIP的配置还是要裁剪一下:TCP窗口不要开太大,PBUF池数量和大小按实际负载设置,我用的是4个TCP连接上限,每个连接的接收窗口控制在1460字节,内存开销非常可控。

移植LwIP时需要把底层接口对接好:F107的以太网MAC驱动提供发送和接收函数,PHY的状态查询通过MDIO/MDC管理接口完成。我在初始化时做了PHY地址匹配,从F107的以太网寄存器里读到PHY ID后,与硬件实际配置比对,确认链路协商到的速率。

TCP Server的初始化流程如下:

static struct tcp_pcb *server_pcb; static err_t server_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { char *cmd; if (err == ERR_OK && p != NULL) { cmd = (char *)p->payload; if (strncmp(cmd, "READ_ALL", 8) == 0) { char reply[256]; int len = snprintf(reply, sizeof(reply), "TEMP: %.2f, %.2f, %.2f, %.2f, %.2f\r\n", temp[0], temp[1], temp[2], temp[3], temp[4]); tcp_write(pcb, reply, len, TCP_WRITE_FLAG_COPY); } pbuf_free(p); tcp_recved(pcb, p->len); } return ERR_OK; } static err_t server_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { tcp_recv(newpcb, server_recv); return ERR_OK; } void ethernet_tcp_server_init(void) { server_pcb = tcp_new(); tcp_bind(server_pcb, IP_ADDR_ANY, 9090); server_pcb = tcp_listen(server_pcb); tcp_accept(server_pcb, server_accept); }

主循环里每隔10ms调用一次tcp_tmr(),这个函数驱动LwIP的TCP定时器,不调用的话TCP连接状态机不会自动超时重传,连接会挂在半开状态。我在实际调试中还发现一个问题:上位机断电或者程序退出时,TCP连接不会干净地关闭,板子这边如果不处理,就会出现旧连接占用PCB资源的情况。解决办法是在accept回调里对同一个客户端的重复连接做清理,或者依靠LwIP的TCP_KEEPALIVE选项自动探测死连接。

3.5 通信帧格式与上位机脚本

TCP上报的协议我设计得比较简单,因为自用为主,不需要复杂方案。客户端发送一个ASCII命令,服务器返回一帧数据,数据帧格式如下:

字段长度说明
帧头1字节0xAA
传感器数1字节0x01-0x10
温度区N×2字节每个温度用int16,放大100倍,单位0.01℃
CRC81字节对前面所有字节计算

温度用int16放大100倍传输,而不是直接用float,这是网络传输的常规操作。float在跨平台通信中有字节序和表示格式差异的问题,int16没有这个问题,固定按小端序传输即可。上位机只需要做一次除法就能还原成摄氏温度。

为了远程监控调试方便,我写了一个简单的Python上位机脚本:

import socket import struct s = socket.create_connection(("192.168.1.233", 9090), timeout=5) s.sendall(b"READ_ALL") header = s.recv(1) if header == b"\xaa": count = s.recv(1)[0] payload = s.recv(count * 2 + 1) temps = [struct.unpack("<h", payload[i:i+2])[0] / 100.0 for i in range(0, count * 2, 2)] print("本地温度: %.2f℃" % temps[0]) print("远程温度: " + ", ".join("%.2f℃" % t for t in temps[1:]))

命令设计为READ_ALL和READ_ONLY两个指令,实际操作中还可以扩展SET_THRESHOLD指令,让上位机直接改写报警阈值,省去现场按键操作。通信连接方式用TCP,主要考虑HVAC监控室上位机和设备之间可能跨交换机,TCP有重传机制,比UDP可靠得多。

4. 完整联调过程与关键参数记录

4.1 分级联调:从点灯到全系统打通

整个系统不是一次性上电就通的,我习惯严格遵守从小到大的联调路径。第一级是电源和最小系统,上电后先用万用表确认3.3V输出正常,然后用一个LED点灯程序验证MCU核心和晶振工作正常。

第二级调试单总线部分。先用一根很短的杜邦线接一个传感器,用串口打印复位应答和ROM码。这个阶段最容易暴露的问题是GPIO配置错误,比如忘记配置成开漏模式,或者上拉电阻没有焊接,表现就是复位永远不成功。把第一个传感器读通之后再往总线上挂第二个、第三个,逐步增加节点数,观察搜索到的ROM码数量是否与实际一致。

第三级调试OLED显示。等到总线上的温度数据能稳定读到了,再驱动OLED显示,检查是否有花屏、地址不对、字库缺字等问题。OLED地址错误时屏幕完全不亮或者全亮,这个很好判断。

第四级调试以太网。先用网线连接路由器和开发板,通过串口打印DHCP分配到的IP地址,然后在PC上ping一下,通了再跑TCP Server,用Python脚本连接测试。这个阶段我踩过最大的坑是RMII时钟问题导致PHY无法协商,后面单独讲。

第五级接入真实的HVAC试点环境。把远程总线的传感器分别放到回风口、送风管、室外新风处,本地传感器留在控制机柜,开启空调运行,观察温度变化趋势是否合理。送风温度在制冷模式下应该明显低于回风温度,室外温度如果比室内高或者低都取决于季节,这些规律能帮我快速判断传感器是否安装正确。

4.2 关键参数与配置记录

整理一份项目参数记录,方便复现时对照:

参数项配置值备注
MCU主频72MHz8MHz晶振×9倍频
本地总线上拉4.7kΩ短线短距离
远程总线上拉2.2kΩ30米双绞线实测
传感器数量本地2个,远程6个最多可扩到8个每路
温度分辨率12位转换时间约800ms
采样周期1秒轮询一遍所有测点
滤波策略中值+滑动平均5次取中值再平均
以太网接口RMIIPHY外置
TCP端口9090服务端监听
静态IP192.168.1.233避免DHCP抖动
报警回差1℃防止阈值反复触发

远程总线长度超过30米时,2.2k上拉还能不能稳,取决于线缆质量和现场干扰强度,建议先用示波器看一下上升沿和下降沿,上升沿时间控制在1us以内比较保险。

4.3 实测数据:本地和远程到底准不准

联调完成后,我把所有测点跑了一天,对比水银温度计的数据如下:

测点PJ85718DM读数水银参照偏差
本地机柜26.4℃26.1℃+0.3
本地进风24.9℃25.0℃-0.1
远程回风27.2℃27.0℃+0.2
远程送风15.8℃15.9℃-0.1
远程室外18.3℃18.1℃+0.2
远程房间25.6℃25.5℃+0.1

从数据看,最大偏差在0.3℃以内,对于HVAC环境监测完全够用。上位机通过TCP读取到的数据与OLED本地显示一致,两者来自同一份内存数据,不存在二次采集差异。网络读取延时在局域网内基本可以忽略,每秒刷新一次完全没压力。

连续24小时运行时,远程总线出现过几次CRC错误,但重试机制都自动恢复了,没有丢点数。调试中还发现一个现象:送风温度测点在制冷刚启动时,读数会先掉到很低再回升,这是传感器贴在风管壁上的热惯性导致的,不是硬件问题,属于正常现场现象。

5. 常见故障与排查技巧实录

5.1 总线上读不到任何设备

这是初次上电最常遇到的问题。排查顺序坚决固定,不要跳步。

第一步用万用表量总线上三个引脚的电平,DQ应该是高电平,如果DQ被拉低到地,说明总线上有传感器短路或者接线错误,这时候复位永远读不到应答。第二步检查上拉电阻是否焊接,没焊上拉的话DQ悬空,电平不确定,也会有诡异表现。第三步用示波器观察复位波形,看是否存在480us以上的低电平脉冲,以及低电平释放后是否有应答脉冲。如果示波器看到主机复位脉冲但没看到应答脉冲,把传感器在断电状态下重新插拔一次,排除接触不良。

远程总线上的设备排查还有个技巧:把总线上的传感器从远端逐段断开,从靠近主控的一端开始试,每断一段就扫一次总线,很快就能定位到故障节点。千万不要在总线上挂着一堆设备的时候做替换测试,那样很难区分是哪个节点把总线拖死的。

常见问题整理:

现象可能原因处理办法
复位无应答DQ接反或短路量电平,查接线
复位无应答上拉电阻缺失补焊4.7k或2.2k
应答不稳定线缆过长干扰大换屏蔽线或降上拉电阻
只识别到部分传感器ROM搜索中止关中断时间过长,查延时函数
读温度全为85℃上电后未等待转换完成转换指令后等足时间

85℃这个现象特别说一下,这是单总线传感器的上电复位默认值。如果你读到85℃且所有点都一样,说明程序在温度转换还没完成时就去读暂存器了,读到了初始化后的原始数据。解决办法就是等足转换时间再读,别省这几百毫秒。

5.2 温度读数乱跳或明显不合理

读数和实际温度差好几度,或者数值一直在跳,这个问题的根源多半不在传感器本身,而在电源和安装。

供电不稳是最常见的元凶。传感器是数字器件,对电源质量仍然敏感,供电电压纹波太大会导致内部ADC参考电压抖动,读数自然不准。我的对策是所有传感器的VDD和GND在远端统一并联一个100nF电容,这个电容不能放在DQ线上,只能放在电源引脚上。其次传感器不要和继电器、接触器共用一个电源回路,MCU用一路隔离电源,总线传感器用另一路,中间用DC-DC隔离或者至少用地线分开走。

安装位置也是一个大坑。传感器直接贴在金属风管壁上,温度反映的是管壁温度而不是空气温度,和真实空气温度差好几度。正确的做法是让传感器探头伸进风管内约10到20cm,悬在气流中,不要碰管壁。室外测点要加防辐射罩,避免阳光直射导致读数偏高。空调传感器、水管温度计其实都有类似问题,安装方式对测量精度的影响常常比传感器本身的精度误差还大。

软件上如果确认硬件没问题,滤波参数也要重新审视。中值滤波的窗口取5次的话,如果总线上有传感器连续两次读取失败,重试期间插入了旧值,会导致转折处的毛刺,这种情况下改成时间序列判断更合理:如果新值比上一次值高出超过8℃,且持续不到两个采样周期,直接判定为无效数据丢弃。

5.3 以太网连接不上或频繁断开

TCP连接不上的排查,我的顺序是先物理层,再网络层,最后应用层。

物理层的第一步是读PHY的寄存器。F107初始化后如果能正确读出PHY ID和链接状态寄存器,说明RMII接口和时钟没问题。如果PHY寄存器读出来全是0xFF,物理层就没通,重点检查RMII时钟和PHY地址配置。第二步看RJ45指示灯,通常Link灯亮代表物理链路已经协商成功。

网络层就是ping。如果PC能ping通板子的IP,但TCP连不上,多半是TCP Server没有正常启动或者监听端口不对。应用层问题则集中在LwIP的tcp_tmr没调用、accept回调里没调用tcp_recv、接收缓存区太小导致数据丢失这几个地方。

还有个细节:上位机的TCP连接在数据读取后要主动调用recv清空数据,否则服务端pcb的接收窗口会慢慢填满,连接看起来是通的,但数据发不出去。这个问题在长连接、高频读取的场景下特别容易出现。

现象可能原因处理办法
PHY寄存器读不到RMII时钟未配置检查50MHz时钟源
能ping通但连不上TCP端口被防火墙拦截检查PC防火墙或换端口
TCP连上后收不到数据recv回调未注册注册tcp_recv并处理pbuf
连接频繁断开LwIP定时器未驱动主循环调用tcp_tmr
上报数据字节错位帧格式解析错误用调试助手逐字节核对

5.4 远程总线长线部署的专项问题

远程总线用于HVAC现场时,最大的敌人是两个:线缆压降和电磁干扰。

线缆压降影响的是传感器供电。远程传感器到主控板的距离超过30米时,如果VDD线径太细,传感器转换期间的大电流会在导线上产生明显压降,导致传感器供电电压低于最低工作电压,表现就是远程节点间歇性丢失。解决方法是加大供电线径,或者直接采用24V供电再在每个传感器附近用LDO降到3.3V。第二个方案在工业现场更常见,因为24V是标配,而且压降远小于3.3V供电场景。

电磁干扰对单总线的影响主要是上升沿被拉缓或者被毛刺打断。应对方法是总线使用屏蔽双绞线,屏蔽层单端接地;如果干扰非常大,可以在总线末端加一个约100Ω的阻尼电阻到地,这能在不破坏时序的前提下抑制振铃。我在一个变频器功率很大的试验间里试过,加阻尼电阻后CRC错误率显著下降。

最后是节点数限制。单总线的理论挂载数量上限有几十个,但实际长线部署时,每增加一个节点,总线上寄生电容就大一点,时序裕量就少一点,可靠性会逐步下降。一般建议每条总线控制在8到10个以内,确实有更多测点就分两路总线。不要贪多,出问题时排查成本比多挂几个传感器高得多。

结尾

这套本地加远程温度监测方案,我在实际项目里用了很长时间,过程中最大的感悟是:温度采集本身不复杂,复杂的反而是总线的物理层处理和现场的干扰防护。如果你只是把一堆传感器接上然后读数据,嵌入式本身就能跑通;但要把这些数据稳定地用在HVAC控制上,就得把上拉电阻、屏蔽布线、供电隔离这些基础细节做扎实,这些功夫不显眼,却是整套系统可靠性的真正保障。

最后再分享一个小技巧:如果你也遇到温度读数在某个时刻统一跳变的问题,别急着怀疑传感器,先看看是不是主控板上的ADC那条高精度参考电压被电磁干扰拉偏了,或者看看传感器电源上是不是有间歇性的高电平毛刺。我后来在总线传感器供电线上加了一个共模电感,然后再也没出现过这个现象。希望这篇笔记能帮你少踩几个坑,省下的调试时间拿去喝茶都是好的。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 16:57:20

【SLAM】ORB-SLAM2的源码阅读(七):KeyFrame类

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/22 16:56:16

AI日报制作方法论:信息筛选、结构化记录与长期维护实践

1. 一份“AI 日报”到底在记录什么每天早上九点&#xff0c;我习惯先花二十分钟把过去二十四小时里跟人工智能相关的动态过一遍。这个动作坚持了快两年&#xff0c;慢慢就形成了一份固定格式的“AI 日报”。很多人以为日报就是新闻搬运&#xff0c;把标题复制粘贴、配个链接就完…

作者头像 李华
网站建设 2026/10/22 16:55:29

AI Agent框架选型:OpenClaw vs Hermes Agent实战对比与避坑指南

2026 年聊 AI Agent 框架&#xff0c;已经过了“能跑通一个 Demo 就了不起”的阶段。现在大家问的问题通常变成&#xff1a;我想让 Agent 稳定干活、能接业务系统、团队里不同水平的人都能维护&#xff0c;应该选哪个底座&#xff1f;过去半年&#xff0c;OpenClaw 和 Hermes A…

作者头像 李华
网站建设 2026/10/22 16:54:35

十大AI论文辅助工具实测:从检索到答辩的避坑指南

又到了毕业论文冲刺季。跟往年不太一样的是&#xff0c;2025届这批毕业生手里几乎人人都握着一两个AI工具&#xff0c;但真正能把它们用到正地方的&#xff0c;其实很少。我见过太多人把“让AI写一段”当成万能解法&#xff0c;结果论文里满是空话套话&#xff0c;导师看一眼就…

作者头像 李华
网站建设 2026/10/22 16:54:33

模具设计介绍不是PPT,而是可验证的技术资产

简介&#xff1a;本资源是一份面向机械设计工程师、模具制造从业者及高校相关专业学生的《模具设计介绍》技术培训课件&#xff0c;聚焦Creo Parametric平台下的全流程模具开发实践。内容系统覆盖数据检查&#xff08;IGES/STEP等多格式导入与自动修复&#xff09;、模仁设计&a…

作者头像 李华
网站建设 2026/10/22 16:53:42

考研数学一概率统计核心考点、解题套路与复习规划

考研数学一的概率论与数理统计&#xff0c;在我的印象里一直是三块内容里最矛盾的存在。论分值&#xff0c;150分里它占33分上下&#xff0c;不算少&#xff1b;论知识点&#xff0c;它的公式密度和学习曲线比高等数学温和得多。但每年对完答案&#xff0c;翻车最惨烈的偏偏就是…

作者头像 李华