资讯动态

STM32F103与W5500 TCP通信例程:SPI驱动与硬件协议栈实战

发布时间:2026/10/19 17:13:16 来源:尧图企业网站定制
简介面向STM32F103与W5500的嵌入式TCP通信开发这份rar压缩包提供可直接移植的完整工程例程适合物联网设备网络通信的初学者与开发者参考。工程基于SPI接口驱动W5500包含TCP客户端与服务器模式实现涵盖网络参数配置、三次握手建立连接、数据收发及中断处理等关键环节可帮助理解硬协议栈芯片与MCU的配合方式。压缩包共183个文件以C源码与头文件为主另有uvprojx工程配置、axf/hex编译输出及清理脚本整体大小约3.48MB便于直接编译烧录调试。资源发布以来已有371人浏览学习对于希望快速入门STM32W5500网络编程的开发者可作为一套结构清晰、可复用的参考例程。1. 为什么是 stm32f103 W5500 而不是 STM32 自带的 MAC 控制器如果你做过带网口的单片机项目大概率被 ETH 接口、RMII 引脚和 PHY 芯片的寄存器配置折磨过。STM32F103 内部虽然集成了以太网 MAC 控制器但要让它在板上跑起来你得外接一颗 PHY 芯片比如 LAN8720A还得把 RMII 的 50MHz 参考时钟、CRS/DV 引脚、MDIO 管理接口全部对上号。F103 的 ETH 模块对 PCB 布线敏感对时钟要求也苛刻BGA 封装的 PHY 芯片焊接难度再叠一层整套下来光是点亮链路就要折腾小半个月。W5500 走的是完全不同的路子它把 TCP/IP 协议栈、MAC 和 PHY 全部封装进一颗芯片里MCU 只负责往 SPI 接口丢数据、读数据。W5500 内部有 32KB 收发缓冲区支持 8 个 Socket 同时独立工作TCP、UDP、ICMP、ARP、DHCP 这些协议栈逻辑全部由硬件完成你不需要在 F103 上移植 lwIP、不需要处理 TCP 时序、不需要关心 ACK 重传和滑动窗口。简单说F103 只做应用层的打包和解包网络协议栈的黑匣子交给 W5500。对于中小数据量的设备联网、数据上报、远程配置这种典型场景这套组合比 F103RMIIPHY 甚至 F103外置 MACPHY 的组合省心得多出问题也好定位怀疑协议栈就查 W5500 寄存器怀疑 SPI 就抓 MOSI 波形。这份资源解决的就是这个需求一份给你跑通的 STM32F103 W5500 TCP 例程从 SPI 引脚初始化到 TCP Client 连接服务器从数据收发循环到 Socket 断开重连所有关键寄存器配置和收发缓冲区的读写逻辑都放在工程里。适合做物联网网关、串口转以太网模块、工业数据采集上报的开发者——你不想从头啃 800 页数据手册只想尽快先把链路跑起来再按自己的协议格式改数据这个例程就是入口。2. W5500 SPI 接口与内存架构先把寄存器模型和收发缓冲区的关系理清2.1 为什么是 SPI 而不是并行总线引脚、速率和并发三条线W5500 支持 SPI 和 8 位并行总线两种模式。F103 的 FSMC 接口可以挂并行总线但片选时序、地址线分配、读写使能这些都要单独配置占用 GPIO 太多。SPI 模式下最少只需要 4 根线SCLK、MOSI、MISO、SCSF103 的硬件 SPI 外设就能胜任速率撑到 SPI1 的 18MHz 也没问题——W5500 手册标注 SPI 最大支持 33.33MHzF103 的主频反而成了瓶颈。这个例程用的是软件片选普通 GPIO 控制 SCS硬件 SPI1 做数据通道这样片选时序可以完全由代码控制不会跟别的外设抢 SPI 总线。W5500 的地址空间是 16 位寻址分两大块寄存器区和 TX/RX 缓冲区区。寄存器区控制收发状态、Socket 模式、中断标志位、重传计数等缓冲区区则是每个 Socket 独立的收发通道数据从这里进出。SPI 帧格式固定为三段16 位地址 8 位控制字节 数据长度按控制字节决定。被地址、控制位和片选时序搞晕的开发者不在少数我第一次自己写底层驱动就是漏了控制字节里那个块选择位导致读的一直是物理寄存器不是 Socket 寄存器。2.2 SPI 帧结构解析地址、控制字节和读写时序W5500 的 SPI 读时序分成三步先发送 2 字节目标地址高字节在前再发 1 字节控制码控制码的低 5 位是高 5 位地址的补充确切说控制字节的 bit[2:0] 作为地址的第 1315 位中间还有 2 位块选择bit[4:3]bit[5] 固定为 1SPI 读操作时该位是 0写是 1bit[7:6] 是 00 的保留位。真正决定读写方向的不是 MOSI 上的电平而是控制字节的 R/W 位。写入时保持一整段连续时序中间不能把片选拉高否则 W5500 会认为当前传输结束。例程的底层驱动文件通常提供两个核心函数W5500_Write_Register和W5500_Read_Register它们的封装都围绕这个三段式帧结构展开。SPI 传输完成后必须无条件读取一次 MISO 数据否则缓冲区的读指针不回退下一次读取会错位。uint8_t W5500_Read_Byte(uint16_t addr) { uint8_t control (addr 8) 0x03; // bit[9:8] control | (addr 6) 0x04; // bit[10] 填入控制字节 bit2 control | 0x08; // 块选择物理寄存器区 control | 0x04; // SPI 读操作R/W0但这里注意 W5500 的读写位在 bit2 // 实际标准写法控制字节 (addr 0x03) 2 | (BS) 4 | 0x00 // 上面的示意写法只是示意标准见下方 }上面这段是个示意请忽略正确的控制字节公式要按 W5500 数据手册 4.3 节的表来算。最稳妥的做法是打开例程里的w5500_driver.c找到W5500_Write_Opcode函数里面ctrl_byte (addr_offset 2) | ((mode 0x03) 4) | (rw ? 0x04 : 0x00)这种写法就对了。这里的addr_offset是地址的低 10 位因为 W5500 地址是 16 位其中高 6 位固定为 0 或块选择位控制字节的 bit[3:2] 放地址的第 9:8 位bit[1:0] 放第 11:10 位……不同手册画法不同对照你自己拿到的那版 datasheet。最容易翻车的地方就是块选择位bit[4:3] 两位是块选择00 表示物理寄存器01 表示 Socket 寄存器10 表示 TX 缓冲区11 表示 RX 缓冲区。这四个块要是选错读回来的数据永远是 0xFF 或者 0x00排查半天也可能查不到。2.3 内存架构8 个 Socket 怎么瓜分 32KB 缓冲W5500 的 32KB 缓冲区分成 TX 和 RX 两区每个 Socket 可以在初始化时通过寄存器设置自己的缓冲区大小。例程里一般把 Socket 0 的 TX/RX 缓冲设为 2KB其余 Socket 各分到 1KB 或干脆关掉。这里的关键是把 W5500 的 Memory 分配看作「硬件管理的内存池」你要操作的是一块块的区域不是连续线性空间。读写数据时你得记录每个 Socket 的读写指针写到缓冲区顶部时回卷wrap-around这就是网上说的「环形缓冲」。例程里TX_WR_PTR和RX_RD_PTR是核心变量所有收发流程都围绕这两个指针展开。内存分配要在打开 Socket 之前做完一旦 Socket 进入了SOCK_ESTABLISHED状态就不能再改缓冲区大小否则数据可能写到别的 Socket 的缓冲里去。例程初始化里分配完 MEM 寄存器后就不再动它Sn_MSSR里设了 1460 字节的 MSS最大分段大小这个值决定了 TCP 数据报文的分段上限服务器端抓包时如果看到大于 1460 的包那基本可以断定是你这个值没配好。3. 驱动移植与初始化从接线到寄存器配置的完整链路3.1 引脚分配与硬件接线表例程配套的硬件参考接线是 F103 最小系统板 W5500 模块SPI1 主模式。用的引脚一般是这样信号STM32F103 引脚W5500 模块引脚说明SCLKPA5SCLKSPI1 时钟最高 18MHzMOSIPA7MOSI主出从入MISOPA6MISO主入从出SCSPA4SCS软件片选低有效RSTPB0RSTn硬件复位低有效INTPB1INTn中断请求引脚可不用RST 引脚一定要用软件 GPIO 控制不要直接接电源或者只接上拉电阻——程序启动时先拉低 RST 至少 10us让 W5500 完成内部上电复位再拉高并延时 50ms 等待 PHY 稳定。INT 引脚如果不用中断模式可以悬空例程是轮询方式所以 INT 没参与逻辑。电源部分 W5500 模块通常板载 3.3V 稳压但要注意模块上的电流需求F103 的 3.3V 输出能力一般只有几百 mA如果模块带网络变压器建议独立供电否则网络握手时电压跌落会导致偶发断连这个坑后面还会提。3.2 SPI 初始化代码频率、极性和相位对齐F103 的 SPI1 挂在 APB2 总线上主频 72MHz 时 SPI 时钟可以分频到 18MHzPCLK2 72MHz除数 4。W5500 要求 SPI 模式 0 或模式 3 都可以但例程固定用模式 0CPOL0CPHA0即时钟空闲为低数据在第一个边沿采样。如果你用的是国产替代的 SPI 主控或者 F103 的 SPI 复用引脚被别的外设占用务必确认极性和相位否则读回来的寄存器全是 0xFF 或者读到半字节错位的数据。SPI_InitTypeDef SPI_InitStructure; SPI_InitStructure.SPI_Direction SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode SPI_Mode_Master; SPI_InitStructure.SPI_DataSize SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL SPI_CPOL_Low; SPI_InitStructure.SPI_CPHA SPI_CPHA_1Edge; SPI_InitStructure.SPI_NSS SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler SPI_BaudRatePrescaler_4; SPI_InitStructure.SPI_FirstBit SPI_FirstBit_MSB; SPI_Init(SPI1, SPI_InitStructure); SPI_Cmd(SPI1, ENABLE);SPI_NSS_Soft这个设置很关键它让 NSS 引脚不起硬件作用片选全部交给 GPIO 的软件控制这样你在多机和单机复用 SPI 总线时不会因为 NSS 被拉到低电平而出错。SPI_BaudRatePrescaler_4把 SPI 时钟降到 18MHz这个值是理论稳妥值实际调试时如果出现偶发 CRC 错误W5500 没 CRC而是数据错位可以降到 8 分频9MHz 速率绝大多数问题都能消失。SPI 时钟频率不要追求极限W5500 的 33MHz 是芯片极限但你的 PCB 走线不可能零阻抗留出裕量是常规操作。3.3 W5500 寄存器初始化序列W5500 上电后默认所有 Socket 是关闭的你必须依次完成以下初始化流程写模式寄存器MR设置 RST 位等待自复位完成关闭所有 SocketSn_CR 写 CLOSE设置网关 IPSHAR、GAR 寄存器设置子网掩码SUBR设置 MAC 地址SHAR然后设置每个 Socket 的 TX/RX 缓冲区大小Sn_TXBUF_SIZE、Sn_RXBUF_SIZE。这个顺序不能颠倒——先配网络层再配传输层缓冲分配要在 Socket 使能之前完成否则 Socket 状态寄存器会出现不可预测的值。void W5500_Init(void) { W5500_Write_Register(MR, 0x80); // MR: RST 位软件复位 Delay(50); // 等待复位完成至少 50ms W5500_Write_Register(GAR, 网关地址, 4); // 网关 W5500_Write_Register(SUBR, 子网掩码, 4); // 子网掩码 W5500_Write_Register(SHAR, MacAddr, 6); // MAC 地址 // 配置 Socket 0 的 TX/RX 缓冲单位 KB W5500_Write_Register(Sn_TXBUF_SIZE(0), 0x04); // 4KB W5500_Write_Register(Sn_RXBUF_SIZE(0), 0x04); // 4KB W5500_Write_Register(Sn_MSSR(0), 0x05B4); // MSS1460 }MR寄存器的0x80是软复位位写 1 后 W5500 内部复位所有寄存器复位完成后该位自动清零。这里有个细节复位之后所有寄存器回到默认值所以必须先复位再写任何配置否则你写的配置在复位瞬间被清掉。延时 50ms 是参考 W5500 数据手册的电源稳定时间实际硬件如果供电纹波大建议延长到 100ms。Sn_MSSR写入的是 0x05B4十进制 1460这是以太网 TCP 的标准 MSS如果你的服务器端 MSS 要求更小抓包发现握手时报文 MSS 不对可以改这里但一般不动。4. TCP Client 连接、数据收发与生命周期管理4.1 Socket 打开和连接服务器的流程初始化完寄存器后进入 TCP Client 连接流程。W5500 的 Socket 操作核心是命令寄存器 Sn_CR你写一个命令芯片执行完把 Sn_IR 的标志位置 1然后才能写下一个命令。不开中断的话你得在主循环里轮询 Socket 状态寄存器 Sn_SR状态机从 SOCK_INIT → SOCK_SYNSENT → SOCK_ESTABLISHED如果在 CONNECT 命令后 3 秒内没到 ESTABLISHED基本就是网络不通或者服务器没监听需要重新走 CLOSE 流程。uint8_t W5500_Socket_Connect(uint8_t sock, uint8_t *ip, uint16_t port) { W5500_Write_Register(Sn_MR(sock), 0x01); // 1 TCP 模式 W5500_Write_Register(Sn_CR(sock), 0x01); // OPEN 命令 while (W5500_Read_Register(Sn_SR(sock)) ! SOCK_INIT) { // 等待 Socket 进入 INIT 状态超时判断可加 } W5500_Write_Register(Sn_DIPR(sock), ip, 4); W5500_Write_Register(Sn_DPORT(sock), port, 2); W5500_Write_Register(Sn_CR(sock), 0x04); // CONNECT 命令 timeout 3000; // 毫秒 while (timeout--) { if (W5500_Read_Register(Sn_SR(sock)) SOCK_ESTABLISHED) return SUCCESS; if (W5500_Read_Register(Sn_IR(sock)) 0x04) // CONNECT 失败中断标志 break; } W5500_Write_Register(Sn_CR(sock), 0x08); // DISCON 命令 W5500_Write_Register(Sn_CR(sock), 0x18); // CLOSE 命令 return FAIL; }Sn_MR的低 4 位决定协议模式0x01 是 TCP0x02 是 UDP0x03 是 MACRAW。例程把 Socket 0 配成 TCP其余 Socket 如果没用到就全部 CLOSE 掉这样内存管理简单。CONNECT 命令发出后W5500 内部会自动处理 SYN 重传重传次数由 Sn_RCR 寄存器决定默认是 8 次。如果你在局域网里连一个不存在的 IP会在 38 秒内收到Sn_IR的 CONNECT 失败中断标志这时必须用 DISCON CLOSE 组合把 Socket 状态清干净否则下一次 CONNECT 会在一个半开状态上执行基本上必然失败。4.2 发送数据TX 缓冲区的写入逻辑W5500 发送数据的核心是往 TX 缓冲区写数据然后写 Sn_CR 的 SEND 命令。TX 缓冲区的地址计算稍显繁琐你要先读 Sn_TX_WR写指针把数据写到 TX 缓冲区对应位置写完后 Sn_TX_WR 数据长度最后命令 SEND。如果写指针到达缓冲区末尾你配置的 4KB 边界要回卷从头写这个回卷逻辑是经常被忽略的点。uint16_t W5500_Send_Buffer(uint8_t sock, uint8_t *buf, uint16_t len) { uint16_t tx_wr W5500_Read_Register16(Sn_TX_WR(sock)); uint16_t tx_base sock * 2 2; // 这个公式不同例程可能不同看你的配置 uint16_t free_size W5500_Get_TX_Free_Size(sock); if (free_size len) { return 0; // 缓冲区不足要等 TCP 确认回收空间 } if (tx_wr len (tx_base 4) * 1024) { // 回卷写到缓冲区末尾剩余部分从头写 uint16_t part1 (tx_base 4) * 1024 - tx_wr; W5500_Write_TX_Buffer(sock, tx_wr, buf, part1); W5500_Write_TX_Buffer(sock, tx_base * 1024, buf part1, len - part1); } else { W5500_Write_TX_Buffer(sock, tx_wr, buf, len); } W5500_Write_Register16(Sn_TX_WR(sock), tx_wr len); W5500_Write_Register(Sn_CR(sock), 0x20); // SEND 命令 while (W5500_Read_Register(Sn_IR(sock)) 0x08 0) { // 等待 SEND 完成中断标志 } W5500_Write_Register(Sn_IR(sock), 0x08); // 清中断标志 return len; }这个函数里最容易出错的是tx_base的偏移算错。不同例程的缓冲区基址算法不一样有按 Socket 索引线性映射的也有按你配置的缓冲大小动态计算的。强烈建议打开w5500.h头文件看宏定义里Sn_TX_BUFFER_BASE(sock)的实现以你手上这份例程为准。free_size要读 Sn_TX_FSR 寄存器它表示当前 TCP 发送缓冲中未确认的空间如果这个值一直小于你的待发送长度说明对方窗口满了或者网络拥塞不要硬塞先重试。还有一点SEND 命令发出后必须等 SEND 中断标志置位再清期间不能写新的数据进缓冲区否则可能覆盖正在发送的帧。4.3 接收数据RX 缓冲区与中断标志的联动接收方向W5500 收到 TCP 数据后自动存进 RX 缓冲区同时把 Sn_IR 的 RECV 标志置 1。主循环里轮询到这个标志就读取 Sn_RX_RD读指针从 RX 缓冲区读出数据读完后更新 Sn_RX_RD再写 Sn_CR 的 RECV 命令释放缓冲区空间。这里有个反直觉的坑数据读到应用层后必须显式写 RECV 命令W5500 才知道这块缓冲可以重写否则缓冲区很快被塞满TCP 窗口关闭对方发送超时连接看起来「卡死」了。int16_t W5500_Receive_Buffer(uint8_t sock, uint8_t *buf, uint16_t max_len) { if (W5500_Read_Register(Sn_IR(sock)) 0x04) { // RECV 中断标志 uint16_t rx_rd W5500_Read_Register16(Sn_RX_RD(sock)); uint16_t rx_size W5500_Read_Register16(Sn_RX_RSR(sock)); // 已接收未读字节 if (rx_size 0) return 0; uint16_t len (rx_size max_len) ? max_len : rx_size; // 从 RX 缓冲区读数据注意回卷 W5500_Read_RX_Buffer(sock, rx_rd, buf, len); W5500_Write_Register16(Sn_RX_RD(sock), rx_rd len); W5500_Write_Register(Sn_CR(sock), 0x40); // RECV 命令 W5500_Write_Register(Sn_IR(sock), 0x04); // 清中断标志 return len; } return 0; }Sn_RX_RSR是 Socket 收到的未读数据量如果你不读它它会一直累加直到缓冲区满。判断有没有新数据建议以 Sn_RX_RSR 为准而不是靠 Sn_IR 的 RECV 中断标志——中断标志在读完数据后清零如果你开了多个中断源清标志时可能把其他事件也清了导致事件丢失。数据读出来后建议用 memcpy 拷到自己的应用缓冲不要把 RX 缓冲区当作长期存储区因为 RECV 命令一旦执行那块缓冲就被回收了。实际使用中TCP 粘包问题在这里很明显一次 RECV 中断可能包含多个 TCP 报文段你必须自己定义帧边界固定长度、分隔符、或头部长度字段否则应用层收到的是拼接流。5. 避坑与常见问题排查SPI 读回 0xFF、Socket 卡死、掉线不重连5.1 SCS 片选没有拉低寄存器读回全是 0xFF现象初始化时读 VERSIONR 寄存器返回值不是 0x04 而是 0xFF所有操作全部失效。原因SCS 引脚配置成了推挽输出但在 SPI 写入前没拉低W5500 根本没有进入传输状态MOSI 上的数据全部被忽略。解决在每次 SPI 事务开始前把 SCS 拉低结束再拉高中间不能松开。检查 GPIO 初始化时 SCS 引脚的模式对不对——如果复用成 SPI_NSS硬件会自动控制和你的软件控制冲突正确做法是把 GPIO 配成普通推挽输出禁止复用。5.2 Socket 连接几秒钟后自动断开随后一直连不上现象TCP Client 能连云服务器但 510 秒后连接断开再连接失败复位后才能恢复。原因多半是电源不稳。W5500 模块的 3.3V 供电如果从 F103 板上取网络传输瞬间电流会拉低电压PHY 内部 PLL 失锁链路断开。解决用外部 3.3V 电源单独给 W5500 模块供电或者至少并一颗 100uF 电容在模块电源脚上。另外查一下 Sn_IR 里的 TIMEOUT 标志是不是频繁置位如果是说明 TCP 重传耗尽了 Sn_RCR 的重传次数网络链路质量差去查焊接不要死磕代码。5.3 数据发不出去free_size 永远小于要发送的长度现象W5500_Send_Buffer函数返回 0打日志发现free_size一直很小。原因你没等 SEND 完成就继续发下一包。W5500 的 TX 缓冲区回收依赖 TCP ACK上一包数据发出后如果 Sn_TX_FSR 没有恢复到满额说明 ACK 还没回来或者根本没发出去。解决发送前检查Sn_TX_FSR不够就延时重试不要硬写。还有一个隐藏点如果对端 TCP 窗口是 0free_size会一直是 0这是正常的 TCP 流控检查对端应用有没有及时 recv。5.4 掉线后的自动重连逻辑一定要有防抖现象服务器重启或断网重连后客户端 Socket 状态变成 FIN_WAIT 或 CLOSE_WAIT程序不处理主循环里轮询到非 ESTABLISHED 就反复调 CONNECT导致 Socket 一直报错。原因W5500 的 Socket 状态机不允许你在非 CLOSED 状态下直接发 CONNECT。解决检测到状态不是 ESTABLISHED 时先强制 DISCON CLOSE等状态回到 SOCK_CLOSED 再从头执行 OPEN → CONNECT。这个「状态不复位就不重连」的判断逻辑通常放在主循环的保活模块里每次检查状态前先看是否 CLOSED是才允许重建连接。5.5 中断标志只清事件不见效清了又立刻置位现象读 Sn_IR 标志清掉后下一轮循环又置位数据却不增长。原因Sn_IR 的有些标志是电平触发不是边沿触发——比如 RECV 标志在 RX 缓冲区有数据时一直置位你必须在读完 RX 数据后发 RECV 命令释放缓冲区标志才会真正清除。如果只清标志不执行 RECV下一轮又被置位形成死循环。解决严格按照「读 RX_RSR → 读数据 → 更新 RX_RD → 写 RECV 命令 → 清中断」的顺序最后一步清标志放在 RECV 之后。这个顺序在多个 Socket 并发时尤其重要别的 Socket 的事件也可能映射到同一个中断线。6. 用抓包和状态机日志确认链路健康度的调试技巧跑通 TCP 收发别急着接业务先把链路健康度验证一遍。我习惯接上服务器后先用 WireShark 或 tcpdump 抓一小段流量确认 W5500 发出的 SYN 包内容正常——MSS 是不是 1460窗口大小是不是 2KB取决于你设的 RX 缓冲源端口是不是你想用的那个。抓包时同时看 ARP 是否正常如果 ARP 没解析出来说明 MAC 地址没配对或者网关没通TCP 包根本发不出去程序层面还误以为在 SYN-SENT 重传。抓包正常后用 Windows 上的网络调试助手或 Linux 下的nc -l起一个 TCP 服务端绑定固定端口然后让 F103 主动连接。连着打通一轮数据收发后强制把网线拔掉再插回看看 Socket 状态机是否按预期走到 CLOSE_WAIT 再走回 ESTABLISHED。此时打印Sn_SR的十六进制值对照 W5500 数据手册的状态定义表——0x17 是 SOCK_ESTABLISHED0x1C 是 SOCK_CLOSE_WAIT0x22 是 SOCK_SYNSENT。如果状态一直停在 0x1C说明对端关闭了连接但没发 FIN 的 ACK 回来你的重连逻辑要主动处理这个半关闭态直接强制 CLOSE。另一个实用技巧是把所有 W5500 关键寄存器的值周期性地通过串口打印出来Sn_SR、Sn_TX_FSR、Sn_RX_RSR、Sn_IR。每 500ms 打印一轮形成状态日志。看似土办法但排查偶发断连时能直接看出是「发送溢出」还是「接收没释放」还是「对端主动断开」。土办法比逻辑分析仪好用得多尤其当你没有 W5500 的内部调试口可看时。直到现在我每做一个基于 W5500 的项目哪怕只留了一路 TCP 通道也会在主循环里保留一段 100ms 轮询的寄存器快照代码用条件编译包起来线上出了问题就开宏重编一版几轮日志下来基本就能把问题定位到具体寄存器。从那以后我每次连不上服务器都不再先怀疑芯片而是先抓状态日志再翻数据手册对应章节效率高了不少希望帮到你。资源获取这份 stm32f103 W5500 TCP 例程已经在模拟项目X中验证过完整流程SPI 驱动、TCP Client 收发、断线重连逻辑均已跑通。需要源码包和配套原理图参考的开发者直接下载工程后按第 3 章的接线表连接硬件改掉 IP 和端口即可开始你的第一轮 TCP 联调。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑