RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

利用LWIP 2.2實(shí)現(xiàn)以太網(wǎng)的DHCP功能

Geehy極海半導(dǎo)體 ? 來(lái)源:21ic論壇極海半導(dǎo)體專(zhuān)區(qū) ? 2024-11-26 14:37 ? 次閱讀

最近學(xué)習(xí)了LWIP,了解到目前LWIP的版本已經(jīng)更新到了2.2版本。LWIP 2.2相較于之前的版本,在協(xié)議支持、性能、安全性等方面都有了顯著的改進(jìn),我將在本帖中探討如何利用LWIP 2.2來(lái)實(shí)現(xiàn)以太網(wǎng)的DHCP功能,并分享一些我所獲得的經(jīng)驗(yàn)。

1.LWIP簡(jiǎn)介

LWIP代表"輕量級(jí)IP"(Lightweight IP),是一個(gè)嵌入式系統(tǒng)中常用的開(kāi)源TCP/IP協(xié)議棧。它被設(shè)計(jì)成小巧、高效,適用于資源受限的系統(tǒng),如嵌入式設(shè)備、物聯(lián)網(wǎng)設(shè)備等。LWIP提供了包括IPv4/IPv6協(xié)議、TCP、UDP、ICMP等在內(nèi)的各種網(wǎng)絡(luò)協(xié)議的實(shí)現(xiàn),同時(shí)支持各種設(shè)備接口操作系統(tǒng)。通過(guò)使用LWIP,開(kāi)發(fā)者可以方便地將網(wǎng)絡(luò)連接功能集成到他們的嵌入式系統(tǒng)中,而無(wú)需從頭開(kāi)始實(shí)現(xiàn)網(wǎng)絡(luò)協(xié)議棧。

LWIP1.4.1與LWIP2.2的對(duì)比

特性/方面 LWIP1.4.1 LWIP2.2
協(xié)議支持 TCP、UDP、IP、ICMP、DHCP、DNS、PPP等 TCP、UDP、IP、ICMP、DHCP、DNS、PPP等,還包括TLS(實(shí)驗(yàn)性)
性能 基本性能優(yōu)化 改進(jìn)的性能優(yōu)化
安全性 有限的安全性功能 增強(qiáng)的安全性功能
API變更 穩(wěn)定的API 一些API變更和新增
Bug修復(fù) 針對(duì)已知問(wèn)題的Bug修復(fù) 為穩(wěn)定性進(jìn)行的Bug修復(fù)和補(bǔ)丁
兼容性 與現(xiàn)有LWIP1.x代碼兼容 與現(xiàn)有LWIP1.x代碼兼容,但可能需要適應(yīng)性修改
文檔 提供了LWIP1.4.1文檔 更新的LWIP2.2文檔
內(nèi)存使用 適度的內(nèi)存使用 優(yōu)化的內(nèi)存使用
多線程支持 有限或無(wú)多線程支持 改進(jìn)的多線程支持
TLS支持
(安全增強(qiáng))
不可用 實(shí)驗(yàn)性的TLS支持

這里列舉了從LWIP1.4.1到目前最新的LWIP2.2版本主要的一些修改點(diǎn)。具體詳細(xì)的組件支持可去LWIP官網(wǎng)了解。

2.DHCP介紹

DynamicHost Configuration Protocol(DHCP)是一種網(wǎng)絡(luò)協(xié)議,用于在計(jì)算機(jī)網(wǎng)絡(luò)上自動(dòng)分配IP地址和其他網(wǎng)絡(luò)配置信息。DHCP的主要目的是簡(jiǎn)化網(wǎng)絡(luò)管理,避免手動(dòng)配置每臺(tái)計(jì)算機(jī)的網(wǎng)絡(luò)參數(shù)。

以下是DHCP的一些關(guān)鍵特性和工作原理

1. 自動(dòng)IP地址分配:DHCP允許網(wǎng)絡(luò)中的設(shè)備自動(dòng)獲取IP地址,而無(wú)需管理員手動(dòng)配置。這對(duì)于大型網(wǎng)絡(luò)特別有用,因?yàn)槭謩?dòng)分配IP地址可能會(huì)變得繁瑣和容易出錯(cuò)。

2. 動(dòng)態(tài)分配:DHCP支持動(dòng)態(tài)分配IP地址,這意味著設(shè)備在每次連接到網(wǎng)絡(luò)時(shí)可以獲得不同的IP地址。這有助于更有效地利用可用的IP地址池。

3. 配置其他網(wǎng)絡(luò)參數(shù):除了IP地址之外,DHCP還可以分配其他網(wǎng)絡(luò)配置信息,如子網(wǎng)掩碼、默認(rèn)網(wǎng)關(guān)、DNS服務(wù)器地址等。這些信息是設(shè)備與網(wǎng)絡(luò)通信所需的關(guān)鍵參數(shù)。

4. 租約機(jī)制:DHCP通過(guò)租約機(jī)制來(lái)管理分配的IP地址。設(shè)備獲得一個(gè)IP地址并與DHCP服務(wù)器建立租約,這個(gè)租約在一定時(shí)間內(nèi)有效。設(shè)備可以選擇在租約到期前續(xù)租或請(qǐng)求新的租約。

5. DHCP服務(wù)器:網(wǎng)絡(luò)中通常有一個(gè)或多個(gè)DHCP服務(wù)器,它們負(fù)責(zé)分配IP地址和配置信息。當(dāng)設(shè)備連接到網(wǎng)絡(luò)時(shí),它們發(fā)送DHCP請(qǐng)求,DHCP服務(wù)器收到請(qǐng)求后分配一個(gè)可用的IP地址和相關(guān)配置信息。

6. DHCP客戶端:設(shè)備上運(yùn)行的DHCP客戶端負(fù)責(zé)向網(wǎng)絡(luò)中的DHCP服務(wù)器發(fā)送請(qǐng)求以獲取IP地址和配置信息。DHCP客戶端通常在設(shè)備啟動(dòng)時(shí)觸發(fā)DHCP過(guò)程。

7. 廣播通信:DHCP通信通常使用廣播方式進(jìn)行。DHCP客戶端在網(wǎng)絡(luò)上廣播一個(gè)請(qǐng)求,DHCP服務(wù)器接收到請(qǐng)求后回應(yīng),然后客戶端使用分配的IP地址和配置信息進(jìn)行通信。

總體而言,DHCP簡(jiǎn)化了網(wǎng)絡(luò)管理過(guò)程,使得設(shè)備可以更輕松地連接到網(wǎng)絡(luò)而無(wú)需手動(dòng)配置網(wǎng)絡(luò)參數(shù)。 DHCP在家庭網(wǎng)絡(luò)、企業(yè)網(wǎng)絡(luò)和大型互聯(lián)網(wǎng)服務(wù)提供商(ISP)網(wǎng)絡(luò)中廣泛應(yīng)用。

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

首先,介紹一下該例程主要實(shí)現(xiàn)的功能。

1.可以實(shí)時(shí)檢測(cè)以太網(wǎng)是否斷開(kāi),并將信息打印在串口上。

2.開(kāi)發(fā)板復(fù)位后首先獲取DHCP服務(wù)器分配的IP地址。若無(wú)法查找到DHCP(設(shè)置的時(shí)間是60s),開(kāi)發(fā)板會(huì)使用默認(rèn)的靜態(tài)IP地址。

3.1 訪問(wèn)官網(wǎng),下載LWIP2.2源碼

官網(wǎng):https://savannah.nongnu.org/projects/lwip

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

3.2 解壓,復(fù)制到工程目錄下,并在工程中添加相關(guān)文件。

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

我這里是按文件分類(lèi)添加的,可以自定義添加。

3.3 編寫(xiě)main函數(shù)

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函數(shù)主要是對(duì)一些串口、GPIO的初始化操作。我在main.h中定義了一個(gè)USE_DHCP的宏,我們可以打開(kāi)或注釋掉這個(gè)宏,選擇是否開(kāi)啟DHCP功能。

3.4 LWIP_Init()函數(shù)

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, eernetif_init, eernet_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網(wǎng)絡(luò)堆棧的函數(shù) LwIP_Init。讓我們逐步分析其功能:

1. 初始化IP地址、子網(wǎng)掩碼和網(wǎng)關(guān)地址的結(jié)構(gòu)體變量 ipaddr、netmask 和 gw。

2. 初始化動(dòng)態(tài)內(nèi)存堆。

3. 初始化內(nèi)存池。

4. 根據(jù)是否啟用了DHCP,設(shè)置IP地址、子網(wǎng)掩碼和網(wǎng)關(guān)地址。

5. 配置MAC地址。

6. 將一個(gè)網(wǎng)絡(luò)接口添加到lwIP網(wǎng)絡(luò)接口列表中。

7. 注冊(cè)默認(rèn)的網(wǎng)絡(luò)接口。

8. 通過(guò)讀取PHY寄存器的狀態(tài)來(lái)判斷網(wǎng)絡(luò)連接狀態(tài):

- 如果連接狀態(tài)為鏈接狀態(tài),設(shè)置網(wǎng)絡(luò)接口的標(biāo)志為鏈接已建立,將網(wǎng)絡(luò)接口設(shè)置為已啟用,并根據(jù)是否啟用了DHCP,設(shè)置DHCP狀態(tài)為啟動(dòng)。

- 如果連接狀態(tài)為斷開(kāi)狀態(tài),將網(wǎng)絡(luò)接口設(shè)置為已關(guān)閉,并根據(jù)是否啟用了DHCP,設(shè)置DHCP狀態(tài)為鏈接斷開(kāi),并打印消息表示網(wǎng)絡(luò)電纜未連接。

9. 設(shè)置網(wǎng)絡(luò)接口的鏈接狀態(tài)回調(diào)函數(shù)為 ETH_link_callback。

綜上所述,該函數(shù)主要用于初始化LwIP網(wǎng)絡(luò)堆棧。它包括初始化內(nèi)存堆和內(nèi)存池、配置網(wǎng)絡(luò)接口的IP地址信息、MAC地址、添加網(wǎng)絡(luò)接口到lwIP列表中、判斷網(wǎng)絡(luò)連接狀態(tài)并相應(yīng)地設(shè)置網(wǎng)絡(luò)接口狀態(tài)和DHCP狀態(tài),最后設(shè)置網(wǎng)絡(luò)接口的鏈接狀態(tài)回調(diào)函數(shù)。

3.5 ETH_link_callback函數(shù)

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! ");

}

}

這段代碼是一個(gè)用于處理以太網(wǎng)鏈接狀態(tài)變化的回調(diào)函數(shù) ETH_link_callback。讓我們逐步分析它的功能:

1. 首先,聲明了一些變量,包括超時(shí)計(jì)數(shù)器 timeout、存儲(chǔ)從PHY讀取的寄存器值的變量 RegValue,以及用于存儲(chǔ)IP地址、子網(wǎng)掩碼和網(wǎng)關(guān)地址的變量。

2. 如果網(wǎng)絡(luò)接口的鏈接狀態(tài)為鏈接狀態(tài)(通過(guò) netif_is_link_up(netif) 判斷):

- 如果啟用了以太網(wǎng)自動(dòng)協(xié)商(ETH_InitStructure.autoNegotiation== ETH_AUTONEGOTIATION_ENABLE),則重新啟動(dòng)自動(dòng)協(xié)商過(guò)程:

- 向PHY寄存器寫(xiě)入自動(dòng)協(xié)商命令 PHY_AUTONEGOTIATION。

- 等待自動(dòng)協(xié)商完成,超時(shí)時(shí)間由 PHY_READ_TIMEOUT 定義。

- 讀取自動(dòng)協(xié)商結(jié)果,根據(jù)結(jié)果配置以太網(wǎng)MAC的速度和雙工模式。

- 根據(jù)速度和雙工模式重新配置以太網(wǎng)MAC控制器的寄存器。

- 重新啟動(dòng)MAC接口。

- 根據(jù)是否啟用了DHCP,設(shè)置IP地址、子網(wǎng)掩碼和網(wǎng)關(guān)地址,并將網(wǎng)絡(luò)接口標(biāo)記為已啟用。

- 打印消息,表示網(wǎng)絡(luò)電纜已連接。

- 將 EthLinkStatus 標(biāo)記為鏈接狀態(tài)。

3. 如果網(wǎng)絡(luò)接口的鏈接狀態(tài)為斷開(kāi)狀態(tài),執(zhí)行以下操作:

- 停止MAC接口。

- 如果啟用了DHCP,將DHCP狀態(tài)設(shè)置為鏈接斷開(kāi),并停止DHCP客戶端。

- 將網(wǎng)絡(luò)接口標(biāo)記為已關(guān)閉。

- 打印消息,表示網(wǎng)絡(luò)電纜已拔出。

綜上所述,該函數(shù)主要用于處理以太網(wǎng)鏈接狀態(tài)的變化。根據(jù)鏈接狀態(tài)的變化,重新啟動(dòng)自動(dòng)協(xié)商過(guò)程(如果啟用了自動(dòng)協(xié)商),配置以太網(wǎng)MAC的參數(shù),并設(shè)置IP地址信息。同時(shí),根據(jù)鏈接狀態(tài)的變化執(zhí)行相應(yīng)的動(dòng)作,例如重新啟動(dòng)或停止MAC接口,并更新相應(yīng)的狀態(tài)標(biāo)志。

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

}

以上函數(shù)是一個(gè)用于處理LwIP(Lightweight IP)網(wǎng)絡(luò)堆棧的周期性任務(wù)的函數(shù)。讓我們逐段分析它:

1.staticuint8_t flagToggle = 0;:定義了一個(gè)靜態(tài)變量 flagToggle,用于跟蹤網(wǎng)絡(luò)連接狀態(tài)的變化。

2. if(ETHTimer - TCPTimer >= TCP_TMR_INTERVAL):檢查T(mén)CP定時(shí)器是否超過(guò)了TCP_TMR_INTERVAL(TCP定時(shí)器間隔),如果超過(guò),則調(diào)用 tcp_tmr() 函數(shù)進(jìn)行TCP定時(shí)器處理。

3. if((ETHTimer - ARPTimer) >= ARP_TMR_INTERVAL):檢查ARP定時(shí)器是否超過(guò)了ARP_TMR_INTERVAL(ARP定時(shí)器間隔),如果超過(guò),則調(diào)用 etharp_tmr() 函數(shù)進(jìn)行ARP定時(shí)器處理。

4. if((ETHTimer - LinkTimer) >= 1000):檢查鏈接狀態(tài)是否需要更新,如果超過(guò)了一定時(shí)間(這里設(shè)置為1000ms),則進(jìn)行鏈接狀態(tài)檢查。

5. if((ETH_GET_LINK_STATUS != 0) && (flagToggle == 0)):檢查網(wǎng)絡(luò)鏈接狀態(tài)是否正常,并且之前的狀態(tài)是斷開(kāi)的,如果是,則設(shè)置網(wǎng)絡(luò)接口為鏈接狀態(tài)。

6. if((ETH_GET_LINK_STATUS == 0) && (flagToggle == 1)):檢查網(wǎng)絡(luò)鏈接狀態(tài)是否異常,并且之前的狀態(tài)是連接的,如果是,則設(shè)置網(wǎng)絡(luò)接口為斷開(kāi)狀態(tài)。

7. if(ETHTimer - DHCPfineTimer >= DHCP_FINE_TIMER_MSECS):檢查是否需要進(jìn)行DHCP的Fine定時(shí)處理,如果超過(guò)了DHCP_FINE_TIMER_MSECS(Fine定時(shí)器間隔),則調(diào)用 dhcp_fine_tmr() 函數(shù)。

8. if(ETHTimer - DHCPcoarseTimer >= DHCP_COARSE_TIMER_MSECS):檢查是否需要進(jìn)行DHCP的Coarse定時(shí)處理,如果超過(guò)了DHCP_COARSE_TIMER_MSECS(Coarse定時(shí)器間隔),則調(diào)用 dhcp_coarse_tmr() 函數(shù)。

在整個(gè)函數(shù)中,主要處理了TCP、ARP、網(wǎng)絡(luò)鏈接狀態(tài)和DHCP的周期性任務(wù)。這些任務(wù)包括定時(shí)器的處理以及相應(yīng)的動(dòng)作,例如發(fā)送ARP請(qǐng)求、更新網(wǎng)絡(luò)鏈接狀態(tài)和處理DHCP狀態(tài)機(jī)等。

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網(wǎng)絡(luò)堆棧中DHCP過(guò)程的函數(shù) LwIP_DHCP_Process_Handle。它通過(guò)狀態(tài)機(jī)來(lái)處理DHCP過(guò)程的不同階段。讓我們逐步分析其功能:

1. 在 DHCP_START 狀態(tài)下,將狀態(tài)切換到 DHCP_WAIT_ADDRESS,并啟動(dòng)DHCP客戶端。

2. 在 DHCP_WAIT_ADDRESS 狀態(tài)下,如果DHCP客戶端獲得了IP地址、子網(wǎng)掩碼和網(wǎng)關(guān)地址,將狀態(tài)切換到 DHCP_ADDRESS_ASSIGNED,打印獲得的IP地址、子網(wǎng)掩碼和網(wǎng)關(guān)地址,并停止DHCP客戶端。

3. 如果DHCP超時(shí)(嘗試次數(shù)超過(guò)4次),將狀態(tài)切換到 DHCP_TIMEOUT,停止DHCP客戶端,并使用靜態(tài)IP地址(如果配置了靜態(tài)IP地址)。

綜上所述,該函數(shù)主要用于處理LwIP網(wǎng)絡(luò)堆棧中DHCP過(guò)程的不同階段。根據(jù)DHCP狀態(tài)的不同,執(zhí)行不同的操作,例如啟動(dòng)DHCP客戶端、處理獲取到的IP地址信息、處理超時(shí)情況等。

4. 實(shí)驗(yàn)現(xiàn)象

1.串口打印相關(guān)信息

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

2.正常獲取IP后,cmd執(zhí)行ping命令,正常通信

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

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 以太網(wǎng)
    +關(guān)注

    關(guān)注

    40

    文章

    5419

    瀏覽量

    171594
  • 嵌入式系統(tǒng)
    +關(guān)注

    關(guān)注

    41

    文章

    3587

    瀏覽量

    129433
  • TCP
    TCP
    +關(guān)注

    關(guān)注

    8

    文章

    1353

    瀏覽量

    79055
  • DHCP
    +關(guān)注

    關(guān)注

    0

    文章

    104

    瀏覽量

    19702
  • LwIP
    +關(guān)注

    關(guān)注

    2

    文章

    86

    瀏覽量

    27146

原文標(biāo)題:APM32芯得 EP.46 | 增強(qiáng)以太網(wǎng)連接:使用LWIP 2.2實(shí)現(xiàn)動(dòng)態(tài)主機(jī)配置協(xié)議(DHCP)

文章出處:【微信號(hào):geehysemi,微信公眾號(hào):Geehy極海半導(dǎo)體】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    如何實(shí)現(xiàn)以太網(wǎng)功能的,是用F107或F407芯片自己移植Lwip還是采用SPI轉(zhuǎn)以太網(wǎng)模塊?

    一般大家是如何實(shí)現(xiàn)以太網(wǎng)功能的,是用F107或F407芯片自己移植Lwip還是采用SPI轉(zhuǎn)以太網(wǎng)模塊?
    發(fā)表于 05-17 06:49

    基于FPGA的萬(wàn)兆以太網(wǎng)接口的設(shè)計(jì)與實(shí)現(xiàn)

    基于FPGA的萬(wàn)兆以太網(wǎng)接口的設(shè)計(jì)與實(shí)現(xiàn)標(biāo)準(zhǔn)中萬(wàn)兆以太網(wǎng)物理層及媒質(zhì)接入控制子層的相關(guān)協(xié)議以 應(yīng)用物理環(huán)境為例,闡述了萬(wàn)兆以太網(wǎng)接口各個(gè)單元模塊的
    發(fā)表于 08-11 15:48

    NIOS實(shí)現(xiàn)以太網(wǎng)

    基于NIOS2的嵌入式實(shí)現(xiàn)以太網(wǎng)通信
    發(fā)表于 09-08 12:39

    請(qǐng)問(wèn)ATK-RM04_WIFI模塊能實(shí)現(xiàn)以太網(wǎng)轉(zhuǎn)WIFI功能嗎?

    ATK-RM04_WIFI模塊能不能實(shí)現(xiàn)以太網(wǎng)轉(zhuǎn)WIFI功能???
    發(fā)表于 11-06 01:15

    請(qǐng)問(wèn)嵌入式系統(tǒng)實(shí)現(xiàn)以太網(wǎng),TCP/IP協(xié)議棧是都是移植的嗎?

    想請(qǐng)教各位大神們。嵌入式系統(tǒng)實(shí)現(xiàn)以太網(wǎng)(比如stm32),TCP/IP協(xié)議棧是不是都是移植的。比如都移植LWIP。UIP等。而不是自己寫(xiě)啊…………感謝……
    發(fā)表于 03-13 02:22

    沒(méi)有發(fā)現(xiàn)以太網(wǎng)

    PIC32以太網(wǎng)啟動(dòng)器套件II,編號(hào):DM320004-2。我編譯并下載了TCPIP演示應(yīng)用程序,但是微芯片以太網(wǎng)發(fā)現(xiàn)器應(yīng)用程序沒(méi)有發(fā)現(xiàn)以太網(wǎng),而不管在另一臺(tái)計(jì)算機(jī)上重復(fù)這個(gè)過(guò)程。有人遇到過(guò)這個(gè)問(wèn)題并找到解決辦法嗎?謝謝
    發(fā)表于 04-10 06:43

    請(qǐng)教大神怎樣去實(shí)現(xiàn)以太網(wǎng)MAC子層協(xié)議?

    什么是以太網(wǎng)MAC子層協(xié)議?怎樣去實(shí)現(xiàn)以太網(wǎng)MAC子層協(xié)議?
    發(fā)表于 05-06 10:33

    怎么實(shí)現(xiàn)以太網(wǎng)的光無(wú)線通信系統(tǒng)的設(shè)計(jì)?

    怎么實(shí)現(xiàn)以太網(wǎng)的光無(wú)線通信系統(tǒng)的設(shè)計(jì)?
    發(fā)表于 05-28 07:08

    如何利用STM32CubeMX實(shí)現(xiàn)FreeRTOS+LAN8720A+LWIP以太網(wǎng)ping通?

    如何利用STM32CubeMX實(shí)現(xiàn)FreeRTOS+LAN8720A+LWIP以太網(wǎng)ping通?
    發(fā)表于 02-22 07:49

    單片機(jī)實(shí)現(xiàn)以太網(wǎng)通訊硬件設(shè)計(jì)

    介紹以太網(wǎng)的幀協(xié)議和以太網(wǎng)控制芯片RTL8019AS的結(jié)構(gòu)特性;介紹單片機(jī)控制RTL8019AS實(shí)現(xiàn)以太網(wǎng)通訊的硬件設(shè)計(jì)方案;采用c51語(yǔ)言實(shí)現(xiàn)RPP協(xié)議(地址解析協(xié)議),并進(jìn)行了系統(tǒng)
    發(fā)表于 08-29 16:32 ?126次下載
    單片機(jī)<b class='flag-5'>實(shí)現(xiàn)以太網(wǎng)</b>通訊硬件設(shè)計(jì)

    ST有關(guān)以太網(wǎng)講座課件

    ST公司培訓(xùn)有關(guān)以太網(wǎng)講座課件,包括tcp/ip協(xié)議、以太網(wǎng)基礎(chǔ)、Lwip、網(wǎng)卡設(shè)計(jì)與實(shí)現(xiàn)等等介紹
    發(fā)表于 03-07 11:50 ?20次下載

    以太網(wǎng)Lwip例程

    以太網(wǎng)Lwip例程
    發(fā)表于 12-06 16:53 ?26次下載
    <b class='flag-5'>以太網(wǎng)</b><b class='flag-5'>Lwip</b>例程

    AT89C52單片機(jī)實(shí)現(xiàn)以太網(wǎng)接口的控制設(shè)計(jì)

    隨著互聯(lián)網(wǎng)的迅速發(fā)展,網(wǎng)絡(luò)用戶飛速增長(zhǎng),在使用計(jì)算機(jī)進(jìn)行網(wǎng)絡(luò)互聯(lián)的同時(shí),各種家電設(shè)備、儀表設(shè)備及工業(yè)中數(shù)據(jù)采集與控制設(shè)備也在逐步走向網(wǎng)絡(luò)化,基于此結(jié)合專(zhuān)用的以太網(wǎng)控制芯片RTL8019學(xué)習(xí)了利用單片機(jī)實(shí)現(xiàn)以太網(wǎng)接口的設(shè)計(jì)。
    發(fā)表于 03-03 11:17 ?2817次閱讀
    AT89C52單片機(jī)<b class='flag-5'>實(shí)現(xiàn)以太網(wǎng)</b>接口的控制設(shè)計(jì)

    PLC如何實(shí)現(xiàn)以太網(wǎng)口無(wú)線通訊

    PLC若想實(shí)現(xiàn)以太網(wǎng)口無(wú)線通訊,首先我們需要確定好PLC型號(hào),然后選擇一個(gè)合適的通訊設(shè)備。比如如果是西門(mén)子S7-200PLC,就需要使用歐美PLC無(wú)線通訊終端,并且這個(gè)設(shè)備需要支持以太網(wǎng)口通訊。
    發(fā)表于 03-08 09:17 ?5062次閱讀

    Android 9以太網(wǎng)功能移植以及設(shè)置IP地址

    基于Android 9實(shí)現(xiàn)以太網(wǎng)的IP地址設(shè)置和功能實(shí)現(xiàn)
    發(fā)表于 06-20 14:42 ?2次下載
    RM新时代网站-首页