STM32F407单片机编程入门(二十七)以太网接口(LAN8720)详解及实战含源码

一.概要

以太网(Ethernet)。指的是由Xerox公司创建并由Xerox,Intel和DEC公司联合开发的基带局域网规范。以太网络使用CSMA/CD(载波监听多路访问及冲突检测技术)技术,并以10M/S的速率运行在多种类型的电缆上。以太网与IEEE802·3系列标准相类似。 它不是一种具体的网络,是一种技术规范。 以太网是当今现有局域网采用的最通用的通信协议标准。该标准定义了在局域网(LAN)中采用的电缆类型和信号处理方法。以太网在互联设备之间以10~100Mbps的速率传送信息包,双绞线电缆10 Base T以太网由于其低成本、高可靠性以及10Mbps的速率而成为应用最为广泛的以太网技术。

以太网是一种广泛应用于各种计算机局域网技术,被普遍用于以下场景:

‌‌工业自动化‌:以太网在工业自动化领域有着广泛的应用。它能够满足工业自动化系统对大量数据传输和实时性的需求,支持多设备连接,适应高温、高湿等恶劣环境,适用于复杂的工业环境。

‌‌企业网络‌:在企业网络中,以太网用于构建高速、稳定的内部网络,支持数据、视频和语音等多业务传输。它广泛应用于大型企业和数据中心,提供高速数据传输支持。

‌‌智能交通‌:在智能交通系统中,以太网连接交通监控设备,实现交通数据的实时传输。这有助于提高交通管理的效率和安全性。

远程监控‌:在远程监控系统中,以太网用于将监控数据传输到控制中心,提高监控效率。它广泛应用于各种远程监控场景,如‌环境监测、设备监控等。

‌数据中心‌:数据中心使用以太网连接服务器和存储设备,实现高速数据交换。‌万兆以太网在数据中心的应用尤为广泛,满足高性能计算和大数据处理的需求。

‌‌超级计算中心‌:在超级计算中心,万兆以太网设备提供高密度的端口和快速的交换性能,满足高性能计算机架构和网络的需求,促进计算机科学研究的发展。

二.单片机以太网系统基本结构

1.OSI 七层模型

‌OSI七层模型‌是国际标准化组织(ISO)定义的一个网络通信框架,旨在为不同计算机系统之间的通信提供一个标准化的方法。这个模型将网络通信过程划分为七个层次,从物理层到应用层,每一层都有其特定的功能和协议。

在这里插入图片描述

2.单片机实现以太网功能组成

一般单片机组成以太网所需部件是:单片机+MAC+PHY+RJ45。

STM32F407VET6内部自带MAC,所以要组成以太网,主要部件就是
STM32F407VET6+PHY+RJ45。
我们常见的以太网PHY芯片是DP83848和LAN8720。

在这里插入图片描述

以太网MAC‌:即媒体访问控制子层协议‌,位于OSI七层协议中的数据链路层下半部分,主要负责控制与连接物理层的物理介质。MAC协议的主要功能包括在发送数据时判断是否可以发送,如果可以发送,则给数据加上一些控制信息,最终将数据以及控制信息以规定的格式发送到物理层;在接收数据时,MAC协议首先判断输入的信息是否发生传输错误,如果没有错误,则去掉控制信息发送至逻辑链路控制层。

以太网PHY:即物理层接口收发器,是网络通信中的一个重要组成部分,它实现了OSI模型中的物理层。IEEE-802.3标准定义了以太网PHY,包括多个子层,如MII/GMII(介质独立接口)、PCS(物理编码子层)、PMA(物理介质附加子层)、PMD(物理介质相关子层)和MDI子层。这些子层共同定义了数据传送与接收所需要的电与光信号、线路状态、时钟基准、数据编码和电路等,并向数据链路层设备提供标准接口。

三.STM32F407VET6单片机以太网内部结构

在这里插入图片描述
以太网在进行数据发送时,单片机首先将数据由系统存储器以 DMA 的方式送至发送 FIFO (Tx FIFO) 进行缓冲,再通过 MAC内核发送,MAC通过RMII或者MII接口与外部PHY进行通讯。
以太网在进行数据接收时,接收 FIFO (Rx FIFO) 则存储通过线路接收的以太网帧,直到这些帧通过 DMA 传送到系统存储器。

1.MII接口介绍

介质独立接口 (MII) 定义了 10 Mbit/s 和 100 Mbit/s 的数据传输速率下 MAC 子层与 PHY 之
间的互连。

MII连接示意图
在这里插入图片描述

在这里插入图片描述

2.RMII接口介绍

精简介质独立接口 (RMII) 规范降低了 10/100 Mbit/s 下微控制器以太网外设与外部 PHY 间的引脚数。

RMII连接示意图

在这里插入图片描述

在这里插入图片描述

对比以上两种连接方式,RMII通过减少信号线数量和提高时钟频率,提供了一种在保持或提高数据传输速率的同时简化硬件设计的解决方案。这种接口在需要平衡成本、性能和复杂性的应用中特别有用‌,所以在STM32开发中,最常见的是RMII连接方式。

四.LWIP TCP/IP协议栈介绍

TCP/IP 协议栈是一系列网络协议的总和,它允许不同电子设备在因特网上进行通信。该协议采用4层结构,分别是应用层、传输层、网络层和网络接口层,每一层都依赖于其下面的层,同时为其上面的层提供服务。

TCP/IP 协议栈和传统的 OSI 模型并不完全对应。TCP/IP 协议是一个简化的模型,强调了实际的协议实现和因特网的实际运作方式。
在这里插入图片描述

Light weight IP(LWIP)是轻量化的 TCP/IP 协议,是瑞典计算机科学院(SICS)的 Adam Dunkels 开发的一个小型开源的 TCP/IP 协议栈。 LwIP 的设计初衷是:用少量的资源消耗(RAM)实现一个较为完整的 TCP/IP 协议栈, 在保持 TCP 协议主要功能的基础上减少对 RAM 的占用。
LwIP既可以移植到操作系统上运行,也可以在无操作系统的情况下独立运行。它只需十几KB的RAM和40K左右的ROM就可以运行,这使LwIP协议栈适合在低端的嵌入式系统中使用。

LwIP是符合 TCP/IP 模型架构,规定了数据的格式、传输、路由和接收,以实现端到端的通信。

应用层:lwIP提供了TCP/IP协议栈的实现,包括HTTP,MQTT等协议
传输层:lwIP实现了TCP和UDP协议
网络层:lwIP实现了IP协议
网络接口层:lwIP并没有实现,这一层由硬件来实现
在这里插入图片描述

五.PHY收发器LAN8720介绍

‌LAN8720A是一款低功耗的10/100M以太网PHY芯片,符合EEE802.3-2005标准,支持通过RMII接口与以太网MAC层通信。‌ 它内置了10-BASE-T/100BASE-TX全双工传输模块,支持10Mbps和100Mbps的传输速度。LAN8720A具有自协商功能,能够与目的主机自动选择最佳连接方式(速度和双工模式),并支持HP Auto-MDIX自动翻转功能,无需更换网线即可实现直连或交叉连接。此外,它还支持通过SMI串行管理接口和MAC接口进行配置和管理。
在这里插入图片描述

1.LAN8720内部框图

在这里插入图片描述

2.LAN8720应用电路

在这里插入图片描述

3.LAN8720以太网模块

LAN8720以太网模块是把PHY,RJ45都放在一块小板子上,只要开发板与模块通过RMII连接,就能组成以太网系统。
在这里插入图片描述

模块参考原理图

在这里插入图片描述

六.CubeMX配置一个LWIP的TCP/IP通讯协议实验

硬件准备:

STLINK接STM32F407VET6开发板,STLINK接电脑USB口。LAN8720模块接到开发板上,网线接模块的RJ45口跟电脑。
在这里插入图片描述

开发板以太网接口定义:
在这里插入图片描述

打开STM32CubeMX软件,新建工程
在这里插入图片描述
Part Number处输入STM32F407VE,再双击就创建新的工程
在这里插入图片描述

配置下载口引脚
在这里插入图片描述

配置外部晶振引脚
在这里插入图片描述

配置以太网RMII接口
在这里插入图片描述
配置中断
在这里插入图片描述
在这里插入图片描述
PHY选择DP83848
在这里插入图片描述
使能FreeRTOS
在这里插入图片描述

LWIP配置,IP地址,掩码,网关配置
在这里插入图片描述

配置系统主频168Mhz,使用外部晶振
在这里插入图片描述

配置工程文件名,保存路径,KEIL5工程输出方式
在这里插入图片描述

生成工程
在这里插入图片描述

用Keil5打开工程
在这里插入图片描述

添加代码
查看服务器IP地址配置是否正确
在这里插入图片描述

查看板子IP地址与网关是否正确
在这里插入图片描述

在这里插入图片描述

主要代码如下:


#define TCP_LOCAL_PORT     		8887 
#define TCP_SERVER_PORT    		8888
#define TCP_SERVER_IP   		192,168,1,11//服务器IP
void MX_LWIP_Init(void)
{
  /* IP addresses initialization */
  IP_ADDRESS[0] = 192;
  IP_ADDRESS[1] = 168;
  IP_ADDRESS[2] = 1;
  IP_ADDRESS[3] = 12;//板子IP地址
  NETMASK_ADDRESS[0] = 255;//掩码
  NETMASK_ADDRESS[1] = 255;
  NETMASK_ADDRESS[2] = 255;
  NETMASK_ADDRESS[3] = 0;
  GATEWAY_ADDRESS[0] = 192;
  GATEWAY_ADDRESS[1] = 168;
  GATEWAY_ADDRESS[2] = 1;
  GATEWAY_ADDRESS[3] = 1;//网关

/* USER CODE BEGIN IP_ADDRESSES */
/* USER CODE END IP_ADDRESSES */

  /* Initilialize the LwIP stack with RTOS */
  tcpip_init( NULL, NULL );

  /* IP addresses initialization without DHCP (IPv4) */
  IP4_ADDR(&ipaddr, IP_ADDRESS[0], IP_ADDRESS[1], IP_ADDRESS[2], IP_ADDRESS[3]);
  IP4_ADDR(&netmask, NETMASK_ADDRESS[0], NETMASK_ADDRESS[1] , NETMASK_ADDRESS[2], NETMASK_ADDRESS[3]);
  IP4_ADDR(&gw, GATEWAY_ADDRESS[0], GATEWAY_ADDRESS[1], GATEWAY_ADDRESS[2], GATEWAY_ADDRESS[3]);

  /* add the network interface (IPv4/IPv6) with RTOS */
  netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init, &tcpip_input);

  /* Registers the default network interface */
  netif_set_default(&gnetif);

  if (netif_is_link_up(&gnetif))
  {
    /* When the netif is fully configured this function must be called */
    netif_set_up(&gnetif);
  }
  else
  {
    /* When the netif link is down this function must be called */
    netif_set_down(&gnetif);
  }

  /* Set the link callback function, this function is called on change of link status*/
  netif_set_link_callback(&gnetif, ethernetif_update_config);

  /* create a binary semaphore used for informing ethernetif of frame reception */
  osSemaphoreDef(Netif_SEM);
  Netif_LinkSemaphore = osSemaphoreCreate(osSemaphore(Netif_SEM) , 1 );

  link_arg.netif = &gnetif;
  link_arg.semaphore = Netif_LinkSemaphore;
  /* Create the Ethernet link handler thread */
/* USER CODE BEGIN OS_THREAD_DEF_CREATE_CMSIS_RTOS_V1 */
  osThreadDef(LinkThr, ethernetif_set_link, osPriorityBelowNormal, 0, configMINIMAL_STACK_SIZE * 2);
  osThreadCreate (osThread(LinkThr), &link_arg);
/* USER CODE END OS_THREAD_DEF_CREATE_CMSIS_RTOS_V1 */

/* USER CODE BEGIN 3 */

/* USER CODE END 3 */
}
/***********************************************************************
函数名称:void TCP_Client_Send_Data(unsigned char *buff)
功    能:TC[客户端发送数据函数
输入参数:
输出参数:
编写时间:2013.4.25
编 写 人:
注    意:for(cpcb = tcp_active_pcbs;cpcb != NULL; cpcb = cpcb->next) 
***********************************************************************/
err_t TCP_Client_Send_Data(struct tcp_pcb *cpcb,unsigned char *buff,unsigned int length)
{
	err_t err;

	err = tcp_write(cpcb,buff,length,TCP_WRITE_FLAG_COPY);	//发送数据
	tcp_output(cpcb);
	//tcp_close(tcp_client_pcb);				//发送完数据关闭连接,根据具体情况选择使用	
	return err;					
}
extern union tcp_listen_pcbs_t tcp_listen_pcbs;
extern struct tcp_pcb *tcp_active_pcbs;  /* List of all TCP PCBs that are in a
/***********************************************************************
函数名称:Check_TCP_Connect(void)
功    能:检查连接
输入参数:
输出参数:
编写时间:2013.4.25
编 写 人:
注    意:for(cpcb = tcp_active_pcbs;cpcb != NULL; cpcb = cpcb->next) 
***********************************************************************/\
struct tcp_pcb *Check_TCP_Connect(void)
{
	struct tcp_pcb *cpcb = 0;
	connect_flag = 0;
	for(cpcb = tcp_active_pcbs;cpcb != NULL; cpcb = cpcb->next)
	{
	//	if(cpcb->local_port == TCP_LOCAL_PORT && cpcb->remote_port == TCP_SERVER_PORT)		//如果TCP_LOCAL_PORT端口指定的连接没有断开
		if(cpcb -> state == ESTABLISHED)  //如果得到应答,则证明已经连接上
		{
			connect_flag = 1;  						//连接标志
			break;							   	
		}
	}

	if(connect_flag == 0)  	// TCP_LOCAL_PORT指定的端口未连接或已断开
	{
		TCP_Client_Init(TCP_LOCAL_PORT,TCP_SERVER_PORT,TCP_SERVER_IP); //重新连接
		cpcb = 0;
	}
	return cpcb;	
}
/***********************************************************************
函数名称:err_t RS232_TCP_Connected(void *arg,struct tcp_pcb *pcb,err_t err)
功    能:完成RS232到TCP的数据发送
输入参数:
输出参数:
编写时间:2013.4.25
编 写 人:
注    意:这是一个回调函数,当TCP客户端请求的连接建立时被调用
***********************************************************************/
err_t TCP_Connected(void *arg,struct tcp_pcb *pcb,err_t err)
{
	//tcp_client_pcb = pcb;
	return ERR_OK;
}
/***********************************************************************
函数名称:TCP_Client_Recv(void *arg, struct tcp_pcb *pcb,struct pbuf *p,err_t err)
功    能:tcp客户端接收数据回调函数
输入参数:
输出参数:
编写时间:2013.4.25
编 写 人:
注    意:这是一个回调函数,当TCP服务器发来数据时调用
***********************************************************************/

err_t  TCP_Client_Recv(void *arg, struct tcp_pcb *pcb,struct pbuf *p,err_t err)
{
	struct pbuf *p_temp = p;
	
	if(p_temp != NULL)
	{	
		tcp_recved(pcb, p_temp->tot_len);//获取数据长度 tot_len:tcp数据块的长度
		while(p_temp != NULL)	
		{				
			/******将数据原样返回*******************/
			tcp_write(pcb,p_temp->payload,p_temp->len,TCP_WRITE_FLAG_COPY); 	// payload为TCP数据块的起始位置       
			tcp_output(pcb);
			p_temp = p_temp->next;
		}		
	}
	else
	{
		tcp_close(pcb); 											/* 作为TCP服务器不应主动关闭这个连接? */
	}
	/* 释放该TCP段 */
	pbuf_free(p); 	
	err = ERR_OK;
	return err;
}
/***********************************************************************
函数名称:TCP_Client_Init(u16_t local_port,u16_t remote_port,unsigned char a,unsigned char b,unsigned char c,unsigned char d)
功    能:tcp客户端初始化
输入参数:local_port本地端口号;remote_port:目标端口号;a,b,c,d:服务器ip
输出参数:
编写时间:2013.4.25
编 写 人:
注    意:
***********************************************************************/
void TCP_Client_Init(u16_t local_port,u16_t remote_port,unsigned char a,unsigned char b,unsigned char c,unsigned char d)
{

	 ip4_addr_t ipaddr,LocalAddress;
	err_t err;
	IP4_ADDR(&ipaddr,a,b,c,d);           //服务器IP地址
	tcp_client_pcb = tcp_new(); /* 建立通信的TCP控制块(Clipcb) */
	if (!tcp_client_pcb)
	{
		return ;
	}	

//IP4_ADDR(&LocalAddress,192,168,10,11);           //服务器IP地址	
	err = tcp_bind(tcp_client_pcb,IP_ADDR_ANY,local_port); /* 绑定本地IP地址和端口号 ,本地ip地址在LwIP_Init()中已经初始化*/
	if(err != ERR_OK)
	{
		return ;
	}    
	tcp_connect(tcp_client_pcb,&ipaddr,remote_port,TCP_Connected);//注册回调函数
	tcp_recv(tcp_client_pcb,TCP_Client_Recv); 				/* 设置tcp接收回调函数 */
}

	unsigned char tcp_data[] = "tcp 客户端实验!\n";
	struct tcp_pcb *pcb;
void StartDefaultTask(void const * argument)
{
  /* init code for LWIP */
  MX_LWIP_Init();
	/* Infinite loop */
	TCP_Client_Init(TCP_LOCAL_PORT,TCP_SERVER_PORT,TCP_SERVER_IP); //tcp客户端初始化

  
  /* USER CODE BEGIN StartDefaultTask */
  /* Infinite loop */
  for(;;)
  {
    osDelay(1000);
		HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13|GPIO_PIN_14);
		pcb = Check_TCP_Connect();
		if(pcb != 0)
		{	
			TCP_Client_Send_Data(pcb,tcp_data,sizeof(tcp_data));	//该函数为主动向服务器发送函数,
		}

		/* handle periodic timers for LwIP */
	//	LwIP_Periodic_Handle(LocalTime);
  }
  /* USER CODE END StartDefaultTask */
}

实验效果:

禁用无线,启动以太网,打开TCP调试助手,配置为服务器监听模式,监听端口8888,板子上电不久,在TCP调试助手上就能看到192.168.1.12的IP地址的板子连接上来,并发送数据。
在这里插入图片描述

七.CubeMX工程源代码下载

通过网盘分享的文件:30.LAN8720以太网通讯实验.zip
链接: https://pan.baidu.com/s/1Ze3UMKZ4W2WbyO0PgkfMIA 提取码: u2sc
如果链接失效,可以联系博主给最新链接
程序下载下来之后解压就行

八.小结

STM32F407开发板加上LAN8720模块可以通过网络连接,实现远程控制、数据传输等功能。

STM32F407单片机设计以太网接口数据采集板AD硬件原理图+PCB+封装库文件,2层板设计,大小为100*100mm,包括完整的原理图和PCB及封装库文件,可以做为你的设计参考。 主要器件型号如下: Library Component Count : 36 Name Description ---------------------------------------------------------------------------------------------------- CAP NP CAP NP_2_Dup1 CAP NP_Dup2 CAP,MLCC,10uF,+/-10%,X5R,6.3V,SMD0805 CRYSTAL_1 CRYSTAL_2 Cap 无极性电容 Cap Pol 极性电解电容 DS Surface mount schottky diode SOD-323(0805) Package DS1128-09-S8B8X Diode 二极管 FET P MOS HFD4/12-S 双路继电器 Header 2 Header, 2-Pin Header 2X2 Header, 2-Pin, Dual row Header 9 Header, 9-Pin Inductor 电感 LED0 Typical INFRARED GaAs LED MAX485 NPN-S9014-贴片 NPN-S9014-贴片 RES-2 RESISTOR RESISTOR_1 RES,thick film,47KOhm,+/-5%,1/16W,SMD0402 RESISTOR_Dup2 通用厚膜电阻,75K,+/-1%,R0402,1/16W. Res 贴片电阻 1% Res1 Resistor Res2 Resistor Res3 Resistor TLP281 TLV62569DBVR dc-dc可调电源 TRANSMITOR100 T_FLASH_A XL1509 dp83620_1 stm32f4xxz1_0 绿色端子6P 贴片按键 封装库列表: Component Count : 58 Component Name ----------------------------------------------- 1N4001-M1二极管 2.2uH 贴片电感 10uF贴片电解电容50V 0603A 0603a - duplicate 0603LED 1210 1808贴片电容 3225晶振 BAT54C BATTERY CAN_2 dp83620以太网芯片 EC20 HDR1X2 HDR1X4 HDR1X5 HDR2X2 HDR2X4_CEN HDR2X5 HDR2X9 HDR2X10 HR911105A key_3 keya LED3528 m35768 MC29302 MICRO_USB microSIMauto MICROUSB PCBComponent_1 PCBComponent_1 - duplicate PCBComponent_1 - duplicate1 QFN24 QFP144 RJ45插孔 RTL8201F s8550 SDCARD SIP4 SMB SMB_L4.6-W3.6-LS5.3-RD SO-8 SOT-23-5 SOT223 SSOP-20 TLP281 TSOP44 TVS58Y W25Q16 xtal YINPIN 轻触开关6*6*4.5 贴片磁珠0603 贴片电阻1812 整流桥ABS210 整流桥HD01
<think>好的,用户想解决STM32以太网TCP通信中不分包的问题。首先,我需要了解这个问题的具体情况。不分包通常指的是当发送的数据超过最大传输单元(MTU)时,数据没有正确分片,导致传输失败或数据丢失。STM32的以太网模块可能默认没有自动处理分包,需要手动配置。 首先,检查MTU设置是否正确。STM32的以太网外设默认MTU是1500字节,这是标准以太网的MTU。如果应用层发送的数据超过这个值,就需要在TCP层进行分片。用户可能需要确认他们的数据包是否超过了这个限制。 接下来,查看TCP MSS(最大分段大小)。MSS通常是MTU减去IP和TCP头的40字节,所以应该是1460字节。如果发送的数据超过MSS,TCP协议栈应该自动分段。但有时候配置不正确可能导致不分段,需要检查相关的宏定义,比如TCP_MSS是否正确设置。 然后,考虑发送数据的处理方式。用户可能在应用层使用send函数直接发送大数据包,这时候需要确保TCP协议栈的缓冲区足够大。如果缓冲区不足,数据可能被截断。建议使用循环发送,将大数据分成多个小包发送,并在代码中处理分片逻辑。 另外,确认硬件和驱动配置。检查以太网DMA描述符的配置,确保每个描述符能够处理足够的缓冲区大小,避免因为缓冲区不足导致的分包失败。同时,确认中断处理是否正确,特别是在处理发送完成中断时是否有资源未释放的问题。 可能还需要调整协议栈参数,比如使能TCP窗口缩放选项,增加发送窗口大小,以支持更大的数据传输。同时,优化ACK确认机制,减少等待时间,提高传输效率。 最后,调试和测试是关键。使用Wireshark抓包工具监控实际传输的数据包,查看是否有正确的分片,以及分片后的数据包是否符合预期。如果发现分片不正确,可以逐步调整相关参数,直到问题解决。 用户提供的参考引用提到PSDN,但看起来和当前问题关联不大,可能是个错误。不过不影响当前问题的解决思路。需要确保在回答中结构清晰,分步骤说明解决方法,并生成相关问题帮助用户深入理解。</think>### STM32以太网TCP通信不分包解决方案 #### 1. 问题分析 TCP协议本身支持数据分段传输,但在STM32以太网应用中可能出现不分包现象,主要原因包括: - MTU(最大传输单元)设置不当 - TCP协议栈缓冲区配置不足 - 应用层数据处理方式不合理 - 硬件描述符配置错误[^1] #### 2. 关键配置步骤 (1) **MTU设置验证** ```c #define ETH_RX_BUF_SIZE 1524 // 标准MTU 1500+Ethernet头24字节 #define ETH_TX_BUF_SIZE ETH_RX_BUF_SIZE ``` (2) **TCP协议栈参数调整** ```c // lwipopts.h #define TCP_MSS 1460 // MTU(1500) - IP头(20) - TCP头(20) #define TCP_SND_BUF (10*TCP_MSS) // 发送缓冲区 ``` #### 3. 数据发送优化 ```c // 分块发送函数示例 err_t send_data(struct tcp_pcb *pcb, const uint8_t *data, u16_t len) { u16_t offset = 0; while (offset < len) { u16_t send_len = MIN(len - offset, TCP_MSS); err_t err = tcp_write(pcb, data + offset, send_len, TCP_WRITE_FLAG_COPY); if (err != ERR_OK) return err; offset += send_len; } return tcp_output(pcb); // 触发实际发送 } ``` #### 4. 硬件配置检查 - 确认ETH DMA描述符数量: ```c #define ETH_RXBUFNB 4 // 接收描述符 #define ETH_TXBUFNB 4 // 发送描述符 ``` - 验证描述符缓冲区地址对齐(需32字节对齐) #### 5. 调试建议 - 使用Wireshark抓包分析实际传输帧结构 - 监控lwIP的`mem_free`统计信息 - 检查`tcp_sndbuf()`返回值确认可用发送缓冲区大小
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值