ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

STM32H7+W5500以太网方案:从硬件连接到TCP/UDP实战

STM32H7+W5500以太网方案:从硬件连接到TCP/UDP实战 简介这是一份面向嵌入式开发者的STM32H7与W5500以太网驱动移植学习资源适用于工业控制、物联网节点及需要稳定网络连接的实时通信场景。W5500集成以太网MAC/PHY与TCP/IP协议栈通过SPI总线与STM32H7对接资源围绕驱动移植展开涵盖SPI底层驱动、W5500初始化与网络参数配置、Socket创建、数据收发函数、客户端与服务器模式示例以及相关头文件和工程配置。可帮助理解寄存器读写、TCP三次握手与四次挥手、中断响应和DMA传输优化等关键知识点。压缩包为rar格式大小约21.4MB上游未提供文件清单具体文件数及类型分布暂不明确实际内容以包内代码工程为准。目前已有1406人学习适合承担STM32H7网络功能开发任务、希望快速上手W5500的中级嵌入式开发者。1. 为什么是 STM32H7 W5500从一块网卡芯片聊起做嵌入式联网的人迟早会遇到一个尴尬场景STM32H7 这颗芯片本身自带 MAC但想要让它稳定上网还得外挂一颗 PHY、移植 TCP/IP 协议栈、调整内存池稍微复杂一点的 UDP/TCP 收发就能把人折腾到半夜。前两年做一个数据采集设备甲方要求把传感器数据通过以太网上报我在 STM32H7 上跑了 LwIP第一版光内存崩溃就调了三天。后来换成外挂 W5500把协议栈从 CPU 上整个剥掉三天内从画板到 ping 通这个组合就成了我后续做联网设备的默认起手式。STM32H7 以太网 W5500 程序.rar 这类工程之所以被反复下载是因为它绕开了「MCU 上跑协议栈」这条最陡的学习曲线。W5500 是一颗带硬件 TCP/IP 协议栈的以太网芯片MCU 只通过 SPI 读写寄存器ARP、IP、ICMP、TCP、UDP 都在芯片内部完成。适合谁适合把大量精力放在业务逻辑和稳定性的开发者——工业数据采集、设备远程监控、串口转以太网网关这类场景要的不是炫技而是能长时间跑在产线上的可靠性。读完这篇你会清楚整套方案的原理、接线、移植步骤和常见坑点。2. W5500 与 STM32H7 的硬件链路SPI 接口与电平匹配2.1 硬件协议栈的工作原理谁在替你处理 TCP/IP 报文W5500 内部集成了 MAC 和 PHY并在此基础上用逻辑电路实现了完整的 TCP/IP 协议栈。MCU 需要做的不是解析报文而是通过 SPI 接口读写 W5500 内部的寄存器与数据缓冲区。发数据时把应用数据写进 W5500 的 TX Buffer然后发一条 SEND 命令收数据时检测到接收事件后从 RX Buffer 把数据读出来。TCP 的三次握手、重传计时、ACK 应答、分片重组这些逻辑在芯片内部完成不消耗 MCU 的 Flash 和 RAM。STM32H7 在这个方案里的角色被简化成了「搬数据的人」。SPI 的时钟频率、FIFO 深度、DMA 能力都会影响吞吐量但即便不用 DMA、纯轮询写 SPI在 20MHz 的 SPI 时钟下也能轻松跑出几 Mbps 的 TCP 吞吐量足够覆盖绝大多数工业数据采集场景。和 STM32H7 自带 MAC 外部 PHY 的方案相比W5500 的优势不是性能而是确定性和开发效率——省去了 LwIP 的内存池调优也省去了协议栈对 Cortex-M7 缓存一致性的特殊处理。2.2 最小硬件连接七根线加一个复位别小看中断线W5500 与 MCU 的通信最少只需要七根线四根 SPI、一根片选、一根复位、一根中断。注意这里的 SPI 只能做主模式且片选必须用 GPIO 软件控制不能用 STM32H7 的硬件 NSS。W5500 引脚功能STM32H7 示例引脚说明SCSSPI 片选PB7GPIO 输出低有效整个帧传输期间保持拉低SCLKSPI 时钟PF7SPI5_SCK速率建议 20MHz 以下MOSI主出从入PF9SPI5_MOSIMISO主入从出PF8SPI5_MISO注意上拉RST复位PC6低有效需保证上电复位时序INT中断输出PC7下降沿有效建议接外部中断输入3.3V / GND电源3.3V / GND就近放 10uF 0.1uF 去耦电容引脚号以你手头开发板的原理图为准这里给的是 STM32H743 的 SPI5 默认复用关系。有一个细节容易被忽略W5500 的 MISO 引脚在 SPI 通信空闲时是高阻态如果 STM32H7 的 SPI 配置了硬件去拉低 MISO会导致第一个字节读到错误数据。最省心的做法是在 MISO 上加一个 4.7kΩ 上拉电阻或者在 STM32CubeMX 里把 MISO 配置为 GPIO 输入上拉模式。2.3 上电时序与复位引脚W5500 不认 SPI 的常见第一个原因很多人拿到工程直接下载发现 SPI 读写寄存器全是 0xFF第一反应是 SPI 配置错了实际上大概率是复位时序没满足。W5500 要求 VCC 稳定之后RST 引脚保持低电平至少 500us才能完成内部 PHY 校准和寄存器初始化。如果 MCU 的复位引脚和 W5500 的 RST 直接连在一起或者 RST 悬空没有上拉上电瞬间可能出现不可预测的初始化状态。常见做法是给 RST 引脚加一个 10kΩ 上拉电阻和 0.1uF 对地电容形成硬件 RC 上电复位。同时软件上在初始化 SPI 之前先把 RST 拉低、延时 10ms、再拉高、再延时 100ms等 W5500 内部逻辑完全稳定后再访问寄存器。判断 W5500 是否就绪有一个标准动作读版本寄存器正确值应当是 0x04。如果读回来是 0xFF 或 0x00先查复位时序再查 SPI 的极性和相位这比盲目调代码高效得多。3. 把 .rar 里的工程跑起来从解压到 ping 通3.1 工程里真正要关心的文件驱动库、平台适配与业务代码解压一份 STM32H7 W5500 的 .rar 工程目录往往混合着 HAL 库、驱动中间层和用户代码。不要去翻每一行先找三类文件W5500 协议栈驱动、平台适配层、网络配置头文件。最常见的是这套结构w5500.c / w5500.h 负责寄存器读写socket.c / socket.h 负责封装 Socket APIwizchip_conf.c 里是协议栈入口还有你自己写的 spi_stm32h7.c 用来对接 STM32H7 的 SPI 外设。需要改的核心只有平台适配层和网络参数配置。协议栈驱动是标准的不要动。你自己写的 SPI 读写函数需要满足驱动库要求的三个原语CS 控制、SPI 单字节收发、可能还有 SPI 高速连续读写。驱动库在读写 RX/TX Buffer 时会用你提供的原语一次搬几十到几百字节如果你的 SPI 读写函数里面每个字节都重新配置一次时钟速度会慢得离谱。我一般会把 SPI 初始化放在一个单独的函数里只做一次然后通过一个纯裸的收发函数供驱动调用。3.2 修改平台适配层SPI 时钟极性与 W5500 帧格式W5500 支持 SPI Mode 0CPOL0, CPHA0和 Mode 3CPOL1, CPHA1绝大多数官方例程默认 Mode 0。你用 STM32CubeMX 配置 SPI 时选择低速主模式、8 位数据长度、MSB First极性选 Low相位选 1Edge片选选 Software就能和 W5500 对上。/* stm32h7_w5500_spi.c */ #include main.h static SPI_HandleTypeDef hspi_w5500; void w5500_spi_init(void) { hspi_w5500.Instance SPI5; hspi_w5500.Init.Mode SPI_MODE_MASTER; hspi_w5500.Init.Direction SPI_DIRECTION_2LINES; hspi_w5500.Init.DataSize SPI_DATA_SIZE_8BIT; hspi_w5500.Init.CLKPolarity SPI_POLARITY_LOW; /* CPOL 0 */ hspi_w5500.Init.CLKPhase SPI_PHASE_1EDGE; /* CPHA 0 */ hspi_w5500.Init.NSS SPI_NSS_SOFT; /* CS 用 GPIO 控制 */ hspi_w5500.Init.BaudRatePrescaler SPI_BAUDRATEPRESCALER_16; /* 约 13.5MHz 216MHz */ hspi_w5500.Init.FirstBit SPI_FIRSTBIT_MSB; if (HAL_SPI_Init(hspi_w5500) ! HAL_OK) { while (1); /* 初始化失败直接卡住便于定位 */ } } static void spi_tx_byte(uint8_t data) { HAL_SPI_Transmit(hspi_w5500, data, 1, HAL_MAX_DELAY); } static uint8_t spi_rx_byte(void) { uint8_t rx 0xFF; HAL_SPI_Receive(hspi_w5500, rx, 1, HAL_MAX_DELAY); return rx; }这里每个字节都调用一次 HAL_SPI_Transmit 其实不是最优的但胜在直观可靠。HAL_SPI_Transmit 在 H7 上每次调用有固定的状态机开销实测在 13.5MHz 下达到 3Mbps 左右的吞吐量没有问题。W5500 的 SPI 帧由三部分组成2 字节地址段、1 字节控制段、N 字节数据段。地址段指定寄存器偏移控制段里的 bit5 表示读还是写bit4-3 选择访问的块——通用寄存器、Socket 寄存器、TX Buffer 或 RX Bufferbit2-0 设为 000 表示可变数据长度模式。以下是我在工程里实际使用的帧读写函数可以直接替换驱动库底层的 SPI 原语/* W5500 片选控制换到你的工程时把引脚宏替换成实际定义的 GPIO */ #define W5500_CS_LOW() HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_RESET) #define W5500_CS_HIGH() HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_SET) void w5500_read_frame(uint32_t addr, uint8_t *buf, uint16_t len) { uint8_t ctrl (((addr 16) 0x03) 3) | (1 5); W5500_CS_LOW(); spi_tx_byte((uint8_t)(addr 8)); spi_tx_byte((uint8_t)(addr 0xFF)); spi_tx_byte(ctrl); /* 读指令 块选择 变长模式 */ while (len--) { *buf spi_rx_byte(); } W5500_CS_HIGH(); } void w5500_write_frame(uint32_t addr, uint8_t *buf, uint16_t len) { uint8_t ctrl (((addr 16) 0x03) 3) | (0 5); W5500_CS_LOW(); spi_tx_byte((uint8_t)(addr 8)); spi_tx_byte((uint8_t)(addr 0xFF)); spi_tx_byte(ctrl); while (len--) { spi_tx_byte(*buf); } W5500_CS_HIGH(); }注意 ctrl 字节的低三位固定为 000这是 VDM 变长数据模式。块选择位来自 addr 的高位这是在驱动库里约定好的 32 位地址编码规则。片选必须在整个帧传输期间保持低电平不能每个字节都拉一次 CS否则 W5500 会认为每次都是新的事务。如果你发现读回来的数据只有第一个字节正确、后续全是 0xFF九成是片选时序问题。3.3 网络参数初始化MAC、IP、掩码、网关缺一不可把 W5500 驱动跑起来之后下一步是配置网络参数。官方驱动的做法是先给每个 Socket 分配 TX/RX 缓冲区大小再写入 MAC、IP、掩码和网关。注意 MAC 地址不要用示例里的默认值也不要和局域网里其他设备冲突否则会出现间歇性 ARP 失败。这里给出最小初始化代码/* 网络参数结构体 */ wiz_NetInfo g_net_info { .mac {0x02, 0x00, 0x00, 0x12, 0x34, 0x56}, .ip {192, 168, 1, 233}, .sn {255, 255, 255, 0}, .gw {192, 168, 1, 1}, .dns {192, 168, 1, 1}, .dhcp NETINFO_STATIC }; static uint8_t g_tx_buf[16 * 1024]; static uint8_t g_rx_buf[16 * 1024]; void network_init(void) { uint8_t txsize[8] {16, 0, 0, 0, 0, 0, 0, 0}; /* Socket0 独占 16KB TX */ uint8_t rxsize[8] {16, 0, 0, 0, 0, 0, 0, 0}; /* Socket0 独占 16KB RX */ /* 复位时序拉低保持 10ms再拉高等待内部逻辑就绪 */ HAL_GPIO_WritePin(GPIOC, GPIO_PIN_5, GPIO_PIN_RESET); HAL_Delay(10); HAL_GPIO_WritePin(GPIOC, GPIO_PIN_5, GPIO_PIN_SET); HAL_Delay(100); wizchip_init(txsize, rxsize, g_tx_buf, g_rx_buf); wizchip_setnetinfo(g_net_info); /* 读回来核对避免结构体字节序导致地址写反 */ wiz_NetInfo verify; wizchip_getnetinfo(verify); }txsize 数组的单位是 KB16 表示 16KB。W5500 芯片内部总共有 32KB 缓冲16KB 给 TX、16KB 给 RX所以 g_tx_buf 和 g_rx_buf 各分配 16KB。如果后续要开多个 Socket需要按比例拆分这些缓冲区每个 Socket 都要有独立的 TX 和 RX。wizchip_init 的参数顺序是 txsize、rxsize、txbuf、rxbuf很多人第一次写反导致后续 socket() 调用直接返回错误这一行值得反复核对。完成以上两步后编译下载PC 端配置同一网段的静态 IP比如 192.168.1.100ping 192.168.1.233。能通说明硬件链路、SPI、寄存器收发都正常ping 不通不要急着看代码先用示波器量 SCLK 引脚有没有时钟输出再量 RST 引脚电平是否被 W5500 拉低。硬件问题占了首轮调试的七成。4. 关键参数与调试技巧从 ping 通到 TCP/UDP 收发4.1 Socket 初始化与监听TCP 服务端连不上的常见原因W5500 的 Socket 操作流程和 BSD Socket 非常接近先 socket() 创建连接设置协议模式和本地端口然后 listen() 或 connect()。对 TCP 服务端来说最容易翻车的点是 socket() 返回成功就直接 while 循环里写 send/recv没有检查 Socket 状态。W5500 不会自己进入监听状态你必须显式调用 listen()并且在每次 Accept 之前确认状态寄存器已经是 SOCK_ESTABLISHED。#define TCP_SOCKET 0 void tcp_server_task(void) { if (socket(TCP_SOCKET, Sn_MR_TCP, 6000, 0) ! SOCK_OK) { return; /* Socket 打开失败多半是缓冲区分配不足 */ } listen(TCP_SOCKET); while (1) { switch (getSn_SR(TCP_SOCKET)) { case SOCK_ESTABLISHED: { uint8_t buf[1024]; int16_t len recv(TCP_SOCKET, buf, sizeof(buf)); if (len 0) { send(TCP_SOCKET, buf, len); /* 回显 */ } break; } case SOCK_CLOSE_WAIT: /* 对端关闭必须主动 disconnect 再 close否则 Socket 卡死 */ disconnect(TCP_SOCKET); close(TCP_SOCKET); break; case SOCK_CLOSED: /* Socket 被释放后重新监听 */ socket(TCP_SOCKET, Sn_MR_TCP, 6000, 0); listen(TCP_SOCKET); break; default: break; } } }socket() 的第三个参数 6000 是本地端口第四个参数 0 是标志位通常不用。这里的状态机是我在工程里一直沿用的写法核心思想是每个 case 都要有对应的处置动作不能只处理 SOCK_ESTABLISHED。如果 TCP 客户端连不上先读一下 getSn_SR() 返回什么值一直停在 SOCK_INIT 说明 listen 没生效停在 SOCK_CLOSED 说明 Socket 被断开后没有重新初始化。端口被占用时 socket() 本身就会失败这时检查是不是有上一个连接没有 close。4.2 UDP 收发不需要握手但要注意 IP 与端口的来源UDP 的 Socket API 更简单因为不需要 listen 和 accept。调用 socket() 指定 Sn_MR_UDP 和端口后直接用 recvfrom 和 sendto。一个容易忽略的点sendto 必须传入对端的 IP 和端口这个信息只能从 recvfrom 返回的参数里拿不能自己编。如果你的设备需要主动向服务器发送数据目标 IP 和端口写死没问题如果是应答式协议请一定保存 recvfrom 回调里返回的 remote_ip 和 remote_port。#define UDP_SOCKET 1 void udp_echo_task(void) { uint8_t buf[512]; uint8_t remote_ip[4]; uint16_t remote_port; if (socket(UDP_SOCKET, Sn_MR_UDP, 6001, 0) ! SOCK_OK) { return; } while (1) { int16_t len recvfrom(UDP_SOCKET, buf, sizeof(buf), remote_ip, remote_port); if (len 0) { sendto(UDP_SOCKET, buf, (uint16_t)len, remote_ip, remote_port); } } }recvfrom 的返回值是收到的数据长度失败时返回 SOCKERR_SOCKINVALID 这类负数。注意 remote_ip 是一个 4 字节数组remote_port 是 16 位无符号整数这两个参数在 recvfrom 里是输出型参数。UDP 模式下如果长时间没有任何数据Socket 会保持打开状态不需要像 TCP 那样处理断开事件所以上面的代码可以一直轮询。实测这个回显逻辑在 13.5MHz SPI 下 UDP 吞吐量约 4Mbps远低于网络带宽瓶颈但做轻量级设备控制足够。4.3 中断与轮询的选择什么时候用回调什么时候用查询W5500 有一个 INT 输出引脚当 Socket 发生接收事件、连接建立、断开等状态变化时INT 会拉低。两种处理方式各有适用场景中断方式响应快但你在回调函数里不能做耗时操作否则会阻塞其他中断轮询方式实现简单但 CPU 需要频繁读寄存器。我的习惯是单 Socket 且数据流量不高的场景直接用 while 循环轮询 Socket 状态代码简单不容易出错多 Socket 或者对响应延迟有要求的场景把 INT 接到外部中断中断服务函数里只置一个标志位实际收发放到主循环里做。判断中断源的方式是读 Sn_IR 寄存器比如 Sn_IR_RECV 表示有数据到达处理完后写回该寄存器清除标志。如果不清除INT 引脚会一直保持低电平后续中断再也进不来。这个清标志的操作必须放在读取数据之前还是之后我的做法是先读数据再清标志因为清完标志后如果又有新数据到达会重新置位。如果先清标志再读数据数据读走之前新数据到了标志位会被置上但你可能读漏一次。顺序反了就是偶发丢包的来源。5. STM32H7 W5500 避坑指南5 条值得记录的踩坑实录5.1 现象能 ping 通但 TCP 连接总是超时现象是最典型的PC 能 ping 通开发板但用网络调试助手连接 TCP 端口时一直没有回应。原因ping 走的是 ICMP 协议W5500 硬件协议栈会自动回包但这并不代表你的 Socket 已经被正确配置。应用层没有调用 socket()、listen()或者 socket 打开失败后没有做任何处理都会导致端口没有任何响应。解决先在初始化代码里检查 socket() 的返回值确保等于 SOCK_OK然后打印 getSn_SR() 的状态值如果一直是 SOCK_INIT 说明 listen() 没有生效。另外一个常见问题socket() 里填的端口号是主机字节序还是网络字节序在 W5500 驱动里端口号直接传 uint16 即可不要手动调用 htons否则本来监听 6000 端口实际却变成了 0x1770 反转后的值PC 端怎么连都连不上。5.2 现象SPI 读回全是 0xFF版本寄存器读到 0xFF现象调用 wizchip_init 之前的读版本操作返回 0xFF或者读 MAC 地址全空。原因SPI 的极性和相位与 W5500 不匹配尤其很多人移植时直接复制了之前驱动 OLED 或 Flash 的 SPI 配置。W5500 支持 Mode 0 和 Mode 3但如果你用的是 Mode 1 或 Mode 2数据会在错误的边沿被采样读回来的全是 1。解决确认 STM32CubeMX 里 SPI 设置为 CPOLLow、CPHA1Edge即 Mode 0。如果你在别的芯片上跑过 W5500 且当时用的是 Mode 3那也要和现在的配置对齐不要混用。验证手段永远先读 VERSION 寄存器读到 0x04 再继续往下调这是最省时间的判断标准。5.3 现象数据偶发错乱TCP 连接频繁断开现象设备长时间运行后收到的数据出现字节错位甚至 TCP 连接直接断开重连。原因多半是中断处理函数里做了过重的工作。W5500 的 INT 引脚下降沿触发后如果你在中断里直接调用 recv() 并且 recv() 内部又通过 SPI 读取大量数据整个 SPI 传输期间其他中断会被阻塞此时又有新数据到达导致 INT 引脚拉低但标志位还没清除事件就丢了。解决中断服务函数里只做一件事——置一个 volatile 标志位主循环检测到标志后调用数据处理函数处理完毕再清除 Sn_IR。另一个隐蔽的坑是 recv() 读完之后没有正确回写 Sn_RX_RD 寄存器导致 W5500 认为数据没被读走缓冲区被占满后停止接收表现就是连接还在但数据不再更新。建议读完一段数据后立即调用 setSn_RX_RD() 和 command(Sn_CR_RECV) 收尾。5.4 现象换一块开发板就失联甚至第一次上电就失败现象同一个程序在这块板子上跑得好好的换一块同型号板子就不通或者重新上电后进入不可用状态。原因W5500 的 RST 引脚悬空或者被板上的电容影响导致复位信号不完整。如果 RST 引脚没接上拉电阻MCU 引脚默认输入状态时电平不确定W5500 可能一直处于复位模式。解决确认 RST 引脚接了 10kΩ 上拉到 3.3V并并联 0.1uF 电容到地。软件上在 SPI 初始化之前执行一次硬复位拉低 10ms拉高再等 100ms。如果你用的板子把 W5500 的 RST 接到了 MCU 的复位引脚上那么 MCU 每次复位都会带动 W5500 复位这没问题但要确保 MCU 的复位时间足够长否则 W5500 还没完成内部初始化MCU 就开始访问 SPI 了。5.5 现象ARP 解析偶尔失败ping 时而通时而不通现象设备刚上电时 ping 不通等几秒又通了或者局域网内多台设备同时出现时ARP 表现不稳定。原因MAC 地址冲突。很多人下载的示例工程里 MAC 地址是写死的同一个值比如 0x00 0x08 0xDC 开头的那串两台设备在同一局域网就会出现 ARP 缓存互相覆盖表现就是时通时断。解决为每台设备生成唯一 MAC。STM32H7 内部有 96 位唯一 IDUID取低 3 字节填充到 MAC 地址的末三位前三位保持厂商前缀不变。这样即使几十台设备同时接入同一个交换机MAC 冲突的概率也极低。顺带提醒改 MAC 后需要重新上电才生效W5500 只在初始化时把 MAC 写入 SHAR 寄存器。6. 进阶玩法把 W5500 从能用用到顺手W5500 的入门玩法是数据回显但真正决定这个方案价值的是三件事多 Socket 的缓冲区切割、DHCP 自动获取 IP、以及把 W5500 做成固件升级通道。多 Socket 的缓冲区分配很容易理解W5500 总共有 16KB TX 和 16KB RX你需要通过 txsize 和 rxsize 数组把它们分配给 8 个 Socket。以下是我常用的分配策略Socket 数量TX 大小RX 大小适用场景1 个16KB16KB大包传输TCP 高速上传2 个8KB / 8KB8KB / 8KB一个 TCP 一个 UDP4 个4KB / 4KB / 4KB / 4KB同左多路传感器上报8 个2KB / 2KB ...同左长时间保持多个 TCP 连接注意一个 Socket 的 TX 和 RX 大小可以不同但芯片正常工作时不建议出现 0KB 的情况否则对应 Socket 打开会失败。分配完缓冲区后记得重新调用 wizchip_init并且不能在程序运行中途随意改只能复位后重新初始化。DHCP 功能可以省去手动配置静态 IP 的麻烦。驱动库里提供了 DHCP 客户端初始化时把 g_net_info 的 dhcp 字段设为 NETINFO_DHCP然后周期调用 DHCP_run() 直到分配成功。实际项目里我一般给设备一个默认静态 IP同时保留 DHCP 模式开关通过拨码或配置项切换这样既能在开发时快速调试又能在现场免配置部署。我最近做的一个项目中还把 W5500 的 TCP 服务端接到了 IAP 升级流程里设备启动时进入一个短暂窗口PC 端通过 TCP 连接把 bin 文件分帧发给设备设备收到后写入外部 SPI Flash全部完成后跳转到应用区实现远程升级。W5500 在这里比 MCU 自带 MAC 方案有天然优势——Bootloader 不需要引入协议栈只依赖一个 Socket API 就能实现文件接收代码量少风险低。这个方向适合有产品化需求的开发者重点投入一个是批量的设备离线升级另一个是设备日志远程抓取两者的技术底座都是这套 Socket API。如果非要说一条血泪经验那就是先把 VERSION 寄存器读出来再写业务代码先 ping 通再写收发逻辑先调好状态机再开优化。这十几年做以太网设备的经验告诉我W5500 的坑基本都在硬件时序和初始化顺序上软件本身反而异常稳定。按照上面的步骤走你也能少走那些我已经替你们蹚过的弯路希望帮到你。本文还有配套的精品资源点击获取
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表