0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

利用LWIP 2.2实现以太网的DHCP功能

Geehy极海半导体 来源:21ic论坛极海半导体专区 2024-11-26 14:37 次阅读

最近学习了LWIP,了解到目前LWIP的版本已经更新到了2.2版本。LWIP 2.2相较于之前的版本,在协议支持、性能、安全性等方面都有了显著的改进,我将在本帖中探讨如何利用LWIP 2.2来实现以太网的DHCP功能,并分享一些我所获得的经验。

1.LWIP简介

LWIP代表"轻量级IP"(Lightweight IP),是一个嵌入式系统中常用的开源TCP/IP协议栈。它被设计成小巧、高效,适用于资源受限的系统,如嵌入式设备、物联网设备等。LWIP提供了包括IPv4/IPv6协议、TCP、UDP、ICMP等在内的各种网络协议的实现,同时支持各种设备接口操作系统。通过使用LWIP,开发者可以方便地将网络连接功能集成到他们的嵌入式系统中,而无需从头开始实现网络协议栈。

LWIP1.4.1与LWIP2.2的对比

特性/方面 LWIP1.4.1 LWIP2.2
协议支持 TCP、UDP、IP、ICMP、DHCP、DNS、PPP等 TCP、UDP、IP、ICMP、DHCP、DNS、PPP等,还包括TLS(实验性)
性能 基本性能优化 改进的性能优化
安全性 有限的安全性功能 增强的安全性功能
API变更 稳定的API 一些API变更和新增
Bug修复 针对已知问题的Bug修复 为稳定性进行的Bug修复和补丁
兼容性 与现有LWIP1.x代码兼容 与现有LWIP1.x代码兼容,但可能需要适应性修改
文档 提供了LWIP1.4.1文档 更新的LWIP2.2文档
内存使用 适度的内存使用 优化的内存使用
多线程支持 有限或无多线程支持 改进的多线程支持
TLS支持
(安全增强)
不可用 实验性的TLS支持

这里列举了从LWIP1.4.1到目前最新的LWIP2.2版本主要的一些修改点。具体详细的组件支持可去LWIP官网了解。

2.DHCP介绍

DynamicHost Configuration Protocol(DHCP)是一种网络协议,用于在计算机网络上自动分配IP地址和其他网络配置信息。DHCP的主要目的是简化网络管理,避免手动配置每台计算机的网络参数。

以下是DHCP的一些关键特性和工作原理

1. 自动IP地址分配:DHCP允许网络中的设备自动获取IP地址,而无需管理员手动配置。这对于大型网络特别有用,因为手动分配IP地址可能会变得繁琐和容易出错。

2. 动态分配:DHCP支持动态分配IP地址,这意味着设备在每次连接到网络时可以获得不同的IP地址。这有助于更有效地利用可用的IP地址池。

3. 配置其他网络参数:除了IP地址之外,DHCP还可以分配其他网络配置信息,如子网掩码、默认网关、DNS服务器地址等。这些信息是设备与网络通信所需的关键参数。

4. 租约机制:DHCP通过租约机制来管理分配的IP地址。设备获得一个IP地址并与DHCP服务器建立租约,这个租约在一定时间内有效。设备可以选择在租约到期前续租或请求新的租约。

5. DHCP服务器:网络中通常有一个或多个DHCP服务器,它们负责分配IP地址和配置信息。当设备连接到网络时,它们发送DHCP请求,DHCP服务器收到请求后分配一个可用的IP地址和相关配置信息。

6. DHCP客户端:设备上运行的DHCP客户端负责向网络中的DHCP服务器发送请求以获取IP地址和配置信息。DHCP客户端通常在设备启动时触发DHCP过程。

7. 广播通信:DHCP通信通常使用广播方式进行。DHCP客户端在网络上广播一个请求,DHCP服务器接收到请求后回应,然后客户端使用分配的IP地址和配置信息进行通信。

总体而言,DHCP简化了网络管理过程,使得设备可以更轻松地连接到网络而无需手动配置网络参数。 DHCP在家庭网络、企业网络和大型互联网服务提供商(ISP)网络中广泛应用。

3.使用LWIP2.2搭建ETH DHCP例程

首先,介绍一下该例程主要实现的功能。

1.可以实时检测以太网是否断开,并将信息打印在串口上。

2.开发板复位后首先获取DHCP服务器分配的IP地址。若无法查找到DHCP(设置的时间是60s),开发板会使用默认的静态IP地址。

3.1 访问官网,下载LWIP2.2源码

官网:https://savannah.nongnu.org/projects/lwip

5fc03846-a656-11ef-93f3-92fbcf53809c.jpg

3.2 解压,复制到工程目录下,并在工程中添加相关文件。

5fde1f1e-a656-11ef-93f3-92fbcf53809c.jpg

我这里是按文件分类添加的,可以自定义添加。

3.3 编写main函数

int main(void)

{

char LCDDisplayBuf[100] = {0};

struct ip4_addr DestIPaddr;

uint8_t flag = 0;

USART_Config_T usartConfig;

/* User config the different system Clock */

UserRCMClockConfig();

/* Configure SysTick */

ConfigSysTick();

/* Configure USART */

usartConfig.baudRate = 115200;

usartConfig.wordLength = USART_WORD_LEN_8B;

usartConfig.stopBits = USART_STOP_BIT_1;

usartConfig.parity = USART_PARITY_NONE ;

usartConfig.mode = USART_MODE_TX_RX;

usartConfig.hardwareFlow = USART_HARDWARE_FLOW_NONE;

APM_BOARD_COMInit(COM1,&usartConfig);

/* Configures LED2 and LED3 */

APM_BOARD_LEDInit(LED2);

APM_BOARD_LEDInit(LED3);

/* KEY init*/

APM_BOARD_PBInit(BUTTON_KEY1, BUTTON_MODE_GPIO);

APM_BOARD_PBInit(BUTTON_KEY2, BUTTON_MODE_GPIO);

printf("This is a ETH TCP Client Demo! ");

/* Configure ethernet (GPIOs, clocks, MAC, DMA) */

ConfigEthernet();

/* Initilaize the LwIP stack */

LwIP_Init();

#ifndef USE_DHCP

/* Use Com printf static IP address*/

sprintf(LCDDisplayBuf,"TINY board Static IP address ");

printf("%s",LCDDisplayBuf);

sprintf(LCDDisplayBuf,"IP: %d.%d.%d.%d ",

IP_ADDR0,

IP_ADDR1,

IP_ADDR2,

IP_ADDR3);

printf("%s",LCDDisplayBuf);

sprintf(LCDDisplayBuf,"NETMASK: %d.%d.%d.%d ",

NETMASK_ADDR0,

NETMASK_ADDR1,

NETMASK_ADDR2,

NETMASK_ADDR3);

printf("%s",LCDDisplayBuf);

sprintf(LCDDisplayBuf,"Gateway: %d.%d.%d.%d ",

GW_ADDR0,

GW_ADDR1,

GW_ADDR2,

GW_ADDR3);

printf("%s",LCDDisplayBuf);

sprintf(LCDDisplayBuf,"TCP Server IP: %d.%d.%d.%d:%d ",

COMP_IP_ADDR0,

COMP_IP_ADDR1,

COMP_IP_ADDR2,

COMP_IP_ADDR3,

COMP_PORT);

printf("%s",LCDDisplayBuf);

#endif

// printf(" KEY1: Connect TCP server ");

// printf("KEY2: Disconnect TCP server ");

while(1)

{

if ((APM_TINY_PBGetState(BUTTON_KEY1)==0)&&(flag==0))

{

APM_TINY_LEDOn(LED2);

if (EthLinkStatus == 0)

{

/* connect to tcp server */

printf(" Connect TCP server ");

IP4_ADDR( &DestIPaddr, COMP_IP_ADDR0, COMP_IP_ADDR1, COMP_IP_ADDR2, COMP_IP_ADDR3 );

tcpc_echo_init(&DestIPaddr,COMP_PORT);

flag=1;

}

}

if ((APM_TINY_PBGetState(BUTTON_KEY2)==0)&&(flag==1))

{

APM_TINY_LEDOff(LED2);

printf(" Disconnect TCP server ");

tcpc_echo_disable();

flag=0;

}

/* check if any packet received */

if (ETH_CheckReceivedFrame())

{

/* process received ethernet packet */

LwIP_Pkt_Handle();

}

/* handle periodic timers for LwIP */

LwIP_Periodic_Handle(ETHTimer);

}

}

main函数主要是对一些串口、GPIO的初始化操作。我在main.h中定义了一个USE_DHCP的宏,我们可以打开或注释掉这个宏,选择是否开启DHCP功能。

3.4 LWIP_Init()函数

void LwIP_Init(void)

{

struct ip4_addr ipaddr;

struct ip4_addr netmask;

struct ip4_addr gw;

/* Initializes the dynamic memory heap */

mem_init();

/* Initializes the memory pools */

memp_init();

#ifdef USE_DHCP

ipaddr.addr = 0;

netmask.addr = 0;

gw.addr = 0;

#else

IP4_ADDR(&ipaddr, IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);

IP4_ADDR(&netmask, NETMASK_ADDR0, NETMASK_ADDR1 , NETMASK_ADDR2, NETMASK_ADDR3);

IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);

#endif

/* Config MAC Address */

ETH_ConfigMACAddress(ETH_MAC_ADDRESS0, SetMACaddr);

/* Add a network interface to the list of lwIP netifs */

netif_add(&UserNetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input);

/* Registers the default network interface */

netif_set_default(&UserNetif);

if (ETH_ReadPHYRegister(ETH_PHY_ADDRESS, PHY_BSR) & 1)

{

UserNetif.flags |= NETIF_FLAG_LINK_UP;

/* When the netif is fully configured this function must be called */

netif_set_up(&UserNetif);

#ifdef USE_DHCP

DHCP_state = DHCP_START;

#endif

}

else

{

netif_set_down(&UserNetif);

#ifdef USE_DHCP

DHCP_state = DHCP_LINK_DOWN;

#endif /* USE_DHCP */

printf("network cable is not connected! ");

}

netif_set_link_callback(&UserNetif, ETH_link_callback);

}

这段代码是用于初始化LwIP网络堆栈的函数 LwIP_Init。让我们逐步分析其功能:

1. 初始化IP地址、子网掩码和网关地址的结构体变量 ipaddr、netmask 和 gw。

2. 初始化动态内存堆。

3. 初始化内存池。

4. 根据是否启用了DHCP,设置IP地址、子网掩码和网关地址。

5. 配置MAC地址。

6. 将一个网络接口添加到lwIP网络接口列表中。

7. 注册默认的网络接口。

8. 通过读取PHY寄存器的状态来判断网络连接状态:

- 如果连接状态为链接状态,设置网络接口的标志为链接已建立,将网络接口设置为已启用,并根据是否启用了DHCP,设置DHCP状态为启动。

- 如果连接状态为断开状态,将网络接口设置为已关闭,并根据是否启用了DHCP,设置DHCP状态为链接断开,并打印消息表示网络电缆未连接。

9. 设置网络接口的链接状态回调函数为 ETH_link_callback。

综上所述,该函数主要用于初始化LwIP网络堆栈。它包括初始化内存堆和内存池、配置网络接口的IP地址信息、MAC地址、添加网络接口到lwIP列表中、判断网络连接状态并相应地设置网络接口状态和DHCP状态,最后设置网络接口的链接状态回调函数。

3.5 ETH_link_callback函数

void ETH_link_callback(struct netif *netif)

{

__IO uint32_t timeout = 0;

uint16_t RegValue;

struct ip4_addr ipaddr;

struct ip4_addr netmask;

struct ip4_addr gw;

if(netif_is_link_up(netif))

{

/* Restart the auto-negotiation */

if(ETH_InitStructure.autoNegotiation == ETH_AUTONEGOTIATION_ENABLE)

{

/* Reset Timeout counter */

timeout = 0;

/* Enable auto-negotiation */

ETH_WritePHYRegister(ETH_PHY_ADDRESS, PHY_BCR, PHY_AUTONEGOTIATION);

/* Wait until the auto-negotiation will be completed */

do

{

timeout++;

} while (!(ETH_ReadPHYRegister(ETH_PHY_ADDRESS, PHY_BSR) & PHY_AUTONEGO_COMPLETE) && (timeout < (uint32_t)PHY_READ_TIMEOUT));  

/* Reset Timeout counter */

timeout = 0;

/* Read the result of the auto-negotiation */

RegValue = ETH_ReadPHYRegister(ETH_PHY_ADDRESS, PHY_SR);

/* Configure the MAC with the Duplex Mode fixed by the auto-negotiation process */

if((RegValue & PHY_DUPLEX_STATUS) != (uint16_t)RESET)

{

/* Set Ethernet duplex mode to Full-duplex following the auto-negotiation */

ETH_InitStructure.mode = ETH_MODE_FULLDUPLEX;

}

else

{

/* Set Ethernet duplex mode to Half-duplex following the auto-negotiation */

ETH_InitStructure.mode = ETH_MODE_HALFDUPLEX;

}

/* Configure the MAC with the speed fixed by the auto-negotiation process */

if(RegValue & PHY_SPEED_STATUS)

{

/* Set Ethernet speed to 10M following the auto-negotiation */

ETH_InitStructure.speed = ETH_SPEED_10M;

}

else

{

/* Set Ethernet speed to 100M following the auto-negotiation */

ETH_InitStructure.speed = ETH_SPEED_100M;

}

/*------------------------ ETHERNET MACCR Re-Configuration --------------------*/

/* Set the FES bit according to ETH_Speed value */

/* Set the DM bit according to ETH_Mode value */

ETH->CFG_B.SSEL = ETH_InitStructure.speed;

ETH->CFG_B.DM = ETH_InitStructure.mode;

Delay(0x00000001);

}

/* Restart MAC interface */

ETH_Start();

#ifdef USE_DHCP

ipaddr.addr = 0;

netmask.addr = 0;

gw.addr = 0;

DHCP_state = DHCP_START;

#else

IP4_ADDR(&ipaddr, IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);+

IP4_ADDR(&netmask, NETMASK_ADDR0, NETMASK_ADDR1 , NETMASK_ADDR2, NETMASK_ADDR3);

IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);

#endif /* USE_DHCP */

netif_set_addr(&UserNetif, &ipaddr , &netmask, &gw);

/* When the netif is fully configured this function must be called.*/

netif_set_up(&UserNetif);

/* Display message on the LCD */

printf("network cable is connected now ! ");

EthLinkStatus = 0;

}

else

{

ETH_Stop();

#ifdef USE_DHCP

DHCP_state = DHCP_LINK_DOWN;

dhcp_stop(netif);

#endif /* USE_DHCP */

/* When the netif link is down this function must be called.*/

netif_set_down(&UserNetif);

printf("network cable is unplugged! ");

}

}

这段代码是一个用于处理以太网链接状态变化的回调函数 ETH_link_callback。让我们逐步分析它的功能:

1. 首先,声明了一些变量,包括超时计数器 timeout、存储从PHY读取的寄存器值的变量 RegValue,以及用于存储IP地址、子网掩码和网关地址的变量。

2. 如果网络接口的链接状态为链接状态(通过 netif_is_link_up(netif) 判断):

- 如果启用了以太网自动协商(ETH_InitStructure.autoNegotiation== ETH_AUTONEGOTIATION_ENABLE),则重新启动自动协商过程:

- 向PHY寄存器写入自动协商命令 PHY_AUTONEGOTIATION。

- 等待自动协商完成,超时时间由 PHY_READ_TIMEOUT 定义。

- 读取自动协商结果,根据结果配置以太网MAC的速度和双工模式。

- 根据速度和双工模式重新配置以太网MAC控制器的寄存器。

- 重新启动MAC接口。

- 根据是否启用了DHCP,设置IP地址、子网掩码和网关地址,并将网络接口标记为已启用。

- 打印消息,表示网络电缆已连接。

- 将 EthLinkStatus 标记为链接状态。

3. 如果网络接口的链接状态为断开状态,执行以下操作:

- 停止MAC接口。

- 如果启用了DHCP,将DHCP状态设置为链接断开,并停止DHCP客户端。

- 将网络接口标记为已关闭。

- 打印消息,表示网络电缆已拔出。

综上所述,该函数主要用于处理以太网链接状态的变化。根据链接状态的变化,重新启动自动协商过程(如果启用了自动协商),配置以太网MAC的参数,并设置IP地址信息。同时,根据链接状态的变化执行相应的动作,例如重新启动或停止MAC接口,并更新相应的状态标志。

3.6 LwIP_Periodic_Handle

void LwIP_Periodic_Handle(__IO uint32_t ETHTimer)

{

static uint8_t flagToggle = 0;

#if LWIP_TCP

/* TCP periodic process every 250 ms */

if (ETHTimer - TCPTimer >= TCP_TMR_INTERVAL)

{

TCPTimer = ETHTimer;

tcp_tmr();

}

#endif

/* ARP periodic process every 5s */

if ((ETHTimer - ARPTimer) >= ARP_TMR_INTERVAL)

{

ARPTimer = ETHTimer;

etharp_tmr();

}

/* Check link status */

if ((ETHTimer - LinkTimer) >= 1000)

{

if ((ETH_GET_LINK_STATUS != 0) && (flagToggle == 0))

{

/* link goes up */

netif_set_link_up(&UserNetif);

flagToggle = 1;

}

if ((ETH_GET_LINK_STATUS == 0) && (flagToggle == 1))

{

EthLinkStatus = 1;

/* link goes down */

netif_set_link_down(&UserNetif);

flagToggle = 0;

}

}

#ifdef USE_DHCP

/* Fine DHCP periodic process every 500ms */

if (ETHTimer - DHCPfineTimer >= DHCP_FINE_TIMER_MSECS)

{

DHCPfineTimer = ETHTimer;

dhcp_fine_tmr();

if ((DHCP_state != DHCP_ADDRESS_ASSIGNED) &&

(DHCP_state != DHCP_TIMEOUT) &&

(DHCP_state != DHCP_LINK_DOWN))

{

/* toggle LED1 to indicate DHCP on-going process */

APM_TINY_LEDOn(LED2);

/* process DHCP state machine */

LwIP_DHCP_Process_Handle();

}

}

/* DHCP Coarse periodic process every 60s */

if (ETHTimer - DHCPcoarseTimer >= DHCP_COARSE_TIMER_MSECS)

{

DHCPcoarseTimer = ETHTimer;

dhcp_coarse_tmr();

}

#endif

}

以上函数是一个用于处理LwIP(Lightweight IP)网络堆栈的周期性任务的函数。让我们逐段分析它:

1.staticuint8_t flagToggle = 0;:定义了一个静态变量 flagToggle,用于跟踪网络连接状态的变化。

2. if(ETHTimer - TCPTimer >= TCP_TMR_INTERVAL):检查TCP定时器是否超过了TCP_TMR_INTERVAL(TCP定时器间隔),如果超过,则调用 tcp_tmr() 函数进行TCP定时器处理。

3. if((ETHTimer - ARPTimer) >= ARP_TMR_INTERVAL):检查ARP定时器是否超过了ARP_TMR_INTERVAL(ARP定时器间隔),如果超过,则调用 etharp_tmr() 函数进行ARP定时器处理。

4. if((ETHTimer - LinkTimer) >= 1000):检查链接状态是否需要更新,如果超过了一定时间(这里设置为1000ms),则进行链接状态检查。

5. if((ETH_GET_LINK_STATUS != 0) && (flagToggle == 0)):检查网络链接状态是否正常,并且之前的状态是断开的,如果是,则设置网络接口为链接状态。

6. if((ETH_GET_LINK_STATUS == 0) && (flagToggle == 1)):检查网络链接状态是否异常,并且之前的状态是连接的,如果是,则设置网络接口为断开状态。

7. if(ETHTimer - DHCPfineTimer >= DHCP_FINE_TIMER_MSECS):检查是否需要进行DHCP的Fine定时处理,如果超过了DHCP_FINE_TIMER_MSECS(Fine定时器间隔),则调用 dhcp_fine_tmr() 函数。

8. if(ETHTimer - DHCPcoarseTimer >= DHCP_COARSE_TIMER_MSECS):检查是否需要进行DHCP的Coarse定时处理,如果超过了DHCP_COARSE_TIMER_MSECS(Coarse定时器间隔),则调用 dhcp_coarse_tmr() 函数。

在整个函数中,主要处理了TCP、ARP、网络链接状态和DHCP的周期性任务。这些任务包括定时器的处理以及相应的动作,例如发送ARP请求、更新网络链接状态和处理DHCP状态机等。

3.7 LwIP_DHCP_Process_Handle

void LwIP_DHCP_Process_Handle(void)

{

struct ip4_addr ipaddr;

struct ip4_addr netmask;

struct ip4_addr gw;

uint8_t iptab[4] = {0};

char LCDDisplayBuf[100] = {0};

switch (DHCP_state)

{

case DHCP_START:

{

DHCP_state = DHCP_WAIT_ADDRESS;

dhcp_start(&UserNetif);

/* IP address should be set to 0

every time we want to assign a new DHCP address */

IPaddress = 0;

printf(" Looking for DHCP server, please wait..... ");

}

break;

case DHCP_WAIT_ADDRESS:

{

/* Read the new IP address */

struct dhcp *dhcp = netif_dhcp_data(&UserNetif);

if (dhcp->offered_ip_addr.addr != 0 && dhcp->offered_sn_mask.addr != 0 && dhcp->offered_gw_addr.addr != 0)

{

DHCP_state = DHCP_ADDRESS_ASSIGNED;

printf("IP address assigned by a DHCP server! ");

IPaddress = dhcp->offered_ip_addr.addr;

iptab[0] = (uint8_t)(IPaddress >> 24);

iptab[1] = (uint8_t)(IPaddress >> 16);

iptab[2] = (uint8_t)(IPaddress >> 8);

iptab[3] = (uint8_t)(IPaddress);

IP4_ADDR(&ipaddr, iptab[3] ,iptab[2] , iptab[1] , iptab[0] );

sprintf(LCDDisplayBuf,"IP: %d.%d.%d.%d ",

iptab[3],

iptab[2],

iptab[1],

iptab[0]);

printf("%s",LCDDisplayBuf);

IPaddress = dhcp->offered_sn_mask.addr;

iptab[0] = (uint8_t)(IPaddress >> 24);

iptab[1] = (uint8_t)(IPaddress >> 16);

iptab[2] = (uint8_t)(IPaddress >> 8);

iptab[3] = (uint8_t)(IPaddress);

IP4_ADDR(&netmask, iptab[3] ,iptab[2] , iptab[1] , iptab[0] );

sprintf(LCDDisplayBuf,"NETMASK: %d.%d.%d.%d ",

iptab[3],

iptab[2],

iptab[1],

iptab[0]);

printf("%s",LCDDisplayBuf);

IPaddress = dhcp->offered_gw_addr.addr;

iptab[0] = (uint8_t)(IPaddress >> 24);

iptab[1] = (uint8_t)(IPaddress >> 16);

iptab[2] = (uint8_t)(IPaddress >> 8);

iptab[3] = (uint8_t)(IPaddress);

IP4_ADDR(&gw, iptab[3] ,iptab[2] , iptab[1] , iptab[0]);

sprintf(LCDDisplayBuf,"Gateway: %d.%d.%d.%d ",

iptab[3],

iptab[2],

iptab[1],

iptab[0]);

printf("%s",LCDDisplayBuf);

IPaddress = dhcp->server_ip_addr.addr;

iptab[0] = (uint8_t)(IPaddress >> 24);

iptab[1] = (uint8_t)(IPaddress >> 16);

iptab[2] = (uint8_t)(IPaddress >> 8);

iptab[3] = (uint8_t)(IPaddress);

sprintf(LCDDisplayBuf,"TCP Server IP: %d.%d.%d.%d ",

iptab[3],

iptab[2],

iptab[1],

iptab[0]);

printf("%s",LCDDisplayBuf);

// IP4_ADDR( &s_ipaddr, iptab[3] ,iptab[2] , iptab[1] , iptab[0] );

// udp_connect();

/* Stop DHCP */

dhcp_stop(&UserNetif);

// UserNetif.ip_addr.addr = ipaddr.addr;

// UserNetif.netmask.addr = netmask.addr;

// UserNetif.gw.addr = gw.addr;

netif_set_addr(&UserNetif, &ipaddr , &netmask, &gw);

APM_TINY_LEDOn(LED2);

}

else

{

/* DHCP timeout */

if (dhcp->tries > 4)

{

DHCP_state = DHCP_TIMEOUT;

/* Stop DHCP */

dhcp_stop(&UserNetif);

/* Static address used */

/* Use Com printf static IP address*/

printf("DHCP timeout! ");

/* Static address used */

IP4_ADDR(&ipaddr, IP_ADDR0 ,IP_ADDR1 , IP_ADDR2 , IP_ADDR3 );

IP4_ADDR(&netmask, NETMASK_ADDR0, NETMASK_ADDR1, NETMASK_ADDR2, NETMASK_ADDR3);

IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);

netif_set_addr(&UserNetif, &ipaddr , &netmask, &gw);

sprintf(LCDDisplayBuf,"TINY board Static IP address ");

printf("%s",LCDDisplayBuf);

sprintf(LCDDisplayBuf,"IP: %d.%d.%d.%d ",

IP_ADDR0,

IP_ADDR1,

IP_ADDR2,

IP_ADDR3);

printf("%s",LCDDisplayBuf);

sprintf(LCDDisplayBuf,"NETMASK: %d.%d.%d.%d ",

NETMASK_ADDR0,

NETMASK_ADDR1,

NETMASK_ADDR2,

NETMASK_ADDR3);

printf("%s",LCDDisplayBuf);

sprintf(LCDDisplayBuf,"Gateway: %d.%d.%d.%d ",

GW_ADDR0,

GW_ADDR1,

GW_ADDR2,

GW_ADDR3);

printf("%s",LCDDisplayBuf);

sprintf(LCDDisplayBuf,"TCP Server IP: %d.%d.%d.%d:%d ",

COMP_IP_ADDR0,

COMP_IP_ADDR1,

COMP_IP_ADDR2,

COMP_IP_ADDR3,

COMP_PORT);

printf("%s",LCDDisplayBuf);

APM_TINY_LEDOn(LED2);

}

}

}

break;

default: break;

}

}

这段代码是用于处理LwIP网络堆栈中DHCP过程的函数 LwIP_DHCP_Process_Handle。它通过状态机来处理DHCP过程的不同阶段。让我们逐步分析其功能:

1. 在 DHCP_START 状态下,将状态切换到 DHCP_WAIT_ADDRESS,并启动DHCP客户端。

2. 在 DHCP_WAIT_ADDRESS 状态下,如果DHCP客户端获得了IP地址、子网掩码和网关地址,将状态切换到 DHCP_ADDRESS_ASSIGNED,打印获得的IP地址、子网掩码和网关地址,并停止DHCP客户端。

3. 如果DHCP超时(尝试次数超过4次),将状态切换到 DHCP_TIMEOUT,停止DHCP客户端,并使用静态IP地址(如果配置了静态IP地址)。

综上所述,该函数主要用于处理LwIP网络堆栈中DHCP过程的不同阶段。根据DHCP状态的不同,执行不同的操作,例如启动DHCP客户端、处理获取到的IP地址信息、处理超时情况等。

4. 实验现象

1.串口打印相关信息

5fe3b852-a656-11ef-93f3-92fbcf53809c.jpg

2.正常获取IP后,cmd执行ping命令,正常通信

5ff26280-a656-11ef-93f3-92fbcf53809c.jpg

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 以太网
    +关注

    关注

    40

    文章

    5424

    浏览量

    171684
  • 嵌入式系统
    +关注

    关注

    41

    文章

    3592

    浏览量

    129464
  • TCP
    TCP
    +关注

    关注

    8

    文章

    1353

    浏览量

    79068
  • DHCP
    +关注

    关注

    0

    文章

    105

    浏览量

    19716
  • LwIP
    +关注

    关注

    2

    文章

    86

    浏览量

    27166

原文标题:APM32芯得 EP.46 | 增强以太网连接:使用LWIP 2.2实现动态主机配置协议(DHCP)

文章出处:【微信号:geehysemi,微信公众号:Geehy极海半导体】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    如何实现以太网功能的,是用F107或F407芯片自己移植Lwip还是采用SPI转以太网模块?

    一般大家是如何实现以太网功能的,是用F107或F407芯片自己移植Lwip还是采用SPI转以太网模块?
    发表于 05-17 06:49

    基于FPGA的万兆以太网接口的设计与实现

    基于FPGA的万兆以太网接口的设计与实现标准中万兆以太网物理层及媒质接入控制子层的相关协议以 应用物理环境为例,阐述了万兆以太网接口各个单元模块的
    发表于 08-11 15:48

    NIOS实现以太网

    基于NIOS2的嵌入式实现以太网通信
    发表于 09-08 12:39

    请问ATK-RM04_WIFI模块能实现以太网转WIFI功能吗?

    ATK-RM04_WIFI模块能不能实现以太网转WIFI功能???
    发表于 11-06 01:15

    请问嵌入式系统实现以太网,TCP/IP协议栈是都是移植的吗?

    想请教各位大神们。嵌入式系统实现以太网(比如stm32),TCP/IP协议栈是不是都是移植的。比如都移植LWIP。UIP等。而不是自己写啊…………感谢……
    发表于 03-13 02:22

    没有发现以太网

    PIC32以太网启动器套件II,编号:DM320004-2。我编译并下载了TCPIP演示应用程序,但是微芯片以太网发现器应用程序没有发现以太网,而不管在另一台计算机上重复这个过程。有人遇到过这个问题并找到解决办法吗?谢谢
    发表于 04-10 06:43

    请教大神怎样去实现以太网MAC子层协议?

    什么是以太网MAC子层协议?怎样去实现以太网MAC子层协议?
    发表于 05-06 10:33

    怎么实现以太网的光无线通信系统的设计?

    怎么实现以太网的光无线通信系统的设计?
    发表于 05-28 07:08

    如何利用STM32CubeMX实现FreeRTOS+LAN8720A+LWIP以太网ping通?

    如何利用STM32CubeMX实现FreeRTOS+LAN8720A+LWIP以太网ping通?
    发表于 02-22 07:49

    单片机实现以太网通讯硬件设计

    介绍以太网的帧协议和以太网控制芯片RTL8019AS的结构特性;介绍单片机控制RTL8019AS实现以太网通讯的硬件设计方案;采用c51语言实现RPP协议(地址解析协议),并进行了系统
    发表于 08-29 16:32 126次下载
    单片机<b class='flag-5'>实现以太网</b>通讯硬件设计

    ST有关以太网讲座课件

    ST公司培训有关以太网讲座课件,包括tcp/ip协议、以太网基础、Lwip、网卡设计与实现等等介绍
    发表于 03-07 11:50 20次下载

    以太网Lwip例程

    以太网Lwip例程
    发表于 12-06 16:53 28次下载
    <b class='flag-5'>以太网</b><b class='flag-5'>Lwip</b>例程

    AT89C52单片机实现以太网接口的控制设计

    随着互联网的迅速发展,网络用户飞速增长,在使用计算机进行网络互联的同时,各种家电设备、仪表设备及工业中数据采集与控制设备也在逐步走向网络化,基于此结合专用的以太网控制芯片RTL8019学习了利用单片机实现以太网接口的设计。
    发表于 03-03 11:17 2819次阅读
    AT89C52单片机<b class='flag-5'>实现以太网</b>接口的控制设计

    PLC如何实现以太网口无线通讯

    PLC若想实现以太网口无线通讯,首先我们需要确定好PLC型号,然后选择一个合适的通讯设备。比如如果是西门子S7-200PLC,就需要使用欧美PLC无线通讯终端,并且这个设备需要支持以太网口通讯。
    发表于 03-08 09:17 5070次阅读

    Android 9以太网功能移植以及设置IP地址

    基于Android 9实现以太网的IP地址设置和功能实现
    发表于 06-20 14:42 2次下载