1. 项目概述与方案选型思考1.1 这个项目解决什么问题先交代下背景。前阵子接了个活儿要给某厂区的 HVAC 机房做一套温度监测改造。现场情况挺典型机房里有几台空调机组需要同时盯着进风温度和出风温度本地控制柜上要能看到实时数据运维办公室在隔壁楼也得能远程看到曲线和报警。如果全部人工拿测温枪去测一天跑好几趟既不及时也不现实。市面上现成的温控器、数据采集器不少但要么只支持本地显示要么远程方案要绑定厂商云平台后期还有年费。现场改造嘛讲究一个灵活可控。所以最后我决定自己基于 PJ85718DM 加 STM32F215RE 做一套双通道温度监测系统本地用屏幕实时显示远程通过以太网口把数据推到内网监控页面。这套方案做下来效果稳定成本可控而且后续想加通道、改报警逻辑都很方便。这套系统解决的核心痛点有三个双通道独立监测进风和出风温度分两路采集互不干扰数据独立上报。本地与远程同步可见本地屏幕显示实时值同时通过网络把数据送到远程终端两边数据一致。可裁剪、可扩展底层基于嵌入式方案想加湿度传感器、加继电器控制、改报警阈值都是在原有框架上做加法不用推翻重来。如果你也在做类似的嵌入式温度采集、HVAC 环境监测或者只是想学习数字温度传感器怎么接入 MCU、怎么走以太网远程上报数据这篇文章的内容应该能给你不少可以直接抄的作业。1.2 为什么选 PJ85718DM 做温度采集先说传感器侧。PJ85718DM 是一颗数字温度传感器我手上这颗是典型的 I2C 接口内部集成 12 位 ADC温度分辨率能到 0.0625°C测量范围覆盖 -55°C 到 125°C精度在 -10°C 到 85°C 范围内可以做到 ±0.5°C 以内。这几个参数放在 HVAC 场景里非常够用机房环境温度基本在 10°C 到 40°C 之间不会超出传感器的舒适区精度余量很充足。选数字温度传感器而不是 NTC 热敏电阻加 ADC 采集主要图三点省心免校准NTC 方案每路都要做分压电阻匹配和软件查表校准批量做的时候工作量很大。PJ85718DM 出厂前已经做过校准读出来的数据直接就是摄氏度省掉了最麻烦的标定环节。接口干净I2C 总线两根线搞定多路传感器可以挂同一条总线上按地址区分。对 PCB 布局和接线来说都是好事。抗干扰能力强数字信号传输不像模拟信号那样容易受电源纹波和走线串扰影响。机房里有变频空调、大功率风机电磁环境其实不算干净模拟信号方案在这个场景下是要吃亏的。PJ85718DM 的工作电压 2.7V 到 5.5V可以直接用 3.3V 供电和 STM32 的系统电压统一不用额外做电平转换。静态电流在微安级别就算以后要改成电池供电的低功耗版本这颗传感器的底子也扛得住。1.3 为什么选 STM32F215RE 做主控主控侧我选了 STM32F215RE。这颗芯片是 ARM Cortex-M3 内核主频最高 120MHzFlash 512KBSRAM 128KB。放在这个项目里性能有不少富余但富余不是坏事——后续想加图形界面、加 TCP 服务、加 JSON 解析库都有空间。选它的理由主要有几个硬件以太网 MACF2 系列内置了 10/100M 以太网 MAC 控制器只需要外挂一颗 PHY 芯片就能联网。相比用 SPI 接口的独立以太网控制器芯片电路更简洁软件栈也更顺畅。多路 I2C 和 UARTI2C 挂温度传感器UART 可以接调试串口、蓝牙模块、4G 模块接口资源充足。生态成熟HAL 库和标准外设库都很完善遇到问题网上资料一抓一大把开发周期能压得很短。如果你手头没有同款芯片其实这个方案移植性也很好换成 STM32F4 系列或者 GD32 系列管脚兼容的话基本可以直接搬就算换了别的 MCU只要带 I2C 和以太网 MAC整个架构思路都是一样的。2. 硬件设计与接口细节2.1 传感器与 MCU 的接线方式整个硬件链路其实很简单PJ85718DM 通过 I2C 总线接到 STM32F215RE以太网 PHY 芯片通过 RMII 接口接到 MCU本地显示用一块 I2C 接口的 OLED 屏幕。全部设备挂在同一条 I2C 总线上地址各不相同互不冲突。PJ85718DM 的引脚不多典型接法如下引脚功能接线说明VDD接 3.3V并加 100nF 去耦电容GND接系统地SDA接 STM32 的 PB7I2C1_SCL 对应的数据线需按实际映射确认SCL接 STM32 的 PB6I2C1_SCLA0/A1地址选择引脚接地或接 VDD 组合出不同地址这里有个容易踩的坑PJ85718DM 的 I2C 从机地址由硬件引脚决定7 位地址的高 4 位是固定的低 3 位看 A0/A1 的电平组合。如果不小心把两片传感器设成了同一个地址I2C 总线上就会冲突读回来的数据乱七八糟。所以设计时一定要先规划好每路传感器的地址分配。我在这套系统里用了两片 PJ85718DM一片测进风温度一片测出风温度。接线时把第一片的 A0/A1 都拉低第二片 A0 拉高、A1 拉低地址就错开了。OLED 屏幕的 I2C 地址通常是 0x3C和传感器不在一个范围不会冲突。STM32F215RE 的 I2C1 外设挂这三路设备完全够用。I2C 速率我配置成 400kHz 快速模式实测读写传感器和屏幕都非常稳定。理论上传感器能支持到 1MHz但 400kHz 在抗干扰方面更有余量长线传输的时候下降沿和上升沿也不容易变形。2.2 PCB 布局与抗干扰设计要点HVAC 现场最容易忽略的就是传感器线路的抗干扰。我把传感器小板和主控板分开设计传感器通过排线引出贴在风管表面或者挂到进风口附近这样传感器能真正测到风道里的温度而不是主板附近的温度。几个布局上的经验传感器尽量远离发热器件MCU、PHY 芯片、电源芯片都是发热源。如果把传感器贴在这些器件旁边读出来的温度会偏高好几度而且这个误差是动态的负载一变温度就漂很难校准。I2C 走线不要太长400kHz 下I2C 信号线超过 30cm 就有明显振铃波形会变得很难看。实际项目里传感器到主板的排线控制在 20cm 以内走线内部加了一根 GND 线做屏蔽实测非常稳定。电源去耦每颗 IC 的电源引脚旁边都要放 100nF 陶瓷电容电容尽量靠近引脚。这个习惯在低频电路里看不出差别但以太网 PHY 工作的时候会产生高频噪声如果去耦做不好I2C 读取偶发出错就是常态。PCB 设计的时候我把 PJ85718DM 的 A0/A1 地址选择引脚用 0Ω 电阻控制方便后期调整地址。量产阶段如果确认地址不再改动可以把 0Ω 电阻换成直接焊接的跳线省成本也省贴片位。3. 软件架构与驱动实现3.1 I2C 驱动与传感器寄存器操作软件部分我用的开发环境是 STM32CubeIDE基于 HAL 库开发。初始化 I2C 的代码很简单但有几个细节需要注意。I2C 初始化时我把时钟频率设成 400kHz上升时间设置为快速模式对应的参数。如果使用默认的 100kHz 标准模式读传感器问题也不大但刷新率会慢一些OLED 屏幕刷新也会有轻微卡顿。I2C_HandleTypeDef hi2c1; void I2C1_Init(void) { hi2c1.Instance I2C1; hi2c1.Init.ClockSpeed 400000; hi2c1.Init.DutyCycle I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 0; hi2c1.Init.AddressingMode I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 0; hi2c1.Init.GeneralCallMode I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(hi2c1) ! HAL_OK) { Error_Handler(); } }传感器读取温度的操作方式是先写入寄存器指针指向温度寄存器然后读取两个字节的数据。第一位是温度整数部分第二位是小数部分。需要注意PJ85718DM 的温度寄存器和很多类似的数字温度传感器一样数据是以 16 位补码形式存放的转换的时候还要考虑符号位。3.2 读取与温度值转换的完整流程温度数据的读取和转换成摄氏度是整个固件里比较核心的部分。我写了一个独立函数来干这件事逻辑清晰方便复用。float PJ85718DM_ReadTemperature(uint8_t devAddr) { uint8_t reg 0x00; // 温度寄存器地址 uint8_t buf[2]; int16_t raw; float temp; HAL_I2C_Master_Transmit(hi2c1, devAddr 1, reg, 1, 100); HAL_I2C_Master_Receive(hi2c1, devAddr 1, buf, 2, 100); raw (buf[0] 8) | buf[1]; if (raw 0x8000) { raw (int16_t)(raw | 0xFFFF0000); // 符号扩展 } temp raw * 0.0625f; // 12位精度下的LSB值 return temp; }代码里的0.0625f就是 12 位 ADC 的分辨率。传感器内部把温度转换成数字量每个 LSB 对应 0.0625°C。这个值其实就是 1/16所以也可以用位移来做整数运算但用 float 做乘法的性能开销在这个场景下完全可以忽略。实测下来传感器的转换时间典型值在 100ms 左右太频繁读取没有意义反而会增加 I2C 总线的负担。我的设计是每 500ms 轮询一次两路传感器这个刷新率对 HVAC 应用来说绰绰有余——风管温度本来就是个慢变量一秒更新两次足够直观了。3.3 多重采样与软件滤波处理数字温度传感器虽然比模拟方案稳定但在工业现场还是会受到干扰。尤其是压缩机启停的瞬间电源会有短暂的跌落可能让 I2C 读取出现偶发错误读出来的数据突然跳变到离谱的值。我加了两个层面的保护第一层滑动平均滤波。每次读取的结果存入环形缓冲区取最近 8 次采样的平均值作为显示值。这样即使某次读数有微小波动最终输出也不会跟着抖。第二层异常值剔除。如果某次读取的温度和上一次有效值的差超过 5°C直接丢弃这次数据不进入滤波缓冲区。5°C 这个阈值是参考 HVAC 场景的温变速率定的——风管温度不可能在 500ms 内跳动 5°C超过这个值基本可以确定是干扰或者通信错误。#define FILTER_SIZE 8 float filterBuf[FILTER_SIZE]; uint8_t filterIdx 0; uint8_t filterCnt 0; float Temperature_Filter(float newVal) { static float lastValid 25.0f; float sum 0.0f; if (fabsf(newVal - lastValid) 5.0f) { return lastValid; // 丢弃异常值 } lastValid newVal; filterBuf[filterIdx] newVal; filterIdx (filterIdx 1) % FILTER_SIZE; if (filterCnt FILTER_SIZE) { filterCnt; } for (uint8_t i 0; i filterCnt; i) { sum filterBuf[i]; } return sum / filterCnt; }这套滤波逻辑实测下来显示界面上的温度值非常平稳不再有小数点后两位来回跳的情况。但要注意滤波只适用于温度这种慢变量如果是采集振动、冲击这类快变量滑动平均会抹掉关键的瞬态特征那时候就得换别的算法了。3.4 主循环状态机设计整个固件的结构我设计成了简单的主循环状态机没有用实时操作系统。HVAC 应用里的任务基本都是周期性的用 RTOS 反而增加复杂度。主循环的流程如下状态 0系统初始化。初始化时钟、I2C、以太网、OLED然后建立 TCP 服务器。状态 1读取传感器数据。轮询两路 PJ85718DM执行滤波和异常剔除更新全局温度变量。状态 2刷新本地显示。把温度值格式化到 OLED 屏幕上同时更新状态图标。状态 3网络数据处理。检查 TCP 连接状态收到上位机请求时回传温度数据同时处理断线重连逻辑。循环回到状态 1。状态轮询的时间基准用HAL_GetTick()控制每个状态根据自己的节奏决定是否执行。比如传感器每 500ms 读一次OLED 每 1 秒刷新一次网络数据每 200ms 检查一次。这样各个功能块的节奏独立互不拖累。4. 本地监测与远程监测的实现细节4.1 本地显示OLED 实时数据面板本地监测我用的是一块 0.96 寸 I2C 接口的 OLED 屏幕分辨率 128x64。显示内容分两行第一行显示进风温度第二行显示出风温度。字体用的是 16x16 的 ASCII 字库屏幕上还能显示传感器状态——通信正常显示 OK异常显示 ERR。OLED 的驱动基于 SSD1306 控制器初始化时序和显存操作比较标准。有现成的驱动库可以直接移植但要注意一个坑SSD1306 的 I2C 地址是 0x3C很多库代码里写死的是 0x3D如果直接抄过来会一直调不通。我遇到这个问题后排查了半天最后用 I2C 扫描工具确认地址才定位到。OLED 显示的温度值保留一位小数比如25.3 C。裸奔的实时数据看着不够直观我还加了一条简易的柱状图——根据温度值映射像素高度一眼就能看出温度是偏高还是偏低。4.2 远程监测以太网上报方案远程部分用的是 STM32F215RE 内置的以太网 MAC 加外挂 PHY 芯片通过 TCP 协议把温度数据推送到上位机。上位机是一台 PC 上跑的简单监控界面监听固定端口收到数据后写入数据库并绘制曲线。以太网初始化这块我最开始用的是 ST 官方的 LwIP 移植包。LwIP 是开源的轻量级 TCP/IP 协议栈MCU 上跑完全没压力。配置好 IP、掩码、网关后MCU 就作为一个 TCP Server 监听 8080 端口。数据传输格式直接用了简单的 JSON 字符串{dev:hvac01,type:temp,ch1:24.8,ch2:28.1,alarm:0}上位机收到之后按 JSON 解析存库、绘图、判断报警。TCP 协议的好处是可靠不丢包而且内网环境下延迟很低基本实时。如果现场没有以太网环境也可以把 PHY 芯片换成 DM9000 或者直接用 UART 接 4G 模块传输层改成 MQTT 或者 HTTP POST整个架构的其余部分完全不用动。4.3 掉线检测与断线补偿逻辑远程监测最容易出问题的不是数据传输本身而是设备掉线后怎么恢复。我遇到过现场工人拔了网线忘了插回去的情况这时候设备端如果没有掉线检测机制TCP 连接挂着不释放等网络恢复后新的连接也建立不起来。解决方案是在 TCP Server 端加超时检测每次收到上位机的请求后记录时间戳如果超过 60 秒没有收到任何请求主动断开当前连接回到监听状态。这样即使客户端异常退出或者网络断开服务器也不会被无效连接占住。if ((HAL_GetTick() - lastRecvTick) 60000) { tcp_abort(pcb); // 超时断开 pcb NULL; tcp_listening start_tcp_server(); }上位机端也做了对应的自动重连逻辑监测软件每隔 5 秒尝试连接一次连不上就一直重试连上之后正常收数据。这套机制跑了大半年期间经历过几次交换机重启、网线松动恢复后系统都能自动回到正常监测状态不需要人工干预。4.4 传感器断线保护坏了传感器比网络断了更麻烦——网络断了能看出来传感器读不到数据了如果程序不处理显示界面会一直保留上一次的数值造成一种“温度正常”的错觉。我在读取函数里加了返回值校验如果 I2C 通信返回错误码或者连续读取 3 次都是同一个固定值传感器数据不可能任何时间都完全一致就判定传感器异常。异常状态下本地 OLED 显示 ERR远程数据包里带上alarm:1字段上位机弹报警提示。这样运维人员能第一时间知道去查传感器接线而不是看着假数据误判。5. 常见问题与排查技巧实录5.1 I2C 通信偶发失败问题测试阶段遇到过一个问题系统运行几小时后偶尔会出现一次传感器读取超时。排查过程挺曲折最初怀疑是传感器本身不稳定后来发现是 I2C 总线上挂了三颗设备两颗传感器加一块 OLED总线的上拉电阻阻值不够。每种 I2C 设备的手册里都会标注推荐的上拉电阻范围但很多人会忽略一个关键点总线上挂的设备越多等效上拉阻抗就越低。一两个设备时用 10kΩ 没问题挂三个设备后就需要降到 4.7kΩ。我把上拉电阻换成 4.7kΩ 之后再也没出现过超时。这里有个更省事的排查技巧如果 I2C 偶发异常用示波器抓 SCL/SDA 波形看高电平是否接近 VDD、上升沿是否陡峭。如果高电平只有 2V 左右或者上升沿很平缓基本就是上拉不足。5.2 温度读数漂移与校准手段还有一次发现进风温度比实际高了两度一开始以为是传感器坏了后来排查发现是传感器贴装位置的问题——我为了固定方便把传感器直接贴在了风管金属外壳外侧而风管外壁的温度本身就比气流温度高一些。解决方法是给传感器做了一个小支架让芯片悬空在风管内壁附近用导热硅胶固定接触面但不紧贴金属外壳。调整位置后再用一支校准过的水银温度计做对比测试误差在 ±0.3°C 之内。如果你在现场发现传感器读数固定偏大或者偏小可以在软件里做偏移校准把实测温差保存到 Flash 里每次读取后叠加偏移量。这种做法适合批量生产时的一致性校准单台设备的话还是建议从安装位置上解决问题。5.3 远程数据中断与排查顺序远程数据中断是最让人头疼的因为问题可能出在任何环节。我的排查顺序一般是先看设备端串口调试助手打印网络状态看 TCP 连接是否建立、是否被异常断开。再测网络链路用 PCping设备 IP能通说明链路正常不通就查网线、交换机、PHY 芯片配置。最后查上位机确认监听端口有没有被防火墙拦截、服务是否在运行。这套顺序能快速定位大多数问题。实际遇到比较多的是第三种情况——上位机电脑重启后防火墙拦截了端口监听或者监控软件服务没有设置为开机自启导致设备端一直重连不上。把防火墙入站规则放行对应端口问题就解决了。常见问题速查表现象可能原因排查方法两端传感器读数都一样I2C 地址冲突扫描总线地址检查 A0/A1 电平读数跳变幅度大电源纹波干扰检查去耦电容加软件滤波OLED 不显示I2C 地址不匹配确认 SSD1306 地址是 0x3CTCP 连接建立后几十秒断开超时检测误判增大超时时间或调整心跳频率远程偶尔丢一条数据缓冲区溢出增大 LwIP 内存池检查上位机接收速度6. 经验总结与后续扩展思路这套系统从硬件设计到软件调试前后大概用了两周时间。现在回想起来方案整体是简洁可靠的但也有些地方可以做得更好。硬件上当时为了赶工期传感器小板和主控板是分开设计的实际安装时排线在风管里走线还是比较纠结。如果重新做一版我会把传感器做成可插拔的探头形式线缆直接用屏蔽双绞线接口用航空插头拆装都方便抗干扰能力也更上一个台阶。软件上目前温度数据是定时主动上报的上位机收到后只做了展示和报警。后续可以加一个简单的存储功能把每天的温升曲线记录下来周末做个报表分析进风出风温差变化对空调机组的运行效率也有参考价值。另外PJ85718DM 本身还支持高低温报警寄存器可以设定超过阈值后自动拉高 ALERT 引脚。我之前因为主板设计时没有预留这个引脚的连接这部分功能没有用上。如果你在设计初期就打算做报警联动记得把 ALERT 引脚引到 MCU 的外部中断输入上软件上会省不少事。最后再分享一个体会嵌入式项目里“能用”和“好用”之间的差距往往就在这些细节里。温度传感器谁都会读但读得稳、传得可靠、断线能恢复、坏了能报警这才是一套监测系统真正值钱的地方。按这个标准去做哪怕用最基础的 MCU 和最普通的传感器也能做出比很多商业产品还靠谱的东西。
阅读完成 · 觉得有帮助?