STM32之LWIP网络协议栈移植步骤与方案

2024-04-30  

1.LWIP介绍

lwip是瑞典计算机科学院网络嵌入式系统小组(SICS)的Adam Dunkels(亚当·邓克尔) 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持 TCP 协议主要功能的基础上减少对RAM的占用。
LwIP是Light Weight(轻型)IP 协议,有无操作系统的支持都可以运行。LwIP 实现的重点是在保持TCP协议 主要功能的基础上减少对RAM的占用,它只需十几KB的RAM和 40K左右的ROM就可以运行,这使LwIP协议栈适合在低端的嵌入式系统中使用。lwip提供三种API:

  • RAW API

  • (NETCONN)lwip API

  • BSD API

2.LWIP源码下载

源码下载地址:LWIP源码

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASVRf6Zi_5rC0,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center

3 LWIP源码移植

  这里以1.4.1为例。
 1.解压文件

poYBAGKWtFqAIMcPAABt5gNzwUI607.png#pic_center

2.打开已完成DM9000驱动的工程,在工程中创建lwip文件夹,在lwip文件夹中创建src文件夹和lwip1.4_config文件夹:

在这里插入图片描述

 3.将lwip-1.4.1源码中的src中所有文件复制到用户创建的src中:

在这里插入图片描述

4.复制contrib中文件

在这里插入图片描述pYYBAGKWsfaAAE0UAADwUORUrHs992.png

5.删除不必要文件

pYYBAGKWslaAHj_1AAGki7Paihs964.pngpoYBAGKWsmeAftq_AAFmzEhEIOM076.png

 6.打开工程,添加.c文件到工程中

pYYBAGKWsoaALzP2AAEk789YQFw702.pngpYYBAGKWsqKAE4plAAUI-Dg7LFY417.pngpoYBAGKWsrSAMKOhAAHbTpSzIEw265.png

7.添加.h文件路径

pYYBAGKWstuAOcRBAAH4aJdhJSc766.png

8.编译工程

poYBAGKWsvWAIrjlAAMQBLj2Co8795.png

9.修改sys_arch.c文件,只保留下面函数,其它全部删除。

pYYBAGKWsxmAP2UoAAFZIKW02nI396.png

10.修改lwipopts.h文件

poYBAGKWszmADeohAAHnlTW5XdQ273.png

11.修改ethernetif.c文件

poYBAGKWs1CAXw-KAAGb9naRI40456.pngpoYBAGKWs2mAX3f2AANJCTEk7UE965.pngpoYBAGKWs4WAb0MHAAOBUpvC74Q434.png

4.LWIP协议栈使用示例之 — 获取动态IP

  在LWIP_confg目录下创建lwip_config.c和lwip_config.h文件

  lwip_config.c文件:


#include "lwip_config.h"

#include "lwip/ip_addr.h"

#include "lwip/init.h"

#include "lwip/netif.h"

#include "netif/etharp.h"

#include "lwip/dhcp.h"

#include "lwip/tcp_impl.h"

extern err_t ethernetif_init(struct netif *netif);//网卡初始化函数,原型在ethernetif.c中

extern void  ethernetif_input(struct netif *netif);

/**************LWIP协议栈初始化***********/

struct netif lwip_netif; //结构体原型在lwip/netif.h中

void LWIP_Config_Init(void)

{

ip_addr_t ip_addr={0};//IP地址

ip_addr_t netmask={0};//子网掩码

ip_addr_t gw={0};//网关

/*静态分配IP*/

// IP4_ADDR(&ip_addr,192,168,12,23);//设置静态IP

// IP4_ADDR(&netmask,255,255,255,0);//子网掩码

// IP4_ADDR(&netmask,192,168,12,1);//网关

/*1.LWIP协议栈初始化*/

lwip_init();

/*2.添加新的网卡设备到LWIP协议栈中*/

/*err_t ethernet_input(struct pbuf *p, struct netif *netif)处理已经读取从硬件接口发来的一个数据包*/

netif_add(&lwip_netif,&ip_addr,&netmask,&gw,NULL,ethernetif_init,ethernet_input);

/*3.设置网卡为LWIP协议栈默认设备*/

netif_set_default(&lwip_netif);

/*4.注册网卡设备为默认接口*/

netif_set_up(&lwip_netif);

/*5.动态分配IP*/

dhcp_start(&lwip_netif);

}

/*****DHCP定期数据处理函数(轮询方式实现数据更新)****/


u32 LWIP_TCP_TIME_CNT=0;

u32 LWIP_ARP_TIME_CNT=0;

u32 LWIP_DHCP_TIME_CNT=0;

u32 LWIP_UPDATE_DHCP_TIME_CNT=0;

u8 lwip_dhcp_stat=0;

void LWIP_DataUpdata(void)

{

/*250MS 更新一次*/

if(LWIP_TCP_TIME_CNT>=TCP_TMR_INTERVAL)

{

LWIP_TCP_TIME_CNT=0;

tcp_tmr(); //对 TCP 数据进行解析

}

/*5000ms 更新一次*/

if(LWIP_ARP_TIME_CNT>=ARP_TMR_INTERVAL)

{

LWIP_ARP_TIME_CNT=0;

etharp_tmr();//清理 ARP 缓存表

}

//500ms获取一次

if(LWIP_DHCP_TIME_CNT>=DHCP_FINE_TIMER_MSECS )

{

LWIP_DHCP_TIME_CNT=0;

dhcp_fine_tmr(); //解析 DHCP 请求,判断 IP 地址是否获取成功

}

/*60S 更新一次*/

if(LWIP_UPDATE_DHCP_TIME_CNT>=DHCP_COARSE_TIMER_MSECS)

{

LWIP_UPDATE_DHCP_TIME_CNT=0;

dhcp_coarse_tmr(); //更新检查 DHCP 的租约时间

}

ethernetif_input(&lwip_netif); //读取网卡的数据进行上报

if(lwip_dhcp_stat==0)

{

LWIP_GetDHCP_Addr();

}

}

/******获取动态分配的IP地址*************/

void LWIP_GetDHCP_Addr(void)

{

char buff[200];

u32 ip_addr;//IP地址

u32 netmask;//子网掩码

u32 gw;//网关

ip_addr=lwip_netif.ip_addr.addr;//IP地址

netmask=lwip_netif.netmask.addr;//子网掩码

gw=lwip_netif.gw.addr;

if(ip_addr!=0)

{

lwip_dhcp_stat=1;//成功获取到IP地址

printf("IP地址:%d.%d.%d.%drn",(ip_addr>>0)&0xff,(ip_addr>>8)&0xff,(ip_addr>>16)&0xff,(ip_addr>>24)&0xff);

snprintf(buff,sizeof(buff),"IP地址:%d.%d.%d.%d",(ip_addr>>0)&0xff,(ip_addr>>8)&0xff,(ip_addr>>16)&0xff,(ip_addr>>24)&0xff);

LCD_ShowStr(30,30+20*4,16,(u8 *)buff);//IP地址

printf("子网掩码:%d.%d.%d.%drn",(netmask>>0)&0xff,(netmask>>8)&0xff,(netmask>>16)&0xff,(netmask>>24)&0xff);

snprintf(buff,sizeof(buff),"子网掩码:%d.%d.%d.%drn",(netmask>>0)&0xff,(netmask>>8)&0xff,(netmask>>16)&0xff,(netmask>>24)&0xff);

LCD_ShowStr(30,30+20*5,16,(u8 *)buff);//子网掩码

printf("网关:%d.%d.%d.%drn",(gw>>0)&0xff,(gw>>8)&0xff,(gw>>16)&0xff,(gw>>24)&0xff);

snprintf(buff,sizeof(buff),"网关:%d.%d.%d.%drn",(gw>>0)&0xff,(gw>>8)&0xff,(gw>>16)&0xff,(gw>>24)&0xff);

LCD_ShowStr(30,30+20*6,16,(u8 *)buff);//子网掩码

}

}

5.主函数

复制

#include "dm9000.h"

#include "lwip_config.h"

u8 dm9000_tx_buff[64]={0x11,0x22,0x33,0x44,0x55};

u8 dm9000_rx_buff[1024];

int main()

{

char buff[200];

u8 stat;

Beep_Init();

Led_Init();

Key_Init();

W25Q64_Init();

Usartx_Init(USART1,115200,72);

TIMx_Init(TIM2,72,20*1000);

IIC_Init();

printf("初始化完成rn");

NT35310_Init();

/*DM9000初始化*/

LCD_ShowStr(30,30,16,"DM9000初始化中。。。");//显示字符串

if(DM9000_Init()==0)

{

printf("DM9000初始化成功rn");

LCD_ShowStr(30,30+20,16,"DM9000t OK!");//显示字符串

}

else 

{

printf("DM9000初始化失败rn");

LCD_ShowStr(30,30+20,16,"DM9000t ERR!");//显示字符串

}

/*获取DM9000工作模式*/

LCD_ShowStr(128,30+20*2,16,"网卡信息");//显示字符串

stat=DM9000_Get_SpeedAndDuplex();//获取连接状态和工作方式

if(stat!=0xff)

{

printf("网卡速度:%d Mbps 模式:%srn",(stat&0x02)?10:100,(stat&0x01)?"全双工":"半双工");

snprintf(buff,sizeof(buff),"网卡速度:%d MHZt %s",(stat&0x02)?10:100,(stat&0x01)?"全双工":"半双工");

LCD_ShowStr(30,30+20*3,16,(u8 *)buff);//网卡速度

}

else 

{

printf("DM9000网卡状态信息获取失败!rn");

LCD_ShowStr(30,30+20*3,16,(u8 *)"获取网卡信息失败!");//网卡速度

}

LWIP_Config_Init();//LWIP协议栈初始化

TIMx_Init(TIM6,72,1000);

TIM6->CR1|=1<<0;

while(1)

{

LWIP_DataUpdata();

}

}

6.运行效果

pYYBAGKWs92AEhr7AAESZQ-rIDQ758.pngpYYBAGKWs_KACnf5AAV1_eHv-eM124.png

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。