lwip环回调试笔记
- 格式:doc
- 大小:18.50 KB
- 文档页数:3
2) sys_thread_new sys_arch_timeouts相关的三个全局变量如下struct sys_timeouts lwip_timeouts[LWIP_TASK_MAX];//为每一个由sys_thread_new创建的任务分配一个存放信号量超时信息的列表struct sys_timeouts null_timeouts;//为一个超过任务上限数的任务和不是由sys_thread_new创建的任务取超时列表时返回使用。
MMAC_RTOS_TASK_ID LWIP_TASKS[LWIP_TASK_MAX];//任务id存放顺序与lwip_timeouts相对应sys_thread_new用来创建一个新的任务,保存任务ID。
sys_arch_timeouts//就是通过取得任务ID返回任务对应的timeouts结构,从而可以添加、删除和判断超时的功能/*** Create a one-shot timer (aka timeout). Timeouts are processed in the* following cases:* - while waiting for a message using sys_mbox_fetch()* - while waiting for a semaphore using sys_sem_wait() or sys_sem_wait_timeout()* - while sleeping using the inbuilt sys_msleep()** @param msecs time in milliseconds after that the timer should expire* @param h callback function to call when msecs have elapsed* @param arg argument to pass to the callback function*/voidsys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)sys_timeouts 只是一个指向下一个的sys_timeo的指针1、InternSocketInit();//TCP连接初始化1.1、lwIPInit(sDevPara.chMACAddr, 0, 0, 0, IPADDR_USE_DHCP);//! Initializes the lwIP TCP/IP stack.//!//! \param pucMAC is a pointer to a six byte array containing the MAC//! address to be used for the interface.//! \param ulIPAddr is the IP address to be used (static).//! \param ulNetMask is the network mask to be used (static).//! \param ulGWAddr is the Gateway address to be used (static).//! \param ulIPMode is the IP Address Mode. \b IPADDR_USE_STA TIC will force //! static IP addressing to be used, \b IPADDR_USE_DHCP will force DHCP with//! fallback to Link Local (Auto IP), while \b IPADDR_USE_AUTOIP will force//! Link Local only.//!//! This function performs initialization of the lwIP TCP/IP stack for the//! Stellaris Ethernet MAC, including DHCP and/or AutoIP, as configured.//!//! \return None.1.1.1、tcpip_init(lwIPPrivateInit, 0); 这个地方用到了回调函数tcpip_init(void (* initfunc)(void *),void *arg)什么是指针函数?函数指针是指向函数的指针变量。
lwip内存分配算法-回复LWIP(Lightweight IP)是一个嵌入式系统中的轻量级的网络协议栈。
它主要用于资源受限的系统,如小型微控制器、嵌入式系统和嵌入式操作系统。
LWIP不仅提供了TCP/IP协议栈的功能,而且还采用了一种特殊的内存分配算法来管理堆上的内存。
本文将详细介绍LWIP的内存分配算法。
LWIP的内存分配算法主要包括两个部分:内存池管理和动态内存管理。
其中,内存池管理用于事先规划和分配一块固定大小的内存池,而动态内存管理用于在程序运行时动态地分配和释放内存空间。
首先,我们来看内存池管理。
内存池管理是通过将内存划分为一组固定大小的内存块,然后将这些内存块存放到一个内存池中,以便在需要时可以快速地分配给应用程序。
具体来说,LWIP将内存划分为不同大小的内存块,这取决于应用程序对内存的需求。
每个内存块都保存着一个链表指针,用于将已分配的内存块连接起来。
当应用程序需要分配内存时,LWIP会遍历内存池中的内存块链表,找到一个大小合适的内存块来分配。
如果找到了一个可用的内存块,LWIP将该内存块从链表中移除,并返回给应用程序使用。
如果没有找到大小合适的内存块,LWIP将会分配一块更大的内存块,并将其划分为多个较小的内存块,其中一个分配给应用程序使用,而其他的内存块则重新加入到内存块链表中。
另一方面,当应用程序释放内存时,LWIP会将该内存块重新加入到内存块链表中,以便在下次分配内存时可以重新使用。
这样,在程序运行时,LWIP可以避免频繁地向操作系统请求内存空间,从而提高了内存的利用率和系统性能。
接下来,我们来看动态内存管理。
动态内存管理是指在程序运行时根据需求动态地分配和释放内存空间。
LWIP使用了一套高效的动态内存管理算法来实现这一功能。
具体来说,LWIP会维护一张内存分区表,用于记录系统中所有已分配的内存区域和大小。
当应用程序需要分配内存时,LWIP会遍历内存分区表,找到一个大小合适且未使用的内存区域来分配。
1.网络芯片比较目前使用的网络芯片一般有以下几种:DP83848、DM9000、enc28j60、RLD8019、w5100网卡工作在osi的最后两层,物理层(PHY)和数据链路层(MAC)。
物理层定义了数据传送与接收所需要的电与光信号、线路状态、时钟基准、数据编码和电路等,并向数据链路层设备提供标准接口。
物理层的芯片称之为PHY。
数据链路层则提供寻址机构、数据帧的构建、数据差错检查、传送控制、向网络层提供标准的数据接口等功能。
以太网卡中数据链路层的芯片称之为MAC 控制器。
1.DP83848:物理层(PHY),跟MII接口。
2. DM9000:物理层(PHY)和数据链路层(MAC)(10/100M)。
跟8/16/32总线接口3. enc28j60:MAC+PHY(10M Base T)。
spi接口4. w5100:硬件TCP/IP协议栈+MAC+PHY(10/100M Base T)。
并行总线接口5. RLD8019:和w5100类似,比较老。
举个例子:W5100里面用硬件逻辑电路实现了TCP/IP的协议栈结构,不需要向ENC28J60这样的网络控制器那样还需要一个资源较大的MCU跑软件协议栈。
你直接把W5100当外部RAM使用,MCU初始化一下I/O,寄存器等就能使用了。
2.TCP/IP协议族的四个层次网络协议通常分不同层次进行开发,每一层分别负责不同的通信功能。
一个协议族,比如TCP/IP,是一组不同层次上的多个协议的组合。
TCP/IP通常被认为是一个四层协议系统,如下图所示:每一层负责不同的功能:1) 链路层,有时也称作数据链路层或网络接口层,通常包括操作系统中的设备驱动程序和计算机中对应的网络接口卡。
它们一起处理与电缆(或其他任何传输媒介)的物理接口细节。
2) 网络层,有时也称作互联网层,处理分组在网络中的活动,例如分组的选路。
在TCP/IP协议族中,网络层协议包括I P协议(网际协议),ICMP协议(Internet互联网控制报文协议),以及IGMP协议(Internet组管理协议)。
lwip超时重传算法-回复LWIP超时重传算法LWIP(轻型网络通信协议)是一个用于嵌入式系统的开源的TCP/IP 协议栈。
在嵌入式系统中,网络通信往往会面临许多挑战,比如网络不稳定、带宽限制等。
为了保证数据传输的可靠性和效率,LWIP实现了一系列的算法和机制,其中就包括超时重传算法。
本文将详细讨论LWIP超时重传算法的原理和应用。
一、超时重传算法的基本原理超时重传算法是一种保证TCP协议数据传输的可靠性的重要机制。
它的基本原理是,发送方在发送数据时,会设置一个定时器,当定时器超时时,会对未被确认的数据包进行重传。
通过超时重传,可以避免数据在网络中丢失而导致的数据传输不完整或延迟。
LWIP超时重传算法的实现主要依赖于以下几个要素:1. 往返时间估计(RTT):RTT是指从发送方发送数据到接收方接收到确认消息的时间。
发送方需要根据RTT来设置超时时间,通常使用平均RTT和其偏差的估计值。
2. 超时时间的选择:超时时间的选择对数据传输的可靠性和效率有着直接的影响。
超时时间过短会导致频繁的不必要的重传,降低网络吞吐量;超时时间过长会延迟数据的传输,增加响应时间。
LWIP使用了一种自适应的方法来调整超时时间,称为加权移动平均超时时间(SRTT)。
3. 重传策略:LWIP中采用了快速重传和快速恢复的策略。
当发送方连续接收到3个重复的确认时,它会立即重传丢失的数据。
同时,为了降低网络拥堵,LWIP采用了拥塞控制算法,限制发送方的发送速率,防止网络拥塞的发生。
二、LWIP超时重传算法的应用LWIP超时重传算法被广泛应用于各种嵌入式系统中,以保证数据的可靠传输。
以下是一些常见的应用场景:1. 无线传感器网络:在无线传感器网络中,节点之间的通信往往受限于有限的带宽和不稳定的信号传输。
通过使用LWIP超时重传算法,可以有效地处理数据包丢失和延迟的问题,确保传感器节点之间的可靠通信。
2. 工业自动化:在工业自动化系统中,各个设备之间需要进行实时的数据传输。
lwip超时重传算法-回复lwip超时重传算法是一种用于网络传输中的数据丢失和延迟问题的解决方案。
该算法可以通过检测数据包丢失并重新发送这些数据包,以确保数据的可靠传输。
本文将详细介绍lwip超时重传算法的原理、流程和改进方法,以及其在实际应用中所面临的挑战和应对措施。
一、lwip超时重传算法的原理lwip超时重传算法的核心原理是基于定时器的事件驱动机制。
在数据包发送过程中,发送方会设置一个定时器来监测数据包的传输状态。
如果在指定的时间内没有收到接收方的确认消息,发送方会认为数据包丢失,进而触发超时重传机制。
通过这种方式,lwip超时重传算法可以在一定程度上解决数据丢失问题,提高网络传输的可靠性。
二、lwip超时重传算法的流程1. 发送方发送数据包:发送方向接收方发送数据包,并在发送时设置定时器。
2. 接收方接收数据包:接收方收到数据包后,会发送一个确认消息给发送方。
3. 发送方收到确认消息:发送方收到接收方的确认消息后,会取消定时器,表示数据包已经安全到达。
4. 定时器超时:如果发送方在指定的时间内没有收到确认消息,定时器会超时。
5. 触发超时重传机制:定时器超时后,发送方会重新发送未确认的数据包。
6. 接收方重复接收:接收方收到重传的数据包后,会再次发送确认消息给发送方。
7. 数据包到达:发送方收到接收方的确认消息后,取消定时器,数据包成功到达。
8. 数据包丢失:如果定时器超时多次,仍未收到确认消息,则数据包被认为丢失。
三、lwip超时重传算法的改进方法虽然lwip超时重传算法可以解决一定程度上的数据丢失和延迟问题,但在实际应用中仍然存在一些挑战和不足之处。
为了进一步提高可靠性和效率,人们进行了一些改进。
以下是几种常见的改进方法:1. 动态超时设置:根据网络状况动态调整超时时间,避免过长的等待时间或过短的重传间隔,提高效率和响应速度。
2. 拥塞控制:通过检测网络拥塞状态,调整数据包的发送速率,避免数据包丢失和网络阻塞。
lwip的tcp socket编程-回复LWIP (Lightweight IP) 是一个轻量级的开源TCP/IP 协议栈,用于嵌入式系统的网络通信。
在本文中,我们将了解如何使用LWIP 进行TCP Socket 编程。
第一步:了解TCP SocketTCP (Transmission Control Protocol) 是一种面向连接的协议,可确保数据的可靠传输。
Socket 是一种用于网络通信的编程接口,允许不同的计算机之间通过网络进行数据传输。
第二步:下载和安装LWIP首先,您需要从LWIP 官方网站下载LWIP 协议栈的最新版本。
下载完成后,解压缩并将其添加到您的项目文件夹中。
第三步:创建一个新的LWIP项目接下来,创建一个新的LWIP 项目,并将LWIP 文件夹添加到该项目目录中。
确保您的编译器正确设置了LWIP 的路径。
第四步:配置LWIPLWIP 需要通过配置文件进行设置。
打开LWIP 项目目录中的"lwip_opts.h" 文件,并根据您的需求进行所需的配置。
例如,您可以设置LWIP 的最大连接数、最大数据包大小等。
第五步:创建TCP Socket在编写TCP Socket 程序之前,您需要创建一个Socket 来进行通信。
在LWIP 中,可以使用"socket()" 函数来创建一个TCP Socket。
该函数将返回一个Socket 文件描述符,供后续操作使用。
第六步:绑定Socket在准备好Socket 后,您需要将其绑定到本地IP 地址和端口上。
使用"bind()" 函数来实现这一点。
将要绑定的IP 地址和端口作为参数传递给该函数。
第七步:监听连接在绑定Socket 之后,您需要开始监听连接请求。
调用"listen()" 函数并传递最大允许连接数作为参数。
第八步:接受连接一旦有连接请求进来,您可以使用"accept()" 函数来接受连接。
lwip内存分配算法-回复lwIP(Lightweight IP)是一个开源的TCP/IP协议栈,专为嵌入式系统设计的。
内存分配算法是lwIP中一个重要的组成部分,它决定了lwIP如何在有限的嵌入式系统内存中分配和管理网络相关数据结构的存储空间。
本文将围绕lwIP内存分配算法展开,深入探讨其原理、实现方式和优化策略。
首先,我们需要了解lwIP内存的基本分配单位是一个叫做PBUF(Packet Buffer)的内存块。
PBUF是一个数据结构,用于存储和管理网络数据包的缓冲区。
lwIP采用了一个池内存管理机制,即将内存分成几个大小不同的池,每个池专门负责分配对应大小的PBUF,从而提高内存的利用效率。
lwIP内部维护了多个pbuf_pool_t结构体,每个结构体对应一个不同大小的PBUF池。
通过pbuf_pool_t结构体,lwIP可以追踪和管理池中每个PBUF的使用情况。
在初始化过程中,lwIP会根据预定义的配置文件,创建不同大小的PBUF池,以满足实际应用的需求。
一般来说,PBUF的大小可以分为以下几个类别:小型PBUF、中型PBUF 和大型PBUF。
小型PBUF用于存储较小的网络数据包,如TCP/IP头部信息;中型PBUF用于存储中等大小的数据包,如TCP/IP数据部分;大型PBUF用于存储较大的数据包,如文件传输。
在运行期间,当lwIP需要分配一个新的PBUF时,它会根据需要的大小选择对应的PBUF池进行分配和申请。
具体分配算法如下:1. 首先,lwIP通过pbuf_alloc()函数向内存池请求分配一个指定大小的PBUF。
2. 如果请求的大小大于最大的PBUF池大小,则直接通过malloc()函数从堆中申请一个新的PBUF,并将其加入PBUF池中,以备下次使用。
3. 如果请求的大小小于等于最大的PBUF池大小,则依次遍历每个PBUF 池,直到找到一个能满足请求大小的PBUF。
4. 如果找到一个可用的PBUF,并且其容量大于请求的大小,则将其分割成两个部分:一个用于分配,一个用于未使用的内存块。
lwip 编程方式-回复LWIP (Lightweight IP)是一种用于嵌入式系统的开源TCP/IP协议栈。
它专为资源受限的设备设计,如单片机和嵌入式系统。
LWIP提供了一组轻量级的API,可用于在这些设备上实现网络连接。
本文将一步一步介绍LWIP的编程方式,从设置和初始化开始,然后探讨TCP和UDP的使用,以及其他一些高级功能的实现。
第一步:设置和初始化LWIP的使用需要在项目中进行设置和初始化。
首先,我们需要在项目中引入LWIP库,并在相关文件中包含lwip.h头文件。
然后,在main函数中调用lwip_init()函数来初始化LWIP。
接下来,我们需要配置和初始化网络接口。
这可以通过调用lwip_netif_add函数来完成。
在这个函数中,我们需要指定网络接口的名称、IP地址和子网掩码等信息。
此外,我们还可以通过调用lwip_default_netif函数来设置默认网络接口。
第二步:TCP的使用一旦网络接口初始化完成,我们可以开始使用LWIP进行TCP通信。
首先,我们需要创建一个监听套接字,用于接受连接请求。
可以通过调用lwip_socket函数来创建一个套接字,并使用lwip_bind和lwip_listen函数来绑定和监听套接字。
当有连接请求到达时,我们可以通过调用lwip_accept函数来接受连接。
接下来,我们可以使用lwip_read和lwip_write函数来进行数据的读取和写入操作。
最后,我们需要使用lwip_close函数关闭套接字。
第三步:UDP的使用除了TCP,LWIP还支持UDP协议。
UDP是一种无连接的协议,适用于一对一或一对多的通信。
在LWIP中,我们可以通过lwip_udp_new函数创建一个UDP套接字。
创建UDP套接字后,我们可以使用lwip_recvfrom和lwip_sendto函数来进行数据的接收和发送操作。
与TCP不同,UDP不需要进行连接的建立和维护,因此可以实现更低延迟的通信。
lwip tcpip_callback函数使用lwIP(轻量级IP)是一个开源的TCP/IP协议栈,专为嵌入式系统而设计。
在lwIP中,tcpip_callback函数是一个核心机制,用于处理来自网络接口的输入数据包以及执行定时器回调。
tcpip_callback函数通常不是由应用程序直接调用的,而是由lwIP的内部机制(如底层网络接口驱动程序)在接收到数据包时调用,或者由lwIP的内部定时器在需要执行定时器回调时调用。
但是,当你使用lwIP并想要处理网络事件时,你通常会注册你自己的回调函数,而不是直接使用tcpip_callback。
例如,你可能会注册一个回调函数来处理接收到的TCP数据,或者处理TCP连接的状态变化。
以下是一些与lwIP回调相关的常见概念和使用方法:1.网络接口的输入处理:当网络接口接收到一个数据包时,它会通过调用lwIP的内部函数来处理这个数据包。
这个过程最终会调用tcpip_input函数,该函数会进一步处理数据包,并可能触发与TCP、UDP或其他协议相关的回调函数。
2.注册回调函数:对于TCP连接,你可能会使用tcp_accept函数来注册一个“接受”回调函数,当一个新的TCP连接建立时,这个函数会被调用。
对于已经建立的TCP连接,你可以使用tcp_recv函数来注册一个“接收”回调函数,当有数据到达时,这个函数会被调用。
3.定时器回调:lwIP使用内部定时器来处理各种定时任务,如TCP重传、ARP请求等。
这些定时任务也可能间接地触发一些回调函数。
然而,应用程序通常不会直接处理这些定时器的回调;相反,它们是通过lwIP的内部机制自动管理的。
4.自定义回调:如果你想要实现自定义的网络处理逻辑,你应该查看lwIP提供的API函数,如tcp_new、tcp_bind、tcp_listen、udp_new、udp_bind等,这些函数允许你设置和控制TCP/UDP连接,并注册你自己的回调函数来处理网络事件。
2) sys_thread_new sys_arch_timeouts相关的三个全局变量如下struct sys_timeouts lwip_timeouts[LWIP_TASK_MAX];//为每一个由sys_thread_new创建的任务分配一个存放信号量超时信息的列表struct sys_timeouts null_timeouts;//为一个超过任务上限数的任务和不是由sys_thread_new创建的任务取超时列表时返回使用。
MMAC_RTOS_TASK_ID LWIP_TASKS[LWIP_TASK_MAX];//任务id存放顺序与lwip_timeouts相对应sys_thread_new用来创建一个新的任务,保存任务ID。
sys_arch_timeouts//就是通过取得任务ID返回任务对应的timeouts结构,从而可以添加、删除和判断超时的功能/*** Create a one-shot timer (aka timeout). Timeouts are processed in the* following cases:* - while waiting for a message using sys_mbox_fetch()* - while waiting for a semaphore using sys_sem_wait() or sys_sem_wait_timeout()* - while sleeping using the inbuilt sys_msleep()** @param msecs time in milliseconds after that the timer should expire* @param h callback function to call when msecs have elapsed* @param arg argument to pass to the callback function*/voidsys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)sys_timeouts 只是一个指向下一个的sys_timeo的指针1、InternSocketInit();//TCP连接初始化1.1、lwIPInit(sDevPara.chMACAddr, 0, 0, 0, IPADDR_USE_DHCP);//! Initializes the lwIP TCP/IP stack.//!//! \param pucMAC is a pointer to a six byte array containing the MAC//! address to be used for the interface.//! \param ulIPAddr is the IP address to be used (static).//! \param ulNetMask is the network mask to be used (static).//! \param ulGWAddr is the Gateway address to be used (static).//! \param ulIPMode is the IP Address Mode. \b IPADDR_USE_STA TIC will force //! static IP addressing to be used, \b IPADDR_USE_DHCP will force DHCP with//! fallback to Link Local (Auto IP), while \b IPADDR_USE_AUTOIP will force//! Link Local only.//!//! This function performs initialization of the lwIP TCP/IP stack for the//! Stellaris Ethernet MAC, including DHCP and/or AutoIP, as configured.//!//! \return None.1.1.1、tcpip_init(lwIPPrivateInit, 0); 这个地方用到了回调函数tcpip_init(void (* initfunc)(void *),void *arg)什么是指针函数?函数指针是指向函数的指针变量。
标题:lwIP TCP接收数据回调函数随着互联网的发展,TCP/IP协议在网络通信中扮演着非常重要的角色。
lwIP是一个轻量级的TCP/IP协议栈,被广泛应用于嵌入式设备和物联网领域。
在lwIP中,TCP接收数据时,需要注册一个回调函数用于处理接收到的数据。
本文将介绍lwIP中TCP接收数据回调函数的相关知识和使用方法。
一、lwIP简介1. lwIP是一个轻量级的TCP/IP协议栈,适用于嵌入式系统和物联网设备。
2. lwIP实现了TCP、UDP、IP、ICMP等协议,提供了丰富的API接口用于网络通信。
3. lwIP的特点包括占用资源少、代码精简、易于移植等,适合于资源有限的嵌入式系统。
二、TCP接收数据回调函数的作用1. TCP接收数据时,需要注册一个回调函数来处理接收到的数据。
2. 回调函数是一个用户自定义的函数,用于处理接收到的数据,可以进行数据解析、处理、存储等操作。
3. 回调函数的注册是在TCP连接建立之后进行的。
三、lwIP中TCP接收数据回调函数的注册方法1. 在lwIP中,注册TCP接收数据回调函数的方法如下:- 创建一个用于处理接收数据的回调函数,可以是全局函数或者静态函数。
- 调用lwIP提供的接口将回调函数注册到TCP连接上。
2. 代码示例:```c// 定义回调函数err_t recv_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err){// 处理接收到的数据// ...return ERR_OK;}// 注册回调函数tcp_recv(tpcb, recv_callback);```四、回调函数参数说明1. 回调函数的参数包括:- arg:用户自定义参数,可以在注册回调函数时传入,在回调函数中可以使用。
- tpcb:TCP控制块,用于标识TCP连接的状态和属性。
- p:指向接收到的数据的pbuf链表。
lwip 样例编译-回复LwIP(Lightweight IP)是一个轻量级的开源TCP/IP协议栈,专门用于嵌入式系统。
它具有尺寸小巧、资源占用低以及高度可移植性等优点,使其成为许多嵌入式设备的首选协议栈。
本文将详细介绍LwIP的样例编译过程,以帮助读者更好地理解和使用该协议栈。
首先,我们需要准备开发环境。
LwIP支持多个平台和编译器,包括Windows、Linux、FreeRTOS等。
在本文中,我们以Windows平台和GCC编译器为例。
以下是编译LwIP样例所需的环境搭建步骤:1. 下载LwIP源码:从LwIP官方网站(2. 安装GCC编译器:在Windows平台上,我们可以使用MinGW (Minimalist GNU for Windows)来安装GCC编译器。
下载MinGW 安装程序并按照安装向导进行安装。
确保将MinGW的bin目录(例如C:\MinGW\bin)添加到系统环境变量的PATH中。
3. 配置LwIP源码:在LwIP源码根目录下,找到Makefile文件并用文本编辑器打开。
根据实际需求修改Makefile中的配置选项。
例如,可以配置IP地址、网关、DNS服务器等。
确认配置完成后保存文件。
4. 打开命令行终端:按下Win键+R,在运行对话框中输入"cmd"并按下回车键,打开命令行终端。
5. 进入LwIP源码目录:在命令行终端中,使用"cd"命令进入LwIP源码根目录。
例如,输入"cd C:\lwip"。
6. 编译样例:执行"mingw32-make"命令开始编译LwIP样例。
编译过程可能需要几分钟的时间,具体时间取决于源码大小和计算机性能。
7. 检查编译结果:编译完成后,在LwIP源码根目录下的"src"目录中会生成可执行文件。
用文本编辑器打开"src"目录下的相关文件,查看编译结果和输出。
这段时间在STM32F107调试lwIP心得开发板:STM3210C-EV AL(STM原厂开发板,用起来确实很爽)因为公司有项目,要做一个以太网的通讯模块,所以这段时间就一直在调试lwIP裸机程序。
大体上实现了lwIP的UDP通讯。
后续对UDP传输协议中的数据分析、控制等都会很快就出来了。
在lwIP中实现UDP协议的客户端,主要过程如下:unsigned char const UDPArr[6] = {"hello!"};int main(void){struct udp_pcb *Udppcb1 ;struct ip_addr ipaddr1 ;struct pbuf *p ;/* Setup STM32 system (clocks, Ethernet, GPIO, NVIC) and STM3210C-EV AL resources */ System_Setup();/* Initilaize the LwIP satck */LwIP_Init();//测试UDP客户端发送数据p = pbuf_alloc( PBUF_RA W , sizeof(UDPArr) , PBUF_RAM ) ;p->payload = ( void *)(UDPArr) ;IP4_ADDR(&ipaddr1 , 192,168,1,11);Udppcb1 = udp_new( ) ;udp_bind( Udppcb1 , IP_ADDR_ANY , 161 ) ;udp_connect( Udppcb1 , &ipaddr1 , 161 ) ;udp_send( Udppcb1 , p ) ;/* Infinite loop */while (1){/* Periodic tasks */System_Periodic_Handle();}}大体解释一下:该程序就是将开发板作为一个UDP客户端,不停的向主机发送“hello!”字符,目前已经实现,程序完整调试通过。
没有上系统,lwip裸奔,raw/callback方式调用UDP函数通过环回接口自发自收。
首先是移植,用户需要编写的文件有cc.h,perf.h,cpu.h,lwipopts.h,参考的是st官方代码和lwip的移植说明。
然后stm32的时钟以及串口再加一个定时器配置好,串口输出调试信息,定时器周期更新ARP table和维护TCP slow/fast timer,最重要的是这里用到的环回接口需要周期性调用netif_poll这个函数,把环回接口中收到的数据递交给IP层。
用伪代码描述一下出错的代码:
Stm32时钟外设初始化;
Lwip初始化;
建立一个UDP客户端,绑定127.0.0.1,连接至UDP服务器;
建立一个UDP服务器,绑定127.0.0.1;连接至UDP客户端;
申请内存,
把数据填至内存;
While{
周期调用tcp_tmr();
周期调用etharp_tmr();
周期发送数据udp_sendto();
netif_poll();
}
结果是第一次发送和接收都正常,第二次开始就出错,经跟踪,到第二次发送前发现错误原因。
首次发送,接收后申请的内存已释放,再次发送前必须再次申请内存且填充用户数据;
改正后
Stm32时钟外设初始化;
Lwip初始化;
建立一个UDP客户端,绑定127.0.0.1,连接至UDP服务器;
建立一个UDP服务器,绑定127.0.0.1;连接至UDP客户端;
While{
周期调用tcp_tmr();
周期调用etharp_tmr();
周期申请内存并填充数据,然后用周期发送数据udp_sendto()发送数据;
netif_poll();
}
至此数据可以正常收发,但是还是高兴早了,程序跑了一会就停了,重启跑了一会又停了,发现每次都是收发223次后停止,开始怀疑是不是内存泄露了,排查中...
在周期申请内存后,检查是否申请成功,不成功打印输出信息;(单片机初学者没上过系统和协议栈,没有用过动态内存分配,这点常识没有,好羞愧。
)果不其然,224次输出memory error
找到问题所在了,就是内存泄露,但是哪里泄露呢?在Udp的接收处理回调函数里最后释放pbuf了呀,怎么回事,排查中...
开始试探:每一次发送11个字节223次时内存不足;
每一次发送196个字节75次时内存不足;
一觉醒来,已经是第二天早上,用keil仿真,看内存区,的确是被占的满满的,开始跟踪调试...
有重大发现,netif_loop_output该函数会申请内存,并把用户数据赋值到其中,而后递交给IP进而UDP,最终至用户,我之前在回调函数里只是把netif_loop_output申请的内存给释放了,而我自个发送前申请的内存未释放,好了改代码如下:
Stm32时钟外设初始化;
Lwip初始化;
建立一个UDP客户端,绑定127.0.0.1,连接至UDP服务器;
建立一个UDP服务器,绑定127.0.0.1;连接至UDP客户端;
While{
周期调用tcp_tmr();
周期调用etharp_tmr();
周期申请内存并填充数据,然后用周期发送数据udp_sendto()发送数据,
发送完毕释放内存;
netif_poll();
}
至此OK;。