ESP32与W5500有线以太网实战:从SPI底层到TCP通信
ESP32 玩腻了 Wi-Fi想给它添一条更稳的有线网线我这几年的结论是W5500 是性价比最高、最不容易出幺蛾子的选择而把它接到 ESP32 上核心就是 SPI 通信。很多朋友一听到“SPI 例程”就头皮发麻觉得寄存器多、时序复杂其实把一条条代码拆开看逻辑相当直白。这篇文章我用一个能直接跑的 W5500 例程从底层 SPI 读写函数开始逐行讲到 TCP 数据收发。你不用再去零散查资料照着抄就能在一个下午把有线以太网跑通。如果你正卡在“例程下载下来看不懂”“不知道寄存器为什么要这么写”这类问题上这篇就是为你准备的。1. 项目概述与方案选型1.1 为什么选 W5500 而不是其他以太网方案做物联网项目最常见的联网方式还是 Wi-Fi但 Wi-Fi 在复杂电磁环境里不稳定断线重连、IP 冲突、信道干扰都很烦人。给设备加有线以太网其实就是加一个 TCP/IP 协议栈芯片让它自己把 TCP、UDP、ICMP 这些协议处理掉MCU 只要通过 SPI 读写寄存器、收发数据即可。市面上常见的有三类方案一是 MCU 内置 MAC 外部 PHY比如 STM32F407 LAN8720优点是用 RMII 接口速率能上 100Mbps但 MAC 层驱动要自己写底层 buffer、描述符、中断处理一堆复杂度明显偏高。二是用老牌 ENC28J60便宜但只有 10Mbps而且内置缓冲区只有 8KB收发并发吞吐一般高负载下容易丢包。三是用 W5500内置全硬件 TCP/IP 协议栈支持 TCP、UDP、IPv4、ICMP、ARP 等MCU 完全不参与协议处理通过 SPI 接口操作即可。传输速率理论可达 10/100Mbps实际项目跑到几 Mbps 很轻松。这就像把整套网络协议栈做成了一个外设把你从协议实现里解放出来。所以如果你的目标是快速、稳定地给 ESP32 加一个有线上网通道W5500 是投入产出比最高的路线。1.2 为什么用 SPI 连接而不是 SDIO 或并行总线W5500 对外只提供 SPI 接口这是设计上的一大优势。ESP32 自带两个 SPI 控制器HSPI 和 VSPI可以同时挂多个 SPI 设备接线只需要 SCLK、MOSI、MISO、SCS 四根线MCU 的资源占用很少。相比并行总线要占十几个 GPIOSPI 让硬件连接和 PCB 布线都简单很多。而且 W5500 最高支持 80MHz SPI 时钟对大多数设备来说带宽足够。ESP32 的 SPI 主模式跑到 40MHz 很稳定我平时甚至保守一点用 20MHz 做长线连接可靠性优先。SPI 虽然看起来只是四根线但它有主从模式、时钟极性和相位、片选控制这些讲究。如果这些搞不明白后面 W5500 可能会“时好时坏”。这篇文章后面会结合例程把这些问题都串起来讲。2. W5500 核心原理搞懂寄存器就成功一半2.1 寄存器是怎么组织的W5500 内部有很多寄存器按功能分成两个区域通用寄存器和 Socket 寄存器。通用寄存器负责全局配置包括重复超时时间、MAC 地址、本机 IP、网关、子网掩码、中断屏蔽等。Socket 寄存器则管理每个独立的套接字W5500 有 4 个 Socket每个 Socket 都有一组相对独立的寄存器用来配置协议类型、源端口、目标 IP、目标端口、缓冲区指针和命令状态等。在 SPI 通信时我们需要通过寄存器地址和块选择来定位要操作的寄存器。这里有一个关键概念W5500 的 16 位寄存器地址在各种手册里都用偏移量表示而在实际 SPI 帧里还需要通过控制字节里的块选择字段BSB[4:0]来告诉芯片“我要访问的是通用寄存器还是 Socket0 的寄存器还是 Socket0 的发送缓冲区”。举个例子通用寄存器的地址偏移里有一个版本寄存器 VER偏移是 0x0039它只能通过 BSB5’b00000 访问。Socket0 的 Sn_MR 寄存器地址偏移是 0x0000但它的 BSB 是 5’b00001。如果访问地址相同但块选择不同对应的寄存器完全不同。这个设计容易让新手懵所以读代码时一定要把“寄存器地址”和“块选择”看成一对组合而不是只看一个数字。2.2 数据收发缓冲区在哪W5500 内部有 32KB 缓冲区分成发送和接收两半每半 16KB可以由用户分配到 4 个 Socket 上。默认情况下每个 Socket 分到 2KB 发送缓冲和 2KB 接收缓冲。当我用 SPI 向 Socket0 发送数据时实际上是把数据写入“Socket0 TX Buffer”这个块然后通过写 Sn_CR 寄存器发送 SEND 命令W5500 硬件就开始自动组包、发送并等待 ACK。接收数据时硬件会把收到的数据放进“Socket0 RX Buffer”MCU 只需要查询 Sn_RX_RSR 寄存器看有多少可读字节然后把它读出来。缓冲区块也是通过 BSB 来映射的例如 Socket0 的 TX Buffer 对应 BSB5’b00101RX Buffer 对应 BSB5b00110。读例程时看到地址是 0x0000但控制字节写的是 0x25那就说明这是在往 Socket0 的 TX Buffer 写数据。2.3 SPI 帧格式三次传输才能完成一次访问W5500 的 SPI 访问不是发一个字节就能完成的而是固定三个阶段第一个阶段发送 16 位寄存器地址。第二个阶段发送 8 位控制字节。控制字节的最高位 RWB 用来表示读还是写1 表示读0 表示写接着是地址偏移模式 OM[1:0]00 表示固定地址、01 表示自动递增低位是 BSB 块选择。第三阶段根据读或写发送或接收数据字节。用代码来表达会更直观。下面是最基本的读写函数也是整个例程的地基#include SPI.h #define W5500_CS 5 #define W5500_RST 4 void w5500_write8(uint16_t addr, uint8_t bsb, uint8_t data) { SPI.beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE0)); digitalWrite(W5500_CS, LOW); SPI.transfer16(addr); // 阶段1地址 SPI.transfer((0 7) | (0 5) | (bsb 0x1F)); // 阶段2控制字节写操作 SPI.transfer(data); // 阶段3写数据 digitalWrite(W5500_CS, HIGH); SPI.endTransaction(); } uint8_t w5500_read8(uint16_t addr, uint8_t bsb) { SPI.beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE0)); digitalWrite(W5500_CS, LOW); SPI.transfer16(addr); SPI.transfer((1 7) | (0 5) | (bsb 0x1F)); // 控制字节读操作 uint8_t data SPI.transfer(0x00); // 阶段3读数据 digitalWrite(W5500_CS, HIGH); SPI.endTransaction(); return data; }读操作时第三阶段主机需要发出一个时钟才能把 MISO 上的数据读回来所以SPI.transfer(0x00)里的参数是什么其实无所谓主要是产生时钟。3. 硬件接线与实操准备3.1 引脚连接表我使用的是 ESP32 DevKitC 开发板和一块常见的 W5500 以太网模块它们之间用杜邦线连接。下面这个接线表可以直接照抄W5500 引脚ESP32 GPIO说明SCLKGPIO18SPI 时钟对应默认 VSPI CLKMOSIGPIO23SPI 主机输出接 W5500 数据输入MISOGPIO19SPI 主机输入接 W5500 数据输出SCSGPIO5片选信号低电平有效RSTGPIO4复位引脚低电平复位INTGPIO34中断输出可选轮询模式下可不接VCC3.3VW5500 供电必须 3.3VGNDGND共地需要注意的是ESP32 的 Arduino 环境里默认 SPI 是 VSPI默认引脚就是 SCK18、MISO19、MOSI23SS 引脚默认是 5。用 GPIO5 做 W5500 片选刚好和默认配置一致省去额外指定引脚的麻烦。GPIO34 是输入专用引脚只能做中断输入不能输出。如果你以后想用 W5500 的中断功能这个引脚可以直接读 INT 状态。不用中断的话轮询查询寄存器状态也完全可行。3.2 供电和复位电路容易踩的坑W5500 模块虽然标称 3.3V 供电但启动时电流峰值不低尤其在进行 PHY 自协商时需要比较大电流。很多朋友用 ESP32 开发板的 3.3V 输出直接给 W5500 供电结果出现“能识别芯片版本号但 TCP 连接不稳定”的问题。解决方法很土但有效用外部独立 3.3V 稳压电源给 W5500 供电同时在 VCC 和 GND 之间靠近模块位置加一个 10uF 电解电容和一个 0.1uF 陶瓷电容。复位电路也很关键。W5500 的 RST 引脚是低电平有效复位完成后要保证有足够的延迟时间。我在例程里用 GPIO4 控制复位pinMode(W5500_RST, OUTPUT); digitalWrite(W5500_RST, LOW); // 拉低复位 delay(10); digitalWrite(W5500_RST, HIGH); // 释放复位 delay(200); // 等待芯片完成初始化这里第 10ms 的拉低时间要保证在 W5500 数据手册要求的复位最小脉宽之上。释放复位之后芯片还要做 PHY 初始化和启动我习惯等 200ms 以上再开始 SPI 通信实测更稳。如果复位后立刻读寄存器有时候会读到 0xFF那就是芯片还没准备好。3.3 SPI 引脚软件配置在 Arduino 环境下初始化 SPI 的代码只有几行SPI.begin(); // 使用默认 VSPI 引脚如果要把 CS 引脚设成输出并默认拉高建议在setup()里做pinMode(W5500_CS, OUTPUT); digitalWrite(W5500_CS, HIGH); // 片选默认高电平防止误选中片选信号低电平有效所以平时要拉高只有访问 W5500 时才拉低。实际操作中最常见的低级错误就是片选忘了初始化导致芯片一直处于选中状态SPI 总线冲突读出来的数据全是乱码。4. 例程逐行讲透从复位到 TCP 收发4.1 读版本号验证 SPI 通路先把 SPI 通信这条路打通再谈网卡逻辑。W5500 有一个固定的版本寄存器 VER地址偏移 0x0039属于通用寄存器块读出来的值固定是 0x04。如果读到的不是 0x04说明 SPI 线路、片选、供电或者复位某个环节有问题。验证代码如下void setup() { Serial.begin(115200); SPI.begin(); pinMode(W5500_CS, OUTPUT); digitalWrite(W5500_CS, HIGH); pinMode(W5500_RST, OUTPUT); digitalWrite(W5500_RST, LOW); delay(10); digitalWrite(W5500_RST, HIGH); delay(200); uint8_t ver w5500_read8(0x0039, 0x00); Serial.printf(W5500 Version: 0x%02X\n, ver); if (ver ! 0x04) { Serial.println(SPI 通路异常请检查接线和供电); while (1); } // 继续初始化网络... }如果读到 0x04恭喜SPI 链路通了后面的网络配置才可能有效。这一步是整套程序的第一道安全门我不管做什么板子都会保留这个检查。4.2 软件复位与网络参数写入SPI 通之后先对芯片做一次软件复位把内部状态恢复到已知的干净状态。W5500 的模式寄存器 MR 地址偏移是 0x0000通用寄存器块把 bit7 写成 1 就会触发软件复位。复位后硬件会自动把位清 0所以不需要手动清。w5500_write8(0x0000, 0x00, 0x80); // MR[7] 1软件复位 delay(50);接下来写入 MAC 地址、网关、子网掩码和本机 IP。这些参数分布在通用寄存器里按字节顺序写入GAR 网关地址偏移 0x0001SUBR 子网掩码偏移 0x0005SHAR MAC 地址偏移 0x0009SIPR 本机 IP偏移 0x000F我封装了一个批量写函数void w5500_write_bytes(uint16_t addr, uint8_t bsb, const uint8_t* data, uint16_t len) { SPI.beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE0)); digitalWrite(W5500_CS, LOW); SPI.transfer16(addr); SPI.transfer((0 7) | (1 5) | (bsb 0x1F)); // 写 地址自动递增 for (uint16_t i 0; i len; i) { SPI.transfer(data[i]); } digitalWrite(W5500_CS, HIGH); SPI.endTransaction(); }注意这里控制字节的 OM[1:0] 使用的是 01也就是地址自动递增模式。连续写入 MAC、IP 这类多字节参数时非常方便不用每个字节都重新发一次地址。在setup()里这样配置uint8_t mac[6] {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; uint8_t ip[4] {192, 168, 1, 100}; uint8_t gw[4] {192, 168, 1, 1}; uint8_t mask[4] {255, 255, 255, 0}; w5500_write_bytes(0x0001, 0x00, gw, 4); // 网关 w5500_write_bytes(0x0005, 0x00, mask, 4); // 子网掩码 w5500_write_bytes(0x0009, 0x00, mac, 6); // MAC 地址 w5500_write_bytes(0x000F, 0x00, ip, 4); // 本机 IP很多现成例程会直接调用开源库的wizchip_setnetinfo()函数完成这些写入本质上就是这一串寄存器操作。搞懂了底层再去看库源码就不觉得玄乎了。4.3 Socket 配置与 TCP 连接建立W5500 有 4 个 Socket编号从 0 到 3。我用 Socket0所以所有 Socket 寄存器的 BSB 都是 0x01。TCP 连接的建立分为四步。第一步设置协议模式。Sn_MR 偏移 0x0000写入 0x01 表示 TCP 模式w5500_write8(0x0000, 0x01, 0x01); // Socket0 Sn_MR TCP第二步打开 Socket。向 Sn_CR 偏移 0x0001 写入 OPEN 命令 0x01然后轮询 Sn_SR 偏移 0x0003直到状态变成 0x13SOCK_INIT表示 Socket 打开成功w5500_write8(0x0001, 0x01, 0x01); // Sn_CR OPEN uint8_t status; while ((status w5500_read8(0x0003, 0x01)) ! 0x13) { delay(1); } Serial.printf(Socket0 status: 0x%02X\n, status);这里有个容易犯的错Sn_CR 是命令寄存器写完命令后芯片会立刻执行并自动清零不需要手工清。但你必须等待操作完成尤其是 OPEN、CONNECT、SEND、RECV 这些命令不能连续猛写。轮询状态寄存器是更稳妥的方式。第三步配置目标 IP 和目标端口。目标 IP 写在 Sn_DIPR 偏移 0x000C目标端口写在 Sn_DPORT 偏移 0x0010Sn_DPORT 是 16 位先写高字节再写低字节uint8_t remote_ip[4] {192, 168, 1, 10}; uint16_t remote_port 8080; w5500_write_bytes(0x000C, 0x01, remote_ip, 4); w5500_write8(0x0010, 0x01, (uint8_t)(remote_port 8)); // 端口高字节 w5500_write8(0x0011, 0x01, (uint8_t)(remote_port 0xFF)); // 端口低字节TCP 是有连接协议本地源端口如果没指定芯片会在打开 Socket 时自动分配一个临时端口。如果要指定本地端口可以在 OPEN 前写 Sn_PORT 偏移 0x0004同样是 16 位。第四步发出 CONNECT 命令并等待连接建立。Sn_CR 写 0x04然后轮询 Sn_SR 直到变成 0x17SOCK_ESTABLISHEDw5500_write8(0x0001, 0x01, 0x04); // Sn_CR CONNECT uint32_t timeout millis() 5000; while ((status w5500_read8(0x0003, 0x01)) ! 0x17) { if (millis() timeout) { Serial.println(TCP 连接超时); break; } delay(1); }这个超时很有必要。如果远端 IP 不通、端口没监听CONNECT 命令不会立刻失败而是一直在重发 SYN 包如果不加超时程序会卡死在 while 循环里。我见过不少人调试时以为死机了其实是在等 TCP 超时。4.4 发送数据先写缓冲区再发命令TCP 连接建立后发送数据的过程比写寄存器要多一个步骤那就是先把数据填到 Socket0 的 TX Buffer 里然后发 SEND 命令。发送缓冲区对应的 BSB 是 0x05。因为要写入一大段连续数据控制字节使用自动递增模式。代码是这样的void w5500_send(const char* data, uint16_t len) { uint16_t free_size; free_size (w5500_read8(0x0020, 0x01) 8) | w5500_read8(0x0021, 0x01); // Sn_TX_FSR if (free_size len) { Serial.printf(发送缓冲区不足剩余 %d需要 %d\n, free_size, len); return; } SPI.beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE0)); digitalWrite(W5500_CS, LOW); SPI.transfer16(0x0000); SPI.transfer((0 7) | (1 5) | 0x05); // 写 Socket0 TX Buffer地址自动递增 for (uint16_t i 0; i len; i) { SPI.transfer(data[i]); } digitalWrite(W5500_CS, HIGH); SPI.endTransaction(); w5500_write8(0x0001, 0x01, 0x20); // Sn_CR SEND delay(5); // 等待发送完成也可以轮询 Sn_IR 的 SEND_OK 标志 }注意 Sn_TX_FSR 是 16 位寄存器偏移 0x0020 和 0x0021先读高字节再读低字节。如果你的程序在发送大量数据时发现free_size长时间小于 0x0800说明上次 SEND 没有完成或者有数据残留。调试的时候把这段打印打开会很有帮助。发送命令为什么要等一下因为 SEND 命令触发后W5500 需要时间从 TX Buffer 里取数据、封装 TCP 段、发送并等待 ACK。SEND_OK 中断标志会告诉你这次发送已经完成了但是我实际测试下来简单应用里直接delay(5)也能跑只是吞吐量上不去。如果你想提高效率可以用中断标志代替固定延时。4.5 接收数据查询可读字节再读取接收端逻辑和发送端是对称的。W5500 硬件会把收到的 TCP 数据放在 Socket0 RX Buffer 里BSB 是 0x06。我们只需要查看 Sn_RX_RSR 偏移 0x0026 这个 16 位寄存器就知道当前有多少字节可以读uint16_t w5500_rx_size() { uint16_t size; size (w5500_read8(0x0026, 0x01) 8); size | w5500_read8(0x0027, 0x01); return size; } uint16_t w5500_recv(uint8_t* buf, uint16_t max_len) { uint16_t size w5500_rx_size(); if (size 0) return 0; if (size max_len) size max_len; SPI.beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE0)); digitalWrite(W5500_CS, LOW); SPI.transfer16(0x0000); SPI.transfer((1 7) | (1 5) | 0x06); // 读 Socket0 RX Buffer地址自动递增 for (uint16_t i 0; i size; i) { buf[i] SPI.transfer(0x00); } digitalWrite(W5500_CS, HIGH); SPI.endTransaction(); w5500_write8(0x0001, 0x01, 0x40); // Sn_CR RECV return size; }这里有一个新手特别容易漏掉的细节读取完 RX Buffer 之后必须向 Sn_CR 写 RECV 命令 0x40表示这帧数据已经被主机取走了芯片才能释放相应缓冲区接收新数据。如果忘了写 RECV第二次可能还能读到数据但很快就会感觉接收越来越慢最后完全卡住因为 RX Buffer 被占满了。主循环里可以这样调用uint8_t buf[512]; uint16_t len w5500_recv(buf, sizeof(buf)); if (len 0) { for (uint16_t i 0; i len; i) { Serial.print((char)buf[i]); } Serial.println(); }5. 常见问题与排查技巧实录5.1 版本寄存器一直读不到 0x04这个问题十有八九出在硬件层面。按可能性从高到低排序现象可能原因排查方法一直读到 0xFFCS 没拉低或电平不对确认 CS 引脚初始化为高电平访问时拉低读到 0x00 或随机值MOSI/MISO 接反对照原理图确认接线刚上电第一次读错复位后再读正常复位时间不够RST 释放后 delay 至少 200ms读到的值不稳定供电不足用独立 3.3V 电源并加电容完全无响应SCLK 极性/相位不匹配确认使用 SPI_MODE0 或 SPI_MODE3我调试过一块自制板子怎么读都是 0xFF最后发现是片选引脚被默认初始化成了输出低电平W5500 一直被选中但数据总线被其他 SPI 外设干扰。把初始电平改成高电平问题立刻解决。5.2 能读到版本号但 Ping 不通版本号能读出来说明 SPI 通路没问题问题大概率在网络参数或硬件 PHY 上。先看 RJ45 的网口指示灯正常连接时 LINK 灯应该亮。如果不亮检查网线、对端交换机端口以及 W5500 模块的变压器是否有问题。再看寄存器里的本机 IP 和网关是否写对尤其是字节顺序。W5500 网络参数都是从低字节开始按顺序存储如果你习惯了大端方式写 IP很容易把 192.168.1.100 写成 100.1.168.192。还有一个经典故障写网络参数前没有对芯片做软件复位导致部分参数没有生效。我的建议是每次配置网络前都先软件复位然后再写参数。5.3 TCP 连不上但 ARP 能通如果对端设备能 Ping 通说明二层和三层的链路都通了TCP 连不上基本是端口或者防火墙的问题。先用 PC 上的网络调试工具开一个 TCP 服务器确认端口号没有被占用再检查目标 IP 和端口有没有写反字节序。端口是 16 位值先高后低。如果你写反了比如把端口 8080 的 0x1F90 写成 0x901F对端自然没有程序监听那个端口。另外 W5500 的 Sn_MR 里还有其他配置位比如 No Delayed ACK、IGMP 版本等普通 TCP 连接用不到但如果你改了这些位连接建立后可能出现响应慢或者数据吞吐异常的情况。没有特殊需求就保持 Sn_MR0x01。5.4 能收发小包大包发送失败这个最常见的原因是发送缓冲区大小不够。默认每个 Socket 的 TX Buffer 是 2KB一次发送超过 2KB 数据free_size不够就会直接打印缓冲区不足。解决办法有两个一是应用层把数据分片一次发 1KB 左右二是通过 Socket 寄存器的 Sn_TXBUF_SIZE偏移 0x001F和 Sn_RXBUF_SIZE偏移 0x001E增大缓冲区。比如把 Socket0 的发送缓冲设为 4KB写入 0x04 即可。需要注意的是缓冲区大小配置必须在 Socket OPEN 之前设置否则不会生效。我在实际项目中用的是一组更大的发送缓冲区同时配合轮询 Sn_IR 寄存器里的 SEND_OK 标志来确认上一包发完才发下一包。这样做的好处是可以用足芯片的缓冲区又不会溢出。5.5 ESP32 与 W5500 的共存问题ESP32 本身有 Wi-Fi如果你同时开了 Wi-Fi STA 和 W5500 以太网会遇到“默认路由被抢占”的问题。Arduino 环境下以太网库和 Wi-Fi 库可能会抢默认网关导致某些请求走了 Wi-Fi 而不是有线网络。解决办法很直接在实际项目中明确指定默认网卡比如在 Wi-Fi 连接后调用eth WiFi.eth()接口强制以太网为默认路由或者在初始化顺序上先初始化 W5500 再初始化 Wi-Fi。另外ESP32 的 SPI 和 Wi-Fi 共用部分硬件资源在 Wi-Fi 收发频繁时 SPI 中断可能会被延迟。如果你的项目对以太网实时性要求高建议让 W5500 使用独立的中断引脚并在中断服务函数里只做标志位处理实际的数据读写放在主循环里完成。6. 手写底层之后再回头用库如果你完整跑通了上面这套手写寄存器例程再去用现成的开源库会非常有底气。常用的几个库我都试过。Arduino 环境下最省心的是Ethernet3库它专门针对 W5500 做了优化底层通过 SPI 访问 W5500使用方法类似标准Ethernet库。初始化代码就这么简单Ethernet.begin(mac, ip);然后就可以用EthernetClient来收发数据了。但用了库不意味着可以不懂底层。实际调试中库能帮你把大部分细节藏起来可一旦出问题你还是要回到寄存器层面去排查。所以我建议的学习路径是先花一个下午把底层寄存器操作调通理解每一个 SPI 事务做了什么然后再切换到库把这个手写的例程作为一个“调试探针”保留备用。以后遇到再怪的以太网问题都有底气定位到是 SPI 层、寄存器配置层还是网络协议层的问题。7. 扩展思路有线以太网还能怎么玩W5500 配上 ESP32能做的事远不止建立一个 TCP 连接。我简单列几个我自己做过的方向。一是做本地 Web 服务器。ESP32 和 W5500 配合可以跑一个轻量级的 HTTP 服务器在浏览器里直接监控传感器数据、控制继电器。由于是有线网络响应比 Wi-Fi 方案更稳定不会出现“页面转圈打不开”的情况。二是做远程 OTA 升级。ESP32 支持通过 HTTP 下载固件升级包在有线网络环境下下载速度和稳定性都比 Wi-Fi 好很多。你可以把固件放在局域网服务器里批量给设备升级设备数量多了以后尤其省事。三是做多设备组网。W5500 有 4 个 Socket可以同时建立多个 TCP 连接或 UDP 会话比如一个 Socket 做 MQTT 客户端另一个 Socket 做本地 Modbus TCP 服务器再加上一个用于远程日志上传。这在工业数据采集项目里很常见。四是配合 ESP32 的低功耗特性做休眠唤醒。W5500 在无数据时可以通过 INT 引脚唤醒 ESP32设备平时休眠有网络事件时再醒来处理非常省电。不管你最终要用在哪个场景先把 SPI 底层搞扎实后面都是水到渠成的事。我自己调试 W5500 的经历里最有价值的经验就是“拆开库从寄存器看问题”。很多项目卡了好几天最后都是靠一步一步检查寄存器状态解决的。这篇文章给你的这套代码其实就是一个最小可用的底层调试工具保留好它以后你会感谢现在的自己。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →