在嵌入式圈子里待久了,总会遇到一些“旧板子干新活”的典型需求。这次的主角是 W55MH32-ADK,一块基于老牌 8051 内核的以太网微控制器评估套件,而任务则是用它搭一套室内/室外环境监测系统,把温度、湿度、气压、光照等数据采集起来,既能本地显示,也能通过以太网在浏览器上远程查看。
放在今天,很多人第一反应是用 ESP32 或树莓派,但退一步看,这类自带以太网 PHY 的 8051 平台其实非常适合做固定式环境监测。它的功耗低、接口齐全、工业生命周期长,而且 ADK 板卡已经把所有外围电路都做好了,真正要关注的是传感器选型、通讯拓扑和固件架构。这篇文章就把我在这个项目上的完整思路、硬件连接、软件实现和踩坑记录整理出来,供正在评估这个平台或者打算做类似网关型监测设备的朋友参考。
这个项目适合三类人:一是手里正好有 W55MH32-ADK 开发板、想验证平台能力的嵌入式工程师,二是做机房、库房、温室等场景环境监控方案的开发者,三是想了解老式 8051 平台如何对接现代传感器网络的学生。前后端和上位机都被我刻意保持在“够用就好”的复杂度,重心放在可靠性和扩展性上。
1. 项目整体设计与方案选型
1.1 核心需求拆解
整个项目看起来是“一个室内/室外气象站”,但拆开来看,实际需求至少要覆盖四块:数据采集、数据传输、本地交互和远程访问。
其中数据采集分两个位置:室内节点采集温度、湿度、气压,室外节点采集温度、湿度、光照、降雨状态。两个节点距离通常在几米到几十米,视安装环境而定。数据传输指的是从室外传感器到主机(W55MH32-ADK)这一段,主机本身内置以太网,所以远程访问直接走 TCP/IP 协议栈就行,不需要额外的模块。本地交互则包括一块小型 LCD 屏显示实时数据,加上几个按键做页面切换。远程访问则是在板卡上跑一个微型 Web 服务,浏览器直接访问板卡 IP,看到曲线和实时表格。
W55MH32-ADK 的板载资源是足够支撑这些需求的。它带了 GPIO、UART、I2C 等常规外设,关键是内置了以太网 MAC/PHY,RJ45 接口直接焊在板上,省去了外挂网络芯片的麻烦。8051 内核的主频不算高,但跑一个轻量 TCP/IP 栈和 Web 服务完全没有问题,关键在于不要给它安排过于复杂的任务。
1.2 通讯拓扑的取舍
我最初的方案是用 2.4G 无线模块(比如 nRF24L01)把室外数据传回主机,这样布线最省事。但在做现场评估时发现一个很现实的问题:室外传感器通常安装在屋檐下或设备机柜外侧,中间可能隔着砖墙、金属面板甚至多组密集的线槽,2.4G 信号在穿透水泥墙和金属结构时衰减非常严重,偶尔还会被环境中的 WiFi 信号干扰。对于稳定性排第一的监测类设备,无线方案的首包成功率一旦达不到 99%,整个数据链路维护成本就上去了。
退而求其次,我选择了 RS485 有线总线。室外传感器通过一根双绞线连接到主机的 UART,RS485 是差分信号,在几十米距离内抗干扰能力很强,而且支持多节点级联,以后要增加雨量计、风速传感器时,在同一条总线上挂载即可,不需要改主机的物理接口。室内传感器则直接用 I2C 总线连接,距离短,也不需要额外的收发芯片。这种“室内 I2C + 室外 RS485”的双通道设计,让主机和传感器的耦合度降到最低,调试时也更容易隔离问题。
1.3 平台选择背后的逻辑
选择 W55MH32-ADK 而不是直接用 STM32,可能有人会觉得奇怪。我的考虑其实很简单:这块 ADK 把电源、复位、调试接口、以太网和引出的 GPIO 全部标准化了,拿来就能焊线跑程序,适合快速原型验证。同时 8051 内核的指令周期非常确定,对时序敏感的外设(比如温湿度传感器)来说,反而比某些带缓存和预取流水线的 ARM 内核更容易把控时序,只要用定时器中断严格分时调度就行。
还有就是可维护性。这类平台在工业自动化领域仍然有大量存量设备,很多现场设备都挂接在基于 8051 的控制器上,用同样的平台做监测终端,意味着工程师可以用同一套 Keil 环境、同一套代码风格维护整个系统,不需要引入新的工具链和新的 RTOS 习惯。这个项目本质上是一次“旧平台再利用”的验证,结果证明这条路是完全走得通的。
2. 硬件连接与传感器选型细节
2.1 室内传感器的选材与接线
室内部分我用了两颗传感器:一颗是 SHT30 数字温湿度传感器,I2C 接口,一颗是 BMP280 气压传感器,同样是 I2C 接口。选择数字传感器而不是模拟传感电阻,主要原因是 ADK 板上的 ADC 通道数量有限,而且模拟信号在长距离走线上容易引入温漂和噪声,数字传感器输出的直接就是校准后的物理值,省去了一堆标定工作。
接线方式上,SHT30 的 SDA 和 SCL 分别接在 ADK 的 P1.0 和 P1.1,这是硬件 I2C 引脚,BMP280 则挂载在同一条 I2C 总线上,通过器件地址区分。SHT30 的默认地址是 0x44,BMP280 是 0x76,两者没有冲突。需要注意的是 SHT30 和 BMP280 都需要外部上拉电阻,ADK 的 I2C 引脚内部虽然有弱上拉,但那种上拉强度只适合极短距离的板级通信。我在传感器模组上加装了 4.7k 欧姆的外部上拉,实测波形上升沿明显变陡,通信稳定性好了很多。
供电方面,室内节点直接从 ADK 的 3.3V 电源轨取电,SHT30 的工作电流只有 0.2mA 左右,BMP280 电流约 1.2mA,功耗完全可以忽略。这里有一点很多人容易踩坑:SHT30 数据手册标明其供电电压范围是 2.4V 到 5.5V,但 I2C 逻辑电平是跟 VDD 关联的,如果 VDD 接 5V,I2C 引脚的高电平范围就会超过 ADK 的 3.3V GPIO 容忍上限,所以我统一把两个传感器都接到了 3.3V,保证逻辑电平匹配。
2.2 室外传感器节点设计
室外节点比室内复杂不少。温度测量我选用的是 DS18B20 防水探头,不锈钢封装,直接插到百叶箱里,测量范围 -55 到 125 摄氏度,精度正负 0.5 摄氏度,对气象监测来说完全够用。DS18B20 是单总线协议,一根数据线上可以并联挂载多个探头,而且它本身支持寄生供电,但在我的设计里没有用寄生模式,而是给每个探头单独拉了 VCC 和 GND,因为寄生供电在长距离线缆上容易因为压降和电容效应导致复位时序失败。
室外湿度传感器我最初计划用 SHT30 的防水版本,但实际询价发现防水透气膜版本的单价偏高,于是改用了一颗带防护涂层的 DHT22 模块。DHT22 的精度是正负 2%RH,响应速度比 SHT30 慢不少,好处是引脚兼容性好、驱动代码到处都是,而且模块自带 10k 上拉,不需要额外搭电路。这里必须诚实地说,DHT22 在长期高湿环境下的稳定性不如 SHT30,但作为室外节点的入门方案,配合定期校准还是可以接受的。
室外光照传感器选了 BH1750,I2C 接口,量程 0 到 65535 lux。它没有直接挂在主机的 I2C 总线上,而是先接到一个 8 位单片机小板上,由小板把光照和降雨开关信号打包成 Modbus 协议帧,再通过 RS485 传给 W55MH32。这个设计看起来绕了一圈,但好处非常明显:室外传感器节点和主机之间只走一条差分总线,电气隔离和抗干扰都更容易做,而且未来要增加新传感器时,只需要修改小板的固件,主机的驱动代码完全不用动。
降雨检测我用了最简单的电容式雨滴传感器,输出数字开关量,当雨滴落在检测板表面时,输出电平从高变低。这类传感器的灵敏度可以通过电位器调节,我把阈值调得比较保守,只在检测板表面明显湿润时才触发,避免露水和轻微雾气导致误报。
2.3 电源与线缆规划
整个系统的供电拓扑是:室内主机用 5V 直流电源适配器供电,板载稳压器把 5V 转换成 3.3V 给 MCU 和室内传感器供电;室外节点的 RS485 通信芯片和传感器小板直接从同一路 5V 电源取电,但我在室外节点入口处加了一个 T 型滤波器(电感加电容),把线缆上可能从雷击或感性设备传来的尖峰脉冲滤掉。同时,RS485 的差分线对采用的是屏蔽双绞线,屏蔽层在主机端单点接地,不在室外节点端接地,避免地环路产生共模干扰。
线缆截面积上,因为室外节点最大工作电流大约 200mA,按 5V 供电、最长 30 米估算,单程电阻约 0.5 欧姆,线损压降只有 0.1V 左右,没有问题。如果现场距离超过 50 米,就要考虑把供电电压提高到 12V,在室外节点端再加一颗降压模块。
3. 固件架构与核心逻辑
3.1 主循环与状态机设计
W55MH32 上我没有跑实时操作系统,而是用一个简单的前后台结构:定时器中断作为心跳,main 循环里跑状态机。这样做的好处是代码逻辑一目了然,每个状态转换都是显式的,调试时只需要盯住状态变量就能定位问题。
整个系统被划分成六个状态:INIT(初始化)、COLLECT(采集数据)、TRANSMIT(通过 RS485 拉取室外数据)、PROCESS(滤波与解析)、DISPLAY(刷新 LCD)、NETWORK(处理 TCP 请求)。时钟节拍是 10ms 一个 tick,一个完整的采集周期是 2 秒,也就是每 200 个 tick 切换一次采集与处理阶段。2 秒的采样周期对气象数据来说绰绰有余,温湿度和气压都是慢变量,采样太频繁反而会导致数据显示抖动。
状态机代码的骨架大致是这个思路:
typedef enum { ST_INIT, ST_COLLECT, ST_TRANSMIT, ST_PROCESS, ST_DISPLAY, ST_NETWORK } sys_state_t; void main(void) { sys_state_t state = ST_INIT; while (1) { switch (state) { case ST_INIT: init_hardware(); init_sensor_bus(); init_tcpip_stack(); state = ST_COLLECT; break; case ST_COLLECT: read_indoor_sensors(); collect_uart_buf(); state = ST_TRANSMIT; break; case ST_TRANSMIT: modbus_poll_outdoor_node(); state = ST_PROCESS; break; case ST_PROCESS: process_data(); state = ST_DISPLAY; break; case ST_DISPLAY: refresh_lcd(); state = ST_NETWORK; break; case ST_NETWORK: handle_tcp_requests(); state = ST_COLLECT; // 回到采集,形成循环 break; } } }这里有一个非常关键的约束:RS485 半双工总线的收发切换必须严格把握时间点,发送完一帧数据后,必须等发送完成标志置位,再延时一小段时间,才能把引脚切回接收模式。如果切换太快,最后一两个字节可能还在移位寄存器里没有真正发出去,就被切断了,对方收到的帧就会丢失尾部字节。我在代码里专门写了几个延时函数,并且在实际调试时用示波器抓了 RS485 收发使能引脚和总线波形,才确定了合适的切换延时。
3.2 数字传感器读取时序
SHT30 的 I2C 读取比较简单,发送测量命令 0x2C 0x06(高重复性、10Hz 模式),然后等待至少 10ms,再连读 6 字节。这 6 字节分别是温湿度的高位、低位和 CRC 校验位。SHT30 的 CRC 校验算法是多项式 0x31,初值 0xFF,具体实现网上有很多现成代码,但很多人偷懒不校验,这在室内近距离 I2C 通信中问题不大,因为走线短,出错的概率确实低。但我还是加上了 CRC 校验,原因很简单:一旦通信中断或电平被干扰,错误的数据可能是一大段跳变的极端值,光靠数据合理性过滤是不够的。
DS18B20 的单总线时序是另一个容易出问题的地方。这个器件对时序要求极其严格,读槽、写槽、复位脉冲的窗口都在几十微秒的级别,而且不同厂家的 DS18B20 对时序参数的要求还有细微差异。我在代码里把时序操作都用汇编语言写了,不是在 C 里内嵌汇编,而是在 Keil C51 中单独建了汇编文件,这样可以把延时精确到单个机器周期。8051 的机器周期是固定已知的,系统时钟选 12MHz,那么一个机器周期就是 1 微秒,延时控制非常直观。
读取 DS18B20 的温度值时,我一直用 12 位分辨率模式,转换时间最长需要 750ms,所以在采集周期设计上,我特意把室外温度读取放到一个较长的等待流程里:先发转换命令,然后不阻塞等待,而是继续去处理室内传感器数据和网络请求,等下次进入室外读取状态时再发读暂存器命令,这时候转换早就完成了。这种交叉调度的方式避免了 750ms 的阻塞浪费。
3.3 数据滤波与异常值剔除
气象数据在传输过程中偶尔会出现瞬时毛刺,比如风吹过传感器探头时,DHT22 的湿度读数可能瞬间跳变几个百分点,又或者 RS485 总线上的一阵干扰导致一帧室外湿度数据错误。如果直接把毛刺数据送去显示或网络发布,用户看到的就是数值乱跳,体验很差。
我采用的方案是做一轮中值滤波加一阶低通滤波的组合。具体来说就是每轮采集周期内连续读取 5 次数据(用 5 次有效读数的数组),排序后取中间值,作为这一轮的滤波输出。然后将滤波输出送入一阶低通环节:
filtered = filtered * 0.7 + raw * 0.3;为什么用 0.7 和 0.3 这两个权重?这是根据我的采样周期(2 秒)和希望达到的时间常数(大约 6 秒左右)估算出来的。一阶低通的时间常数约为采样周期乘以 (weight_old / weight_new),也就是 2 秒乘以 (0.7 / 0.3) 约等于 4.7 秒。这个时间常数既不会掩盖真实的温度变化趋势,又能把瞬时跳变压下去。如果权重取 0.9 和 0.1,时间常数会变长,温度曲线会显得迟钝,早上开机预热时段数据看着就不真实。
另外,我还写了一个合理性判断函数,定义了每个物理量的上下限阈值。比如温度如果在 -60 到 80 摄氏度之外,湿度在 0 到 100% 之外,就判定为无效读数,直接丢弃这一轮采集结果,保留上一次的有效值。同时在数据状态字段里打上对应的告警标志,比如“室外温度传感器故障”或者“湿度数据超限”,这样远程页面上就能直接看到异常状态,而不是看到一堆闪烁的乱码数字。
4. 以太网接入与网页远程查看
4.1 TCP/IP 协议栈的集成方式
W55MH32-ADK 这块板子在出厂时通常会附带一个精简版的 TCP/IP 协议栈库,调用起来非常直接:初始化网卡、配置 MAC 地址、向 DHCP 服务器申请 IP,然后建立一个 TCP socket 监听特定端口。整个流程不需要自己处理 ARP、IP 分片这些底层细节,协议栈库都已经封装好了。这一点对老平台来说算是难得的便利,毕竟 8051 资源紧张,不可能指望它跑一个完整联网内核。
我的网络初始化代码大致是这样的:
void network_init(void) { /* ADK 板载的以太网控制器初始化 */ eth_phy_reset(); eth_mac_set(MAC_ADDR); /* 从 EEPROM 读取或使用默认地址 */ dhcp_start(); /* 向 DHCP 服务器请求地址 */ while (dhcp_status == DHCP_OFF) { dhcp_tick(); } tcp_server_start(80, web_callback); }IP 地址的获取方式我最终用的是 DHCP 自动获取,而不是固定 IP。原因是家庭和多数办公网络的网关网段经常变化,固定 IP 要么需要现场询问管理员,要么就得提前规划网段,如果规划错了,设备一插上去就离线。DHCP 方式虽然会在某些网关下分配到不稳定的地址,但对监测场景来说,只要在开机时把获取到的 IP 显示在 LCD 上,用户照着输入浏览器就行。
如果设备部署在没有 DHCP 服务的专网里,我在代码里也做了兜底:等待 DHCP 超时 30 秒后,自动启用备用的固定 IP 255 段地址。
4.2 Web 页面与实时数据更新
远程页面我采用了两层的结构:首页是一个纯 HTML 的仪表盘页面,展示当前最新数据,页面通过 JavaScript 定时请求 JSON 接口来刷新数据,不需要整页重载;另一个是趋势页,用简单的前端脚本拉取最近一小时的采样记录,在 Canvas 上画折线图。
主机端响应请求时,把当前温湿度、气压、光照和降雨状态封装成 JSON,每次请求都重新生成最新内容。JavaScript 的定时刷新间隔我设成 5 秒一次,这是因为后端数据本身的采样周期是 2 秒,再加上滤波过程,5 秒的刷新频率已经足够平滑。如果刷新频率太快(比如 1 秒),浏览器的请求堆积反而会给 8051 内核造成不小的负担,因为它需要处理 TCP 连接建立和断开。
典型的 JSON 返回数据长这样:
{ "timestamp": "2024-05-20 09:32:11", "indoor": { "temp": 25.6, "humidity": 58.2, "pressure": 1013.4 }, "outdoor": { "temp": 22.1, "humidity": 66.7, "light": 32000, "rain": false }, "status": { "sensor_fault": 0 } }页面左侧用卡片展示数据,右侧是告警区域。告警逻辑我放在前端做了一部分,比如当室外温度低于 5 摄氏度时显示蓝色告警,高于 35 摄氏度时显示红色告警,这样用户可以不用盯住数字也能快速感知环境异常。当然真正严格的环境告警逻辑(比如机房温度超过 28 度自动通知运维)应该放在主机后端做,后端判断比前端可靠得多,前端页面只是辅助展示。
4.3 数据日志与导出
光有实时页面肯定不够,监测系统的价值有一半在于历史数据。我在 W55MH32 上划了一块外部 SPI Flash 作为日志存储区,每隔 5 分钟把一组数据写入日志循环缓冲,最多可以保存最近 14 天的数据。SPI Flash 的写入需要先擦除后写入,我封装了一个小型的环形存储区管理模块,用来处理坏块和损耗均衡。
Web 页面上提供了一个下载按钮,点击后会触发主机把日志区域的数据以 CSV 格式流式发送给浏览器。8051 上生成 14 天的完整 CSV 文件会占用大量内存,所以我没有一次性把所有数据都加载到 RAM,而是采用边读边发的流式方式:一页日志读出来、拼上 CSV 头、发送、再读下一页。这样即使数据量大,内存占用也保持在几百字节的级别。
这里的坑是 HTTP 响应头和字符编码。CSV 文件如果不带 UTF-8 BOM,用 Excel 打开时中文表头会乱码。我在生成 CSV 时特意在文件起始处加入了 EF BB BF 三个字节的 BOM 标记,并把整个文件内容用 UTF-8 编码生成,用户下载后直接用 Excel 打开就是正常的表格。
5. 可靠性设计与现场校准
5.1 传感器校准与偏移修正
电子传感器出厂时虽然都做过校准,但每颗芯片之间依然存在细微差异,尤其是在温湿度这类受材料和工艺影响的器件上。最典型的问题是 DHT22 的湿度值在 60%RH 以上时会有明显偏高或偏低的系统误差,不同批次的模块可能相差 3 到 5 个百分点。如果只是随便玩玩,这个误差可以接受,但既然要做远程监测,我就在系统里加入了校准常数配置接口。
校准的思路是用一个高精度的参考仪器(这里用的是工业级的温湿度计)和监测系统放在同一个环境里,稳定 30 分钟后,读取两者读数之差,把差值作为修正偏移量写入 EEPROM。在固件初始化时,把这些偏移量从 EEPROM 中读出,叠加到每次滤波后的测量值上。这个过程只能修正系统性的偏差,对非线性误差(比如某些传感器在 10%RH 和 90%RH 下的误差方向不一致)效果有限,但作为工业现场最常用的校准手段,已经足够支撑大多数应用场景。
5.2 室外节点的保护措施
室外环境远比室内恶劣,不光有雨水、阳光直射,还有温差膨胀和昆虫等各种干扰因素。我的室外传感器节点被装进了一个小型百叶箱式的防护壳里,顶盖做成倾斜面,雨水可以自然流走。传感器探头没有直接裸露在壳体内,而是用防水接头引出,探头本身套了一层透气防水膜。杜绝对探头直接淋雨,否则 DS18B20 的响应会严重滞后,DHT22 的采样头一旦进水,湿度读数会直接飙到 99% 然后卡住。
保护壳的通风设计也要注意。很多人会把外壳做成完全密封的,这样虽然防水,但壳内空气不流通,太阳辐射热会导致内部温度比真实环境高出好几度。百叶箱的结构就是允许空气自然流过,但阻挡直射阳光和雨水。我在处理室外温度探头时,还特意把它悬空安装在壳体中部,不接触任何金属结构,减少热传导的影响。
5.3 看门狗与异常恢复
嵌入式设备最怕的不是启动不了,而是运行一段时间后“假死”——程序还在跑,但逻辑卡在某个循环里,或者中断异常导致主循环不再推进。对于无人值守的监测设备来说,这种假死状态会在用户察觉之前就已经造成长时间的数据空白。
我在代码里启用了 W55MH32 的硬件看门狗,并且在主循环中喂狗。关键是喂狗的位置不要放在每个 case 之后,而是放在一个悖论检查之后:只有当一个完整的采集流程(采集、传输、处理)确实完成后,才喂狗。如果某个环节卡住,狗就不会被喂,芯片会在几秒后复位,重新走一遍初始化流程。这样虽然会造成短暂的数据中断,但至少能保证设备不会一直“装死”。
此外,复位原因寄存器也被我利用起来:看门狗复位之后,固件会把复位原因记录到 EEPROM,然后在上电初始化时读取该记录,如果发现是看门狗复位超限(比如一小时内复位超过 5 次),就把系统切换到故障模式,只启动基础显示功能,并打上醒目的故障代码。这个设计的目的是防止在严重硬件故障时,看门狗复位和再次崩溃之间形成无休止的抖动循环。
6. 常见问题与排查实操
6.1 RS485 通信偶发丢帧
现象:主机端接收到的室外数据,每过一段时间就会出现一次校验错误,错误频率不固定,有时候一天都没事,有时候一小时错好几帧。
排查过程:先用示波器抓了主机端 A/B 差分线波形,发现总线空闲时 A/B 之间的电压只有 0.2V,而规范要求终端匹配电阻两端的差分电压应在 0.2V 以上,这个值刚好踩着下限。这是因为主机和室外节点距离超过 20 米,总线末端的偏置电阻不够或根本没有。解决办法是给链路两端各加一个 120 欧姆终端匹配电阻,并且只在主机端那侧增加一组上下拉偏置电阻,让总线在空闲时稳定在确定电平。加上之后,波形干净很多,错误帧几乎绝迹。
另一个容易忽略的细节是 RS485 收发芯片的 RO 引脚和 DI 引脚电平匹配。ADK 的 UART 是 3.3V 电平,而部分 RS485 芯片是 5V 供电,其 DI 引脚的逻辑阈值对 3.3V 高电平输入是兼容的,但原板卡的 Jumper 如果默认接在 5V 参考,就有可能在边沿处产生误判。我最后把 RS485 芯片的 VCC 也接到了 3.3V,虽然传输距离上略逊于 5V 供电,但在这个项目里完全够用,换来的是可靠稳定的电平配合。
6.2 DHT22 在潮湿天气读数失效
现象:连续几天阴雨天之后,室外 DHT22 的读数一直保持在 99.9%RH 不变,重启后能短暂恢复,但很快又回到老样子。
问题根源:DHT22 模块的塑料外壳虽然能防少量溅水,但在高湿度环境下水汽会渗透到传感器探头内部,造成探头表面凝结水膜,导致读数饱和。这种情况不是固件能解决的,而是防护方案的结构问题。
解决思路:给 DHT22 外面加装一层 GORE-TEX 防水透气膜。这个膜能把液态水阻挡在外面,但允许水汽分子通过,既保护了探头又保证了湿度响应。需要说明的是,透气膜本身有透气阻力,会导致传感器响应速度变慢一点点,实际测试下来响应时间从原来的 2 秒变成大约 10 秒,对气象监测完全可以接受。
6.3 以太网连接不稳定,网页偶尔打不开
现象:浏览器第一次打开板卡 IP 时一切正常,但刷新几次之后偶尔会加载不出来,过十几秒又自己恢复。
排查过程:我把 TCP 连接数目的限制调了出来,发现板卡默认最多只支持 4 个并发连接。而浏览器本身打开页面时,主页面和 JS 文件会建立多个 TCP 连接,加上某些浏览器会预取页面,并发连接数很容易就超了。超了之后协议栈会把新的连接请求丢弃,反映到用户端就是页面转圈半天没反应。
解决办法有三步:第一,优化 HTML 页面,把 CSS 和 JavaScript 内联到同一个 HTML 文件里,减少页面发起的连接数;第二,把 TCP 最大并发连接数从默认值调高到 8(对 8051 内存是一种考,但关闭不使用的功能后足以负担);第三,开启了 TCP 半连接超时回收机制,把一些空连接在 60 秒内回收掉。
6.4 室内与室外温度显示差值过大
现象:当阳光直射室外保护壳时,室外温度显示比周边气温高了约 4 摄氏度。
原因找到了:保护壳的涂装是深灰色,吸热能力强,而且壳内空气虽然能流通,但换气速度不够快,壳体受到太阳辐射加热后,内部空气温度被明显抬高。这是所有温度观测装置都会面临的共性难题,气象站的专业做法是强制通风百叶箱,内部装一个小风机持续换气。
我的项目没有采用强制通风,因为会增加功耗和噪声。替代方案是给壳体表面贴了一层铝箔隔热膜,把阳光辐射反射掉大部分,同时把百叶箱的进出风口开大了一些,并调整了探头的安装位置,让它距离壳体表面保持至少 5 厘米的间距。改造后,太阳直射下的温度偏差从 4 摄氏度降低到了 1 摄氏度以内。如果未来有更大的预算和电源余量,可以考虑加装微型直流风机,把偏差进一步压到 0.2 摄氏度以内。
7. 实际使用中的体会与扩展方向
整个项目做下来,我最深的体会是:硬件平台的年龄不代表能力上限,关键看你怎么设计和裁剪需求。W55MH32-ADK 这块板子虽然主频不高、Flash 和 RAM 也紧张,但只要把功能模块边界划分清楚,让每个环节都在它自己最擅长的频率上运转,这个系统的完成度可以非常高。
如果现在再给我一次机会重做这个项目,我会在几个方面做出调整。第一,室外传感器节点的单片机不再自己做 Modbus 协议栈,而是直接用开放源码的库,因为自己写的 Modbus 从机代码在异常帧处理上有不少遗漏,在总线上多挂几个节点对时序的要求会急剧提升。第二,Web 页面会增加一个简单的用户权限认证,哪怕只是 HTTP Basic Auth,否则只要知道 IP 就能看到环境数据,在公开网络下还是有些不妥。第三,日志存储会切换到 SD 卡而不是 SPI Flash,因为 SD 卡容量大、容量扩展方便,后期如果要做月度报表就不用频繁地导数据了。
这个系统目前已经连续运行了几个月,稳定性和准确性都达到了我最初的预期。下一步我打算在室外部加一个超声波风速风向传感器,接入到现有的 RS485 总线上,让天气监测的功能更完整。另外,如果读者手里的传感器型号和我的不一样,不用照搬参数,重点参考我这里的拓扑划分和状态机思路,再根据自己器件的时序要求做适配,就能快速搭起一套属于你自己的室内外环境监测站。