ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

以太网温湿度感知节点:基于ESP32与LAN8720的硬件设计及TCP通信实践

以太网温湿度感知节点:基于ESP32与LAN8720的硬件设计及TCP通信实践 1. 项目整体设计与硬件架构选型1.1 为什么选择以太网作为感知节点的通信方式作为常年泡在实验室和现场设备打交道的人我接到“以太网温湿度感知节点”这个需求时第一反应不是急着画板子而是先想清楚一个问题为什么放着好好的WiFi不用非要拉网线WiFi方案从ESP8266开始就非常成熟了几块钱的模组上手快代码生态也丰富。但你真把它丢到工业现场或者机房环境里问题立马就出来了。第一是稳定性WiFi是共享信道周围微波炉、蓝牙设备、隔壁AP的同频干扰都会导致丢包你采集的温湿度数据一分钟丢一包可能环境异常就恰好丢在那几秒里。第二是漫游与重连节点一旦掉线AP切换、DHCP重租约这套流程少说也要好几秒对于连续性要求高的监测场景就很伤。第三是安全问题很多WiFi设备默认配的WPA2/WPA3如果管理不善或者干脆为了省事开了无密码热点这在等保和内部审计里是很扎眼的漏洞。以太网没有这些问题。它是有线介质点对点连接几乎不存在同频干扰重连机制简单可靠标准的TCP/IP协议栈保证了数据端到端可达交换机端口有MAC地址绑定、VLAN隔离等一整套管控手段。对于温湿度感知这类长时间无人值守的采集节点有线接入几乎是“一次部署、长期稳定”的代名词。当然代价也有。以太网物理层PHY芯片比WiFi模组贵PCB布线要求高RJ45座子加网络变压器占地也不小。但如果你是做楼宇自控、机房动环、仓库环境监测这类需要长期在线、数据要进监控平台的项目这点成本完全值得。1.2 芯片选型ESP32、LAN8720与温湿度传感器硬件核心选型我定了这样一套组合模块型号作用选型理由主控MCUESP32ESP32-DEVKITC兼容设计数据采集、协议栈、业务逻辑内置10/100M以太网MAC直接对接RMII接口自带TCP/IP协议栈主频240MHz足够跑业务以太网PHY芯片LAN8720A物理层信号转换RMII接口、支持10/100M自适应、休眠功耗低至1μA、外围器件少厂家成熟度高网络变压器RJ45HR911105A带变压器一体式信号隔离与电平适配一体化封装省PCB面积内置隔离变压器满足EMC要求温湿度传感器SHT30-DIS环境参数采集I2C接口精度±2%RH、±0.3℃价格在十元档位带CRC校验替换DHT系列的老旧方案ESP32在这套方案里的角色很多人容易误解。它本身不带以太网物理层但它集成了以太网MAC控制器支持RMII接口与外部PHY芯片通信。这就像你家网络是光纤入户光猫负责光电转换PHY路由器负责MAC和IP处理ESP32。LAN8720A就是那个“光猫”把差分信号转成数字电平把复杂的物理层编解码、载波监听、冲突检测全包了ESP32只需按RMII协议收发数据即可。SHT30我多说两句。选它不选DHT22主要是因为DHT22的单总线协议对时序要求极其苛刻在ESP32这种多任务环境下需要关中断去读数据稍微有点其他中断打扰数据就废了。SHT30是标准I2C接口硬件时序由外设自动处理配合ESP32的I2C驱动非常省心。而且它支持I2C CRC校验多项式0x31初值0xFF这在温湿度采集里很有用——传感器放在配电房一类电磁环境复杂的场所线缆感应噪声可能让I2C数据出错有了CRC至少能当场发现并重读。1.3 系统整体架构与数据流规划整个节点的数据流并不复杂但架构设计上要提前把模块边界划分清楚否则后面写代码就是一坨浆糊感知层SHT30 采集温湿度原始数据 ↓ I2C总线轮询周期默认2s 控制层ESP32 处理数据CRC校验、单位换算、存储最近N组数据 ↓ TCP协议栈LWIP打包发送 传输层LAN8720A RJ45 物理链路 ↓ 双绞线Cat5e及以上 应用层上位机/监控平台 接收、存储、展示、告警我习惯把“感知”“控制”“传输”“应用”四层分开想问题。感知层只管采集控制层只管组帧与策略传输层保证链路通畅应用层不关心底层细节。这样的好处是每一层都能独立测试传感器坏了换传感器网络不通排查网络不需要把整个系统推翻重来。协议栈层面ESP32使用的是乐鑫移植的LWIP轻量级TCP/IP协议栈BSD Socket接口编程跟你在Linux上写socket服务端几乎一模一样这对后面开发TCP通信协议非常友好——网上资料多、调试工具多、踩坑经验也好找。2. 以太网接口电路与PCB实操要点2.1 LAN8720A的核心电路设计LAN8720A的硬件设计看似简单但细节非常多。先看RMII接口的引脚定义这是整个电路设计的骨架ESP32引脚LAN8720A引脚功能说明GPIO0REF_CLK (CLKOUT)50MHz参考时钟输出GPIO27RMII_TXD0发送数据位0GPIO26RMII_TXD1发送数据位1GPIO25RMII_TX_EN发送使能GPIO23RMII_RXD0接收数据位0GPIO22RMII_RXD1接收数据位1GPIO21RMII_CRS_DV载波监听/数据有效GPIO19MDIO管理接口数据线GPIO18MDC管理接口时钟线RMII接口的精髓在于“窄而快”。相比MII接口的16根数据线RMII只用了7根数据线但时钟频率翻倍统一为50MHz。发送数据在时钟上升沿采样每周期传2位拼起来就是100Mbps的吞吐。这里有个特别容易踩的坑REF_CLK的时钟源配置。LAN8720A默认为时钟输出模式也就是由PHY自己产生50MHz时钟供MAC使用。这个模式下ESP32侧的GPIO0必须配置为输入模式并且要开启内部上拉电阻。PHY有没有正确输出时钟直接影响后边的MAC初始化能不能成功。我这边遇到过好多次程序卡在esp_eth_phy_negotiate这一步一查GPIO0没配上拉PHY时钟根本没起来网络层自然起不来。2.2 电源与复位设计要点LAN8720A的功耗不算大典型工作电流约70mA3.3V但它的电源要求比较讲究PHY芯片的数字电源和模拟电源建议分别退耦至少各放置一个100nF电容靠近电源引脚。我在设计时还额外加了一个10μF钽电容做低频储能防止网线插入瞬间的大电流浪涌导致电压跌落。整体供电方案是外部5V输入 → AMS1117-3.3线性稳压 → 3.3V电源轨。温湿度传感器SHT30和PHY芯片共用这一路电源但每个器件都在电源引脚就近加了0.1μF去耦电容有效避免了传感器数据跳变时对PHY的干扰。复位电路这里提一个容易被忽略的点。LAN8720A的NRST引脚是低电平复位需要至少1μs的复位脉冲。很多人图省事直接用MCU的GPIO去控制复位这本身没问题但要注意MCU上电瞬间GPIO状态不确定如果恰好输出高电平PHY会一直处于复位状态。我在ESP32的GPIO2上接了PHY复位引脚同时在GPIO2外部加了一个10kΩ下拉电阻到GND确保上电时PHY处于复位状态等MCU初始化完成后再拉高释放复位。2.3 PCB布线的关键教训这块板的布线有几个血泪教训我逐条说。差分信号线是重中之重。LAN8720A的TXD、TXD-、RXD、RXD-是四根差分对阻抗要求100Ω±10%。如果你用两层板没有完整的参考地平面差分阻抗就很难控制。有条件就上四层板第二层做完整地平面退而求其次的话两层板布线要保证差分对正下方不穿其他信号线且线宽线距按厂商参数计算。我用嘉立创打样双层板50mil宽的差分对线距6mil实测也能跑通100M但余量明显不如四层板。然后是RJ45座子的位置。网络变压器电流隔离的任务由HR911105A内部完成但PCB上RJ45到PHY芯片之间的走线还是要遵循“先过变压器再过共模电感最后进PHY”的顺序。有些参考设计把共模电感省掉省掉也不是不能用但静电测试和脉冲群测试就有可能在网络口挂掉。最后是晶振。LAN8720A需要一个50MHz晶振我采用的是有源晶振方案SIT8008系列它直接把50MHz时钟信号送到PHY的XI引脚比无源晶振少两个匹配电容可靠性也更高。注意晶体走线要短且周围不要走数字信号线否则时钟抖动大了PHY的接收性能会明显下降。3. TCP通信协议设计与开发实现3.1 协议设计从裸数据到结构化帧硬件通了之后最大的工作量其实在通信协议上。很多人一上来就把温湿度数据直接send出去上位机也一收就完事。短期内自己调试没问题但一旦接入监控系统、多节点并发上报、网络丢包场景出现裸传方案体无完肤。我建议哪怕节点再简单也按以下帧格式定义| 帧头(2B) | 长度(2B) | 命令字(1B) | 节点ID(2B) | 数据区(NB) | CRC16(2B) |字段说明如下字段名长度说明帧头2字节固定0xAA55用于接收方帧同步长度2字节从命令字开始到CRC16之前的字节总数大端序命令字1字节0x01主动上报0x02心跳0x03配置下发节点ID2字节设备编号支持最多65535个节点数据区N字节温湿度等业务数据长度由帧头字段决定CRC162字节Modbus CRC16校验范围是长度字段之后到数据区末尾这里最核心的设计决策是长度字段、CRC校验和帧头固定值三者缺一不可。长度字段解决TCP流式传输的粘包问题CRC保证数据完整性帧头则让接收方在流里能快速找到帧边界。我的经验是这三个要素加在一起协议才算“能用于生产环境”。数据区具体格式我做的是定长结构体typedef struct { float temperature; // 单位℃保留两位小数 float humidity; // 单位%RH保留两位小数 uint32_t timestamp; // 本次采集的UTC时间戳 uint8_t battery_level; // 电池电量百分比便于后期扩展 } sensor_data_t;用二进制定长结构体而不是JSON主要是效率考虑。一个温湿度帧总共才20多字节如果转成JSON串“{temp:25.36,hum:42.78}”就是40多个字节还要处理字符串解析设备端资源有限的情况下显然不划算。JSON协议留给应用层二次开发用设备端只吐最精简的二进制帧。3.2 TCP通信模式选择服务端还是客户端节点的角色定位直接决定代码架构。我设计的是“TCP客户端主动上报”模式感知节点作为客户端主动连接监控服务器连接建立后周期性上报数据。这个选择主要考虑了两个因素。第一是NAT和防火墙友好性。现场环境几乎不可避免有NAT转换如果节点做服务端上位机没办法直接连进来节点做客户端主动外联只需要交换机放行出方向流量即可。第二是节点管理与扩展。每个节点知道自己要连哪个服务器服务器端只需要监听一个端口等着成百上千个节点接入维护成本更低。不过在客户端模式下心跳机制必须设计好。TCP本身有KeepAlive功能但系统默认探测间隔是2小时太慢了。我们在应用层每30秒发一个心跳帧命令字0x02服务器连续3次90秒没收到心跳就判定节点离线产生告警。这个心跳间隔实测下来既不消耗太多带宽30秒×约20字节约等于每秒不到1字节又能保证故障快速感知。3.3 基于ESP-IDF的以太网驱动与TCP客户端实现ESP32侧的代码基于ESP-IDF v5.1开发核心是ETH驱动初始化和TCP客户端任务。先看初始化部分#include esp_eth.h #include esp_eth_mac.h #include esp_eth_phy.h #include esp_netif.h // 配置PHY时钟来源和复位引脚 eth_phy_config_t phy_config ETH_PHY_DEFAULT_CONFIG(); phy_config.phy_addr 0; // LAN8720A的PHY地址由PHYAD0引脚决定接地为0 phy_config.reset_gpio_num 2; // 复位引脚GPIO2 esp_eth_phy_t *phy esp_eth_phy_new_lan8720(phy_config); esp_eth_mac_t *mac esp_eth_mac_new_esp32(mac_config); esp_eth_handle_t eth_handle NULL; esp_eth_driver_install(eth_config, eth_handle); esp_netif_config_t netif_config ESP_NETIF_DEFAULT_ETH(); esp_netif_t *eth_netif esp_netif_new(netif_config); esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle)); esp_eth_start(eth_handle);这段代码的关键点在第2个参数phy_addr。LAN8720A的PHY地址由芯片的PHYAD0引脚的上下拉状态决定——悬空或接低为0接高为1。如果板子上这个引脚拉了高你没改这个参数驱动就找不到PHY直接返回ESP_ERR_NOT_FOUND。很多人第一次初始化失败基本都是这个原因。驱动起来后网络层配置有两种方式DHCP自动获取IP或静态IP。温湿度节点这种固定部署的设备我强烈建议使用静态IP。原因很简单如果服务器重启导致DHCP池重新分配节点可能会拿到不同IP服务器端的设备白名单就得跟着改。而且静态IP让网络管理更清晰——机房网管一看IP段就知道是那个区域的采集节点。TCP客户端任务的核心结构static void tcp_client_task(void *arg) { while (1) { int sock socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); struct sockaddr_in server_addr {0}; server_addr.sin_family AF_INET; server_addr.sin_port htons(SERVER_PORT); inet_pton(AF_INET, SERVER_IP, server_addr.sin_addr); // 连接服务器失败则延时重试 if (connect(sock, (struct sockaddr *)server_addr, sizeof(server_addr)) 0) { close(sock); vTaskDelay(pdMS_TO_TICKS(5000)); continue; } // 连接成功后执行上报与心跳循环 while (is_connected) { sensor_data_t data read_sensor_data(); send_frame(sock, CMD_REPORT, (uint8_t*)data, sizeof(data)); vTaskDelay(pdMS_TO_TICKS(REPORT_INTERVAL_MS)); send_frame(sock, CMD_HEARTBEAT, NULL, 0); vTaskDelay(pdMS_TO_TICKS(HEARTBEAT_INTERVAL_MS)); } close(sock); } }上报周期我设为默认10秒心跳30秒两个任务通过一个简单的状态机管理。实际测试中10秒上报间隔对于温湿度变化来说足够了温湿度是缓变量除非你部署在空调出风口这种极速变化的环境否则没必要做到1秒一次徒增网络负担。3.4 缓存与重传应对网络瞬断的兜底方案这里我要重点聊一个很多人直到现场掉线才想起的东西数据缓存。TCP连接再稳定也耐不住交换机断电、网线被误拔这类物理故障。网络恢复后节点重新连上服务器这期间的温湿度数据如果丢了在回溯环境异常事件时就会留下盲区。我的做法是在ESP32的NVS非易失性存储中维护一个FIFO环形队列最多缓存最近2000条采集记录约5.5小时10秒间隔。正常情况下数据发完即清空缓存网络异常时数据持续写入NVS重新连接后先补发缓存数据再进入实时上报模式。NVS闪存写入寿命正常在10万次左右2000条记录用4KB空间闪存按扇区均衡写入理论寿命足够设备用十几年。需要注意的一点是补发数据时不要一次性全发否则容易触发服务器端的流量限速或socket接收缓冲区溢出。我测试下来补发速率限制为每秒20条记录服务器端处理毫无压力。4. 上位机通信模块设计与数据解析4.1 服务器端TCP监听与帧同步解析上位机通信模块我用C编写了一个轻量级的TCP服务端运行在Linux环境下监听端口默认8888。核心逻辑是每个接入的节点分配一个独立的socket线程线程里循环接收数据、解析帧、写入数据库。接收缓冲区处理TCP流式数据的粘包问题是关键。TCP是字节流协议你不去管它一次recv可能只有半个帧也可能一次塞进来十几个帧。我的处理方式如下#define FRAME_HEADER 0xAA55 // 在缓冲区中搜索帧头并提取完整帧 int parse_stream(uint8_t *buf, int buflen, frame_t *out_frame) { int offset 0; while (offset buflen - 4) { // 查找帧头 if (buf[offset] 0xAA buf[offset 1] 0x55) { uint16_t payload_len (buf[offset 2] 8) | buf[offset 3]; if (offset 4 payload_len buflen) { // 有完整帧校验CRC if (check_crc16(buf offset 2, payload_len)) { memcpy(out_frame, buf offset 2, payload_len); return offset 4 payload_len; // 返回帧结束位置 } } else { // 帧不完整等待后续数据 return 0; } } offset; } return 0; }这个函数每一次返回的是“当前缓冲区已消费的字节数”调用方把它从接收缓冲区移除然后继续处理下一帧。核心思想就是永远不要假设一次recv就是一个完整帧也永远不要假设缓冲区里只有一个帧。我开始写的时候偷懒把帧解析写成了“等积累到固定长度才开始找帧头”的笨办法结果现场一测试节点上报间隔稍有不均匀就各种丢帧后来改成流式解析才彻底解决。4.2 设备和数据的双维度管理TCP服务端只负责接收数据还不够一个实用系统需要两个维度的管理设备在线状态管理和历史数据管理。设备在线管理我用了两张表device_info存设备ID、部署位置、静态IP、最近一次在线时间device_status实时更新心跳时间戳、当前温湿度、链路质量-- 设备信息表 CREATE TABLE device_info ( device_id INT PRIMARY KEY, device_name VARCHAR(64), location VARCHAR(128), static_ip VARCHAR(16), last_seen_time DATETIME ); -- 温湿度历史表 CREATE TABLE sensor_data ( id INT AUTO_INCREMENT PRIMARY KEY, device_id INT, temperature FLOAT, humidity FLOAT, sample_time DATETIME );设备上线时服务端根据节点ID查询device_info如果是新设备则自动注册这在多节点批量部署时非常省事。设备下线时90秒未收到心跳就更新device_status状态为离线并在前端产生告警弹窗运维人员能第一时间知道哪台节点异常。4.3 告警阈值的动态配置策略温湿度监控项目最怕两个词误报和漏报。阈值设置太紧空调稍微波动一下就叫个不停太松机柜温度到45℃了还在淡定录数据。我的做法是把报警阈值做成可远程配置的而不是写死在节点固件里。协议里预留了命令字0x03用于配置下发。服务器端向节点发送一帧配置数据节点收到后更新本地阈值参数并回发确认帧配置项默认值说明温度上限35.0℃超过即报警温度下限5.0℃低于即报警湿度上限80%RH超过即报警湿度下限20%RH低于即报警上报周期10s可调范围1~60s比如夏天机房空调改造你不需要重新烧固件直接通过平台下发新阈值节点在下一次心跳周期后自动生效。这个设计在后续运维中节约了大量时间强烈推荐所有做设备类项目的人都预留配置下发通道。5. 实测过程中遇到的5个经典问题与解决方法5.1 LAN8720A初始化失败时钟、地址、复位逐一排查这是玩ESP32LAN8720组合时遇到率最高的问题。我把它分为三类依次排查PHY时钟没输出检查GPIO0是否正确配置为上拉输入。这问题用万用表量GPIO0电压就能发现正常情况应该是50MHz方波直流电压约2.5V左右占空比50%。如果测出来是0V或3.3V说明PHY根本没起振短接RXD0和TXD0测试一下芯片自检模式可以快速定位。PHY地址不匹配报ESP_ERR_NOT_FOUND错误时先确认PHYAD0引脚拉的是高还是低。LAN8720A的PHY地址仅由这一个引脚决定接高是1接低或悬空是0。复位释放太早PHY上电后需要一段时间才能准备好如果复位脚在电源稳定前就释放芯片可能锁死在异常状态。我的改法是在MCU初始化完成前一直保持复位有效初始化时先释放复位、延时10ms、再配置寄存器稳定得很。5.2 网络连不上从网线到交换机的链路排查插座插上了网口灯也亮了可就是ping不通。这时候先把物理层的可疑因素排查干净。第一步确认PHY是否完成了链路协商。LAN8720A的寄存器0x01里有个Link Status位我用ethtool或者esp_eth日志查看。如果Link是down状态大概率是网线或交换机端口有问题。第二步看速率协商结果正常情况下应该是100Mbps Full Duplex如果协商成10Mbps Half Duplex多半是PCB差分不走线的锅信号质量太差自动降级了。第三步再考虑网线本身Cat5e和Cat6的短距离其实都能跑100M但劣质网线会把噪声带进来我现场调试时吃过一次亏换根线全好了。5.3 发送帧校验错误CRC范围没搞明白有段时间我发现服务器端CRC校验老是有大约5%的帧不过关排查后确认问题出在发送端CRC16的校验范围把帧头也包含进去了而接收端的校验范围是从长度字段开始的。Modbus CRC16的算法本身网上代码一抓一大把但这东西最容易出错的就是边界条件。我的建议是发送端和接收端用同一套代码用几个已知的测试向量互测例如数据01 03CRC16为89 B8低字节在前数据AA 55 00 04CRC16为C3 47把这些测试向量写进单元测试每次改协议都跑一遍比现场抓包定位高效太多。5.4 拔掉网线再插上TCP连接无法恢复这个坑坑了我整整两天。现象是节点运行正常但只要网线从交换机拔掉再插回去TCP连接就断了而且一直重连不上。后来发现根因在TCP栈的保活机制上。LWIP默认的TCP KeepAlive探测要等很长时间才能发现连接已死而在这期间节点一直以为连接还是好的数据发出去也无人接收socket缓冲区塞满后行为就诡异了。解决方案是双重保险一是在应用层缩短心跳间隔到30秒二是设置socket的KeepAlive探测参数int keepalive 1; int keepidle 10; // 10秒无数据开始探测 int keepintvl 3; // 每次探测间隔3秒 setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, keepalive, sizeof(keepalive)); setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, keepidle, sizeof(keepidle)); setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, keepintvl, sizeof(keepintvl));设置后效果立竿见影网线恢复后节点最多多花十几秒就能重连并补发缓存数据。5.5 多节点并发上报导致服务器疑似卡死节点从10个加到30个后服务器出现偶发性的响应变慢。抓包发现原因是30个节点每10秒上报一次高峰期每秒会有3帧数据同时到达服务器端如果有节点在慢速处理比如写入数据库时加锁其他节点的socket缓冲区就会积压TCP窗口随之缩小发送端被迫降速。解决办法很简单服务器端接收线程和解码线程分开接收线程只负责把字节流塞进队列解码线程从队列拿数据做CRC校验和数据库写入。这样即使数据库写入慢接收端也能及时把数据从socket缓冲区拿走不会拖累TCP传输。6. 现场部署与长期运行经验6.1 网线布线原则与供电注意部署在真实环境中很多东西是实验室里想不到的。先说网线节点到交换机的距离建议控制在50米以内。100M以太网理论极限是100米但现场往往要过桥架、穿金属管、贴强电走线线缆性能打了折扣。我见过一个项目因为走线距离超过80米节点频繁丢包最后把交换机挪近才解决。供电方面如果节点部署在机柜里直接从机柜的PDU取电最省事。但要特别注意温湿度传感器和PHY芯片对电源纹波敏感PDU如果带了激光打印机这类大功率设备电压波动会传导到节点板上。我在电源入口额外加了一个LC滤波器10μH电感100μF电容实测纹波从约120mV降到了30mV以内。6.2 长期运行后的三项升级建议项目上线三个月后我根据运维数据做了三处升级。第一是固件升级机制。原来升级固件要拆设备接串口线运维成本极高。后来我把固件升级集成到TCP协议里——服务器下发固件分块节点收到后写入OTA分区校验通过后重启生效。这次改造后40多个节点的固件更新从3天人工工作量缩短到1小时全搞定。第二是数据加密。温湿度数据虽然不算核心机密但如果被恶意篡改温度报警就可能被隐瞒。我在帧数据区加了一个基于设备ID和密钥的简单HMAC签名服务器端验证签名后才接受数据。MCU算力够用每帧增加的耗时不到0.5ms。第三是传感器标定。SHT30出厂精度是±2%RH、±0.3℃但长时间在高温高湿环境工作后会有漂移。我建议每半年做一次对比校准用一个经过计量检定的标准温湿度计放在同一环境里记录差值后在阈值配置里做偏移修正。这个工作温湿度计几百块一个整体成本可控但能让上报数据的可信度上一个档次。6.3 关于数据存储周期的思考大量历史数据存起来不难难的是决定存多久、怎么存。我的经验是原始采集数据10秒间隔保留30天即可满足日常查询超过30天的数据聚合为5分钟均值保留两年超过两年的数据直接删除或者归档到冷存储避免数据库膨胀影响查询性能。这种分级存储策略在动环监控这种长期运行的项目里尤为重要——节点一年产生约315万条记录按10秒间隔算40个节点就是1.26亿条/年。如果没有一个清理策略用不了一两年数据库就拖垮了。7. 一些我踩过之后才明白的设计心得最后分享几个压箱底的心得。第一个是协议设计宁可冗余不要省事。帧头、长度、CRC、设备ID四个字段看着占了8个字节但每一个都在后续调试中救过我的命。如果你打算长期维护这个系统协议设计上的一定要“先想清楚再写代码”。第二个是断线缓存必不可少。我做第一版的时候觉得“TCP这么可靠数据肯定丢不了”结果实测一个月后统计发现因为网络瞬断丢掉的数据竟然占了总数据量的0.4%。数据量不大但对环境异常回溯场景来说那可能正是最关键的几个点。第三个是硬件调试时先把网络跑通再碰业务。我做这块板的顺序是先验证ETH驱动能ping通PC再挂上SHT30传感器最后才写TCP协议和业务逻辑。每一步都锁定一个里程碑出了Bug范围也就局限在这一个模块里。否则硬件、驱动、协议、业务逻辑全部混在一起出了一点问题根本不知道从哪查起。以太网温湿度感知节点这个项目看起来很简单就是“一个传感器加一根网线”但真正从硬件设计走到稳定运行这中间的路远比你想象的曲折。希望这篇实践记录能帮你少走几段弯路把精力花在更有价值的系统优化上。
返回列表