STM32F4Ucosii环境LWIP移植

移植平台使用STM32F407为核心芯片的正点原子开发平台,网络芯片使用LAN8720。LWIP使用官方1.4.1版本。本文章只说移植,详细说明请参考正点原子《STM32F4 LWIP开发手册》
1、修改lwipopt.h文件
添加系统优先级代码

//线程优先级 #ifndef TCPIP_THREAD_PRIO #define TCPIP_THREAD_PRIO5 //定义内核任务的优先级为5 #endif #undefDEFAULT_THREAD_PRIO #define DEFAULT_THREAD_PRIO2

//选择操作系统
#define NO_SYS 0
//对lwip关键代码做保护
#define SYS_LIGHTWEIGHT_PROT 1
//选择使用NETCON和Socket编程方式
#define LWIP_SOCKET 1
#define LWIP_NETCONN 1
在tcp选项下添加如下代码
#undef TCP_QUEUE_OOSEQ #define TCP_QUEUE_OOSEQ0//当TCP的数据段超出队列时的控制位,当设备的内存过小的时候此项应为0 #undef TCPIP_MBOX_SIZE #define TCPIP_MBOX_SIZEMAX_QUEUE_ENTRIES//tcpip创建主线程时的消息邮箱大小#undef DEFAULT_TCP_RECVMBOX_SIZE #define DEFAULT_TCP_RECVMBOX_SIZEMAX_QUEUE_ENTRIES#undef DEFAULT_ACCEPTMBOX_SIZE #define DEFAULT_ACCEPTMBOX_SIZEMAX_QUEUE_ENTRIES

添加有关系统代码
//有关系统的选项 #define TCPIP_THREAD_STACKSIZE1000 //内核任务堆栈大小 #define DEFAULT_UDP_RECVMBOX_SIZE2000 #define DEFAULT_THREAD_STACKSIZE512

2、修改cc.h文件
添加"ucos_ii.h"头文件
添加如下代码
//使用操作系统时的临界区保护,这里以UCOS II为例 //当定义了OS_CRITICAL_METHOD时就说明使用了UCOS II #if OS_CRITICAL_METHOD == 1 #define SYS_ARCH_DECL_PROTECT(lev) #define SYS_ARCH_PROTECT(lev)CPU_INT_DIS() #define SYS_ARCH_UNPROTECT(lev)CPU_INT_EN() #endif#if OS_CRITICAL_METHOD == 3 #define SYS_ARCH_DECL_PROTECT(lev) u32_t lev #define SYS_ARCH_PROTECT(lev)lev = OS_CPU_SR_Save()//UCOS II中进入临界区,关中断 #define SYS_ARCH_UNPROTECT(lev)OS_CPU_SR_Restore(lev) //UCOS II中退出A临界区,开中断 #endif

3、修改sys_arch.c和sys_arch.h文件
sys_arch.c文件中定义了lwip用到的信号量、邮箱等操作函数,因此非常重要,函数功能来自sys_arch.txt文档
sys_arch.c相关代码如下
/* #define SYS_ARCH_GLOBALS/* lwIP includes. */ #include "lwip/debug.h" #include "lwip/def.h" #include "lwip/lwip_sys.h" #include "lwip/mem.h" #include "includes.h" #include "delay.h" #include "arch/sys_arch.h" #include "malloc.h"//当消息指针为空时,指向一个常量pvNullPointer所指向的值. //在UCOS中如果OSQPost()中的msg==NULL会返回一条OS_ERR_POST_NULL //错误,而在lwip中会调用sys_mbox_post(mbox,NULL)发送一条空消息,我们 //在本函数中把NULL变成一个常量指针0Xffffffff const void * const pvNullPointer = (mem_ptr_t*)0xffffffff; //创建一个消息邮箱 //*mbox:消息邮箱 //size:邮箱大小 //返回值:ERR_OK,创建成功 //其他,创建失败 err_t sys_mbox_new( sys_mbox_t *mbox, int size) { (*mbox)=mymalloc(SRAMIN,sizeof(TQ_DESCR)); //为消息邮箱申请内存 mymemset((*mbox),0,sizeof(TQ_DESCR)); //清除mbox的内存 if(*mbox)//内存分配成功 { if(size>MAX_QUEUE_ENTRIES)size=MAX_QUEUE_ENTRIES; //消息队列最多容纳MAX_QUEUE_ENTRIES消息数目 (*mbox)->pQ=OSQCreate(&((*mbox)->pvQEntries[0]),size); //使用UCOS创建一个消息队列 LWIP_ASSERT("OSQCreate",(*mbox)->pQ!=NULL); if((*mbox)->pQ!=NULL)return ERR_OK; //返回ERR_OK,表示消息队列创建成功 ERR_OK=0 else { myfree(SRAMIN,(*mbox)); return ERR_MEM; //消息队列创建错误 } }else return ERR_MEM; //消息队列创建错误 } //释放并删除一个消息邮箱 //*mbox:要删除的消息邮箱 void sys_mbox_free(sys_mbox_t * mbox) { u8_t ucErr; sys_mbox_t m_box=*mbox; (void)OSQDel(m_box->pQ,OS_DEL_ALWAYS,&ucErr); LWIP_ASSERT( "OSQDel ",ucErr == OS_ERR_NONE ); myfree(SRAMIN,m_box); *mbox=NULL; }//向消息邮箱中发送一条消息(必须发送成功) //*mbox:消息邮箱 //*msg:要发送的消息 void sys_mbox_post(sys_mbox_t *mbox,void *msg) { if(msg==NULL)msg=(void*)&pvNullPointer; //当msg为空时 msg等于pvNullPointer指向的值 while(OSQPost((*mbox)->pQ,msg)!=OS_ERR_NONE); //死循环等待消息发送成功 }//尝试向一个消息邮箱发送消息 //此函数相对于sys_mbox_post函数只发送一次消息, //发送失败后不会尝试第二次发送 //*mbox:消息邮箱 //*msg:要发送的消息 //返回值:ERR_OK,发送OK //ERR_MEM,发送失败 err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg) { if(msg==NULL)msg=(void*)&pvNullPointer; //当msg为空时 msg等于pvNullPointer指向的值 if((OSQPost((*mbox)->pQ, msg))!=OS_ERR_NONE)return ERR_MEM; return ERR_OK; }//等待邮箱中的消息 //*mbox:消息邮箱 //*msg:消息 //timeout:超时时间,如果timeout为0的话,就一直等待 //返回值:当timeout不为0时如果成功的话就返回等待的时间, //失败的话就返回超时SYS_ARCH_TIMEOUT u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout) { u8_t ucErr; u32_t ucos_timeout,timeout_new; void *temp; sys_mbox_t m_box=*mbox; if(timeout!=0) { ucos_timeout=(timeout*OS_TICKS_PER_SEC)/1000; //转换为节拍数,因为UCOS延时使用的是节拍数,而LWIP是用ms if(ucos_timeout<1)ucos_timeout=1; //至少1个节拍 }else ucos_timeout = 0; timeout = OSTimeGet(); //获取系统时间 temp=OSQPend(m_box->pQ,(u16_t)ucos_timeout,&ucErr); //请求消息队列,等待时限为ucos_timeout if(msg!=NULL) { if(temp==(void*)&pvNullPointer)*msg = NULL; //因为lwip发送空消息的时候我们使用了pvNullPointer指针,所以判断pvNullPointer指向的值 else *msg=temp; //就可知道请求到的消息是否有效 } if(ucErr==OS_ERR_TIMEOUT)timeout=SYS_ARCH_TIMEOUT; //请求超时 else { LWIP_ASSERT("OSQPend ",ucErr==OS_ERR_NONE); timeout_new=OSTimeGet(); if (timeout_new>timeout) timeout_new = timeout_new - timeout; //算出请求消息或使用的时间 else timeout_new = 0xffffffff - timeout + timeout_new; timeout=timeout_new*1000/OS_TICKS_PER_SEC + 1; } return timeout; }//尝试获取消息 //*mbox:消息邮箱 //*msg:消息 //返回值:等待消息所用的时间/SYS_ARCH_TIMEOUT u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) { return sys_arch_mbox_fetch(mbox,msg,1); //尝试获取一个消息 }//检查一个消息邮箱是否有效 //*mbox:消息邮箱 //返回值:1,有效. //0,无效 int sys_mbox_valid(sys_mbox_t *mbox) { sys_mbox_t m_box=*mbox; u8_t ucErr; int ret; OS_Q_DATA q_data; memset(&q_data,0,sizeof(OS_Q_DATA)); ucErr=OSQQuery (m_box->pQ,&q_data); ret=(ucErr<2&&(q_data.OSNMsgs=timeout) timeout_new = timeout_new - timeout; else timeout_new = 0xffffffff - timeout + timeout_new; timeout = (timeout_new*1000/OS_TICKS_PER_SEC + 1); //算出请求消息或使用的时间(ms) } return timeout; }//发送一个信号量 //sem:信号量指针 void sys_sem_signal(sys_sem_t *sem) { OSSemPost(*sem); } //释放并删除一个信号量 //sem:信号量指针 void sys_sem_free(sys_sem_t *sem) { u8_t ucErr; (void)OSSemDel(*sem,OS_DEL_ALWAYS,&ucErr ); if(ucErr!=OS_ERR_NONE)LWIP_ASSERT("OSSemDel ",ucErr==OS_ERR_NONE); *sem = NULL; } //查询一个信号量的状态,无效或有效 //sem:信号量指针 //返回值:1,有效. //0,无效 int sys_sem_valid(sys_sem_t *sem) { OS_SEM_DATAsem_data; return (OSSemQuery (*sem,&sem_data) == OS_ERR_NONE )? 1:0; } //设置一个信号量无效 //sem:信号量指针 void sys_sem_set_invalid(sys_sem_t *sem) { *sem=NULL; }

同时创建lwip进程和sys_msleep()、sys_now()两个函数
//arch初始化 void sys_init(void) { //这里,我们在该函数,不做任何事情 } extern OS_STK * TCPIP_THREAD_TASK_STK; //TCP IP内核任务堆栈,在lwip_comm函数定义 //创建一个新进程 //*name:进程名称 //thred:进程任务函数 //*arg:进程任务函数的参数 //stacksize:进程任务的堆栈大小 //prio:进程任务的优先级 sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio) { OS_CPU_SR cpu_sr; if(strcmp(name,TCPIP_THREAD_NAME)==0)//创建TCP IP内核任务 { OS_ENTER_CRITICAL(); //进入临界区 OSTaskCreate(thread,arg,(OS_STK*)&TCPIP_THREAD_TASK_STK[stacksize-1],prio); //创建TCP IP内核任务 OS_EXIT_CRITICAL(); //退出临界区 } return 0; } //lwip延时函数 //ms:要延时的ms数 void sys_msleep(u32_t ms) { delay_ms(ms); } //获取系统时间,LWIP1.4.1增加的函数 //返回值:当前系统时间(单位:毫秒) u32_t sys_now(void) { u32_t ucos_time, lwip_time; ucos_time=OSTimeGet(); //获取当前系统时间 得到的是UCSO的节拍数 lwip_time=(ucos_time*1000/OS_TICKS_PER_SEC+1); //将节拍数转换为LWIP的时间MS return lwip_time; //返回lwip_time; }

sys_now()函数与无操作系统时的不同,不在使用lwip_localtime全局变量来记录时钟,移植时需注意
sys_arch.h文件如下
#ifndef __ARCH_SYS_ARCH_H__ #define __ARCH_SYS_ARCH_H__ #include #include "arch/cc.h" #include "includes.h" #ifdef SYS_ARCH_GLOBALS #define SYS_ARCH_EXT #else #define SYS_ARCH_EXT extern #endif #define MAX_QUEUES10 // 消息邮箱的数量 #define MAX_QUEUE_ENTRIES20 // 每个消息邮箱的大小 //LWIP消息邮箱结构体 typedef struct { OS_EVENT*pQ; //UCOS中指向事件控制块的指针 void*pvQEntries[MAX_QUEUE_ENTRIES]; //消息队列 MAX_QUEUE_ENTRIES消息队列中最多消息数 } TQ_DESCR, *PQ_DESCR; typedef OS_EVENT *sys_sem_t; //LWIP使用的信号量 typedef OS_EVENT *sys_mutex_t; //LWIP使用的互斥信号量 typedef PQ_DESCR sys_mbox_t; //LWIP使用的消息邮箱,其实就是UCOS中的消息队列 typedef INT8U sys_thread_t; //线程ID,也就是任务优先级 #endif

【STM32F4Ucosii环境LWIP移植】3、修改lwip_comm.c文件
比较无操作系统的comm文件,lwip_comm_init()函数改动不大,DHCP相关改动较打。因为我使用静态IP较多,因此对DHCP没有太多关注。代码如下
#include "lwip_comm.h" #include "netif/etharp.h" #include "lwip/dhcp.h" #include "ethernetif.h" #include "lwip/timers.h" #include "lwip/tcp_impl.h" #include "lwip/ip_frag.h" #include "lwip/tcpip.h" #include "malloc.h" #include "delay.h" #include "usart.h" #include #include "ucos_ii.h"__lwip_dev lwipdev; //lwip控制结构体 struct netif lwip_netif; //定义一个全局的网络接口extern u32 memp_get_memorysize(void); //在memp.c里面定义 extern u8_t *memp_memory; //在memp.c里面定义. extern u8_t *ram_heap; //在mem.c里面定义.//lwip两个任务定义(内核任务和DHCP任务)//lwip内核任务堆栈(优先级和堆栈大小在lwipopts.h定义了) OS_STK * TCPIP_THREAD_TASK_STK; //lwip DHCP任务 //设置任务优先级 #define LWIP_DHCP_TASK_PRIO7 //设置任务堆栈大小 #define LWIP_DHCP_STK_SIZE128 //任务堆栈,采用内存管理的方式控制申请 OS_STK * LWIP_DHCP_TASK_STK; //任务函数 void lwip_dhcp_task(void *pdata); //用于以太网中断调用 void lwip_pkt_handle(void) { ethernetif_input(&lwip_netif); } //lwip内核部分,内存申请 //返回值:0,成功; //其他,失败 u8 lwip_comm_mem_malloc(void) { u32 mempsize; u32 ramheapsize; mempsize=memp_get_memorysize(); //得到memp_memory数组大小 memp_memory=mymalloc(SRAMIN,mempsize); //为memp_memory申请内存 ramheapsize=LWIP_MEM_ALIGN_SIZE(MEM_SIZE)+2*LWIP_MEM_ALIGN_SIZE(4*3)+MEM_ALIGNMENT; //得到ram heap大小 ram_heap=mymalloc(SRAMIN,ramheapsize); //为ram_heap申请内存 TCPIP_THREAD_TASK_STK=mymalloc(SRAMIN,TCPIP_THREAD_STACKSIZE*4); //给内核任务申请堆栈 LWIP_DHCP_TASK_STK=mymalloc(SRAMIN,LWIP_DHCP_STK_SIZE*4); //给dhcp任务堆栈申请内存空间 if(!memp_memory||!ram_heap||!TCPIP_THREAD_TASK_STK||!LWIP_DHCP_TASK_STK)//有申请失败的 { lwip_comm_mem_free(); return 1; } return 0; } //lwip内核部分,内存释放 void lwip_comm_mem_free(void) { myfree(SRAMIN,memp_memory); myfree(SRAMIN,ram_heap); myfree(SRAMIN,TCPIP_THREAD_TASK_STK); myfree(SRAMIN,LWIP_DHCP_TASK_STK); } //lwip 默认IP设置 //lwipx:lwip控制结构体指针 void lwip_comm_default_ip_set(__lwip_dev *lwipx) { u32 sn0; sn0=*(vu32*)(0x1FFF7A10); //获取STM32的唯一ID的前24位作为MAC地址后三字节 //默认远端IP为:192.168.1.100 lwipx->remoteip[0]=10; lwipx->remoteip[1]=10; lwipx->remoteip[2]=1; lwipx->remoteip[3]=118; //MAC地址设置(高三字节固定为:2.0.0,低三字节用STM32唯一ID) lwipx->mac[0]=2; //高三字节(IEEE称之为组织唯一ID,OUI)地址固定为:2.0.0 lwipx->mac[1]=0; lwipx->mac[2]=0; lwipx->mac[3]=(sn0>>16)&0XFF; //低三字节用STM32的唯一ID lwipx->mac[4]=(sn0>>8)&0XFFF; ; lwipx->mac[5]=sn0&0XFF; //默认本地IP为:192.168.1.30 lwipx->ip[0]=10; lwipx->ip[1]=10; lwipx->ip[2]=1; lwipx->ip[3]=101; //默认子网掩码:255.255.255.0 lwipx->netmask[0]=255; lwipx->netmask[1]=255; lwipx->netmask[2]=255; lwipx->netmask[3]=0; //默认网关:192.168.1.1 lwipx->gateway[0]=10; lwipx->gateway[1]=10; lwipx->gateway[2]=1; lwipx->gateway[3]=2; lwipx->dhcpstatus=0; //没有DHCP } //LWIP初始化(LWIP启动的时候使用) //返回值:0,成功 //1,内存错误 //2,LAN8720初始化失败 //3,网卡添加失败. u8 lwip_comm_init(void) { OS_CPU_SR cpu_sr; struct netif *Netif_Init_Flag; //调用netif_add()函数时的返回值,用于判断网络初始化是否成功 struct ip_addr ipaddr; //ip地址 struct ip_addr netmask; //子网掩码 struct ip_addr gw; //默认网关 if(ETH_Mem_Malloc())return 1; //内存申请失败 if(lwip_comm_mem_malloc())return 1; //内存申请失败 if(LAN8720_Init())return 2; //初始化LAN8720失败 tcpip_init(NULL,NULL); //初始化tcp ip内核,该函数里面会创建tcpip_thread内核任务 lwip_comm_default_ip_set(&lwipdev); //设置默认IP等信息 #if LWIP_DHCP//使用动态IP ipaddr.addr = 0; netmask.addr = 0; gw.addr = 0; #else//使用静态IP IP4_ADDR(&ipaddr,lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]); IP4_ADDR(&netmask,lwipdev.netmask[0],lwipdev.netmask[1] ,lwipdev.netmask[2],lwipdev.netmask[3]); IP4_ADDR(&gw,lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]); printf("网卡en的MAC地址为:................%d.%d.%d.%d.%d.%d\r\n",lwipdev.mac[0],lwipdev.mac[1],lwipdev.mac[2],lwipdev.mac[3],lwipdev.mac[4],lwipdev.mac[5]); printf("静态IP地址........................%d.%d.%d.%d\r\n",lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]); printf("子网掩码..........................%d.%d.%d.%d\r\n",lwipdev.netmask[0],lwipdev.netmask[1],lwipdev.netmask[2],lwipdev.netmask[3]); printf("默认网关..........................%d.%d.%d.%d\r\n",lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]); #endif OS_ENTER_CRITICAL(); //进入临界区 Netif_Init_Flag=netif_add(&lwip_netif,&ipaddr,&netmask,&gw,NULL,ðernetif_init,&tcpip_input); //向网卡列表中添加一个网口 OS_EXIT_CRITICAL(); //退出临界区 if(Netif_Init_Flag==NULL)return 3; //网卡添加失败 else//网口添加成功后,设置netif为默认值,并且打开netif网口 { netif_set_default(&lwip_netif); //设置netif为默认网口 netif_set_up(&lwip_netif); //打开netif网口 } return 0; //操作OK. } //如果使能了DHCP #if LWIP_DHCP //创建DHCP任务 void lwip_comm_dhcp_creat(void) { OS_CPU_SR cpu_sr; OS_ENTER_CRITICAL(); //进入临界区 OSTaskCreate(lwip_dhcp_task,(void*)0,(OS_STK*)&LWIP_DHCP_TASK_STK[LWIP_DHCP_STK_SIZE-1],LWIP_DHCP_TASK_PRIO); //创建DHCP任务 OS_EXIT_CRITICAL(); //退出临界区 } //删除DHCP任务 void lwip_comm_dhcp_delete(void) { dhcp_stop(&lwip_netif); //关闭DHCP OSTaskDel(LWIP_DHCP_TASK_PRIO); //删除DHCP任务 } //DHCP处理任务 void lwip_dhcp_task(void *pdata) { u32 ip=0,netmask=0,gw=0; dhcp_start(&lwip_netif); //开启DHCP lwipdev.dhcpstatus=0; //正在DHCP printf("正在查找DHCP服务器,请稍等...........\r\n"); while(1) { printf("正在获取地址...\r\n"); ip=lwip_netif.ip_addr.addr; //读取新IP地址 netmask=lwip_netif.netmask.addr; //读取子网掩码 gw=lwip_netif.gw.addr; //读取默认网关 if(ip!=0)//当正确读取到IP地址的时候 { lwipdev.dhcpstatus=2; //DHCP成功 printf("网卡en的MAC地址为:................%d.%d.%d.%d.%d.%d\r\n",lwipdev.mac[0],lwipdev.mac[1],lwipdev.mac[2],lwipdev.mac[3],lwipdev.mac[4],lwipdev.mac[5]); //解析出通过DHCP获取到的IP地址 lwipdev.ip[3]=(uint8_t)(ip>>24); lwipdev.ip[2]=(uint8_t)(ip>>16); lwipdev.ip[1]=(uint8_t)(ip>>8); lwipdev.ip[0]=(uint8_t)(ip); printf("通过DHCP获取到IP地址..............%d.%d.%d.%d\r\n",lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]); //解析通过DHCP获取到的子网掩码地址 lwipdev.netmask[3]=(uint8_t)(netmask>>24); lwipdev.netmask[2]=(uint8_t)(netmask>>16); lwipdev.netmask[1]=(uint8_t)(netmask>>8); lwipdev.netmask[0]=(uint8_t)(netmask); printf("通过DHCP获取到子网掩码............%d.%d.%d.%d\r\n",lwipdev.netmask[0],lwipdev.netmask[1],lwipdev.netmask[2],lwipdev.netmask[3]); //解析出通过DHCP获取到的默认网关 lwipdev.gateway[3]=(uint8_t)(gw>>24); lwipdev.gateway[2]=(uint8_t)(gw>>16); lwipdev.gateway[1]=(uint8_t)(gw>>8); lwipdev.gateway[0]=(uint8_t)(gw); printf("通过DHCP获取到的默认网关..........%d.%d.%d.%d\r\n",lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]); break; }else if(lwip_netif.dhcp->tries>LWIP_MAX_DHCP_TRIES) //通过DHCP服务获取IP地址失败,且超过最大尝试次数 { lwipdev.dhcpstatus=0XFF; //DHCP失败. //使用静态IP地址 IP4_ADDR(&(lwip_netif.ip_addr),lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]); IP4_ADDR(&(lwip_netif.netmask),lwipdev.netmask[0],lwipdev.netmask[1],lwipdev.netmask[2],lwipdev.netmask[3]); IP4_ADDR(&(lwip_netif.gw),lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]); printf("DHCP服务超时,使用静态IP地址!\r\n"); printf("网卡en的MAC地址为:................%d.%d.%d.%d.%d.%d\r\n",lwipdev.mac[0],lwipdev.mac[1],lwipdev.mac[2],lwipdev.mac[3],lwipdev.mac[4],lwipdev.mac[5]); printf("静态IP地址........................%d.%d.%d.%d\r\n",lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]); printf("子网掩码..........................%d.%d.%d.%d\r\n",lwipdev.netmask[0],lwipdev.netmask[1],lwipdev.netmask[2],lwipdev.netmask[3]); printf("默认网关..........................%d.%d.%d.%d\r\n",lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]); break; } delay_ms(250); //延时250ms } lwip_comm_dhcp_delete(); //删除DHCP任务 } #endif

文中有些地方用到的includes.h是在ucos移植过程中用到的,主要用到了其中的ucos_ii.h

    推荐阅读