##初始化配置步骤 ##
第一:硬件底层DMA缓存以及以太网内存初始化
if(ETH_Mem_Malloc())return 1; //内存申请失败
if(lwip_comm_mem_malloc())return 1; //内存申请失败
u8 ETH_Mem_Malloc(void)
{
DMARxDscrTab=mymalloc(SRAMIN,ETH_RXBUFNB*sizeof(ETH_DMADESCTypeDef));//申请内存
DMATxDscrTab=mymalloc(SRAMIN,ETH_TXBUFNB*sizeof(ETH_DMADESCTypeDef));//申请内存
Rx_Buff=mymalloc(SRAMIN,ETH_RX_BUF_SIZE*ETH_RXBUFNB); //申请内存
Tx_Buff=mymalloc(SRAMIN,ETH_TX_BUF_SIZE*ETH_TXBUFNB); //申请内存
if(!DMARxDscrTab||!DMATxDscrTab||!Rx_Buff||!Tx_Buff)
{
ETH_Mem_Free();
return 1; //申请失败
}
return 0; //申请成功
}
//lwip中mem和memp的内存申请
//返回值: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申请内存
if(!memp_memory||!ram_heap)//有申请失败的
{
lwip_comm_mem_free();
return 1;
}
return 0;
}
第二步:网卡硬件初始化
LAN8720_Init()
第三步:以太网初始化
lwip_init();
第四步:设置IP地址
//静态:
IP4_ADDR(&ipaddr,192.168.1.100);
IP4_ADDR(&netmask,192.168.1.1);
IP4_ADDR(&gw,255.255.255.0);
//动态暂时为0,待会自动获取:
IP4_ADDR(&ipaddr,0.0.0.0);
IP4_ADDR(&netmask,0.0.0.0);
IP4_ADDR(&gw,0.0.0.0);
第五步:添加网卡
Netif_Init_Flag=netif_add(&lwip_netif,&ipaddr,&netmask,&gw,NULL,ðernetif_init,ðernet_input);
第六步:如果为动态IP则开启动态IP服务
lwipdev.dhcpstatus=0; //DHCP标记为0
dhcp_start(&lwip_netif); //开启DHCP服务
第七步:设置默认网口,并打开
netif_set_default(&lwip_netif); //设置netif为默认网口
netif_set_up(&lwip_netif); //打开netif网口
第八步:等待动态获取IP,如果获取失败,则使用静态IP
while((lwipdev.dhcpstatus!=2)&&(lwipdev.dhcpstatus!=0XFF))//等待DHCP获取成功/超时溢出
{
lwip_periodic_handle();
}
//LWIP轮询任务
void lwip_periodic_handle()
{
#if LWIP_TCP
//每250ms调用一次tcp_tmr()函数
if (lwip_localtime - TCPTimer >= TCP_TMR_INTERVAL)
{
TCPTimer = lwip_localtime;
tcp_tmr();
}
#endif
//ARP每5s周期性调用一次
if ((lwip_localtime - ARPTimer) >= ARP_TMR_INTERVAL)
{
ARPTimer = lwip_localtime;
etharp_tmr();
}
#if LWIP_DHCP //如果使用DHCP的话
//每500ms调用一次dhcp_fine_tmr()
if (lwip_localtime - DHCPfineTimer >= DHCP_FINE_TIMER_MSECS)
{
DHCPfineTimer = lwip_localtime;
dhcp_fine_tmr();
if ((lwipdev.dhcpstatus != 2)&&(lwipdev.dhcpstatus != 0XFF))
{
lwip_dhcp_process_handle(); //DHCP处理
}
}
//每60s执行一次DHCP粗糙处理
if (lwip_localtime - DHCPcoarseTimer >= DHCP_COARSE_TIMER_MSECS)
{
DHCPcoarseTimer = lwip_localtime;
dhcp_coarse_tmr();
}
#endif
}
void lwip_dhcp_process_handle(void)
{
u32 ip=0,netmask=0,gw=0;
switch(lwipdev.dhcpstatus)
{
case 0: //开启DHCP
dhcp_start(&lwip_netif);
lwipdev.dhcpstatus = 1; //等待通过DHCP获取到的地址
printf("正在查找DHCP服务器,请稍等...........\r\n");
break;
case 1: //等待获取到IP地址
{
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]);
}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;
default : break;
}
}
#endif
第九步:测试
udp_demo_test();
第一步:如果对方IP是动态的,则第一步为设置远程IP
udp_demo_set_remoteip();
//部分代码
/*前三一般较为固定,实际是只需设置第四部分*/
lwipdev.remoteip[0]=lwipdev.ip[0]; //192
lwipdev.remoteip[1]=lwipdev.ip[1]; //168
lwipdev.remoteip[2]=lwipdev.ip[2]; //1
while(1)
{
key=KEY_Scan(0);
if(key==WKUP_PRES)break;
else if(key)
{
if(key==KEY0_PRES)lwipdev.remoteip[3]++;//IP增加
if(key==KEY2_PRES)lwipdev.remoteip[3]--;//IP减少
LCD_ShowxNum(xoff,150,lwipdev.remoteip[3],3,16,0X80);//显示新IP
}
}
第二步:创建DCP控制块
udppcb=udp_new();
第三步:连接指定IP,指定端口
err=udp_connect(udppcb,&rmtipaddr,UDP_DEMO_PORT);//UDP客户端连接到指定IP地址和端口号的服务器
第四步:绑定本地IP和端口号
err=udp_bind(udppcb,IP_ADDR_ANY,UDP_DEMO_PORT);//绑定本地IP地址与端口号
第五步:注册接收回调函数,只要接收到数据,这个回调函数会被lwip内核调用
udp_recv(udppcb,udp_demo_recv,NULL);//注册接收回调函数
//回调函数的编写
void udp_demo_recv(void *arg,struct udp_pcb *upcb,struct pbuf *p,struct ip_addr *addr,u16_t port)
{
u32 data_len = 0;
struct pbuf *q;
if(p!=NULL) //接收到不为空的数据时
{
memset(udp_demo_recvbuf,0,UDP_DEMO_RX_BUFSIZE); //数据接收缓冲区清零
for(q=p;q!=NULL;q=q->next) //遍历完整个pbuf链表
{
//判断要拷贝到UDP_DEMO_RX_BUFSIZE中的数据是否大于UDP_DEMO_RX_BUFSIZE的剩余空间,如果大于
//的话就只拷贝UDP_DEMO_RX_BUFSIZE中剩余长度的数据,否则的话就拷贝所有的数据
if(q->len > (UDP_DEMO_RX_BUFSIZE-data_len)) memcpy(udp_demo_recvbuf+data_len,q->payload,(UDP_DEMO_RX_BUFSIZE-data_len));//拷贝数据
else memcpy(udp_demo_recvbuf+data_len,q->payload,q->len);
data_len += q->len;
if(data_len > UDP_DEMO_RX_BUFSIZE) break; //超出TCP客户端接收数组,跳出
}
upcb->remote_ip=*addr; //记录远程主机的IP地址
upcb->remote_port=port; //记录远程主机的端口号
lwipdev.remoteip[0]=upcb->remote_ip.addr&0xff; //IADDR4
lwipdev.remoteip[1]=(upcb->remote_ip.addr>>8)&0xff; //IADDR3
lwipdev.remoteip[2]=(upcb->remote_ip.addr>>16)&0xff;//IADDR2
lwipdev.remoteip[3]=(upcb->remote_ip.addr>>24)&0xff;//IADDR1
udp_demo_flag|=1<<6; //标记接收到数据了
pbuf_free(p);//释放内存
}else
{
udp_disconnect(upcb);
LCD_Clear(WHITE); //清屏
POINT_COLOR = RED;
LCD_ShowString(30,30,200,16,16,"Explorer STM32F4");
LCD_ShowString(30,50,200,16,16,"UDP Test");
LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK");
POINT_COLOR=BLUE;
LCD_ShowString(30,90,200,16,16,"Connect break!");
LCD_ShowString(30,110,200,16,16,"KEY1:Connect");
udp_demo_flag &= ~(1<<5); //标记连接断开
}
}
**第六步:发送数据udp_send(upcb,ptr); **
关键函数:打包函数,发送函数
void udp_demo_senddata(struct udp_pcb *upcb)
{
struct pbuf *ptr;
ptr=pbuf_alloc(PBUF_TRANSPORT,strlen((char*)tcp_demo_sendbuf),PBUF_POOL); //申请内存
if(ptr)
{
pbuf_take(ptr,(char*)tcp_demo_sendbuf,strlen((char*)tcp_demo_sendbuf)); //将tcp_demo_sendbuf中的数据打包进pbuf结构中
udp_send(upcb,ptr); //udp发送数据
pbuf_free(ptr);//释放内存
}
}
第七步:断开连接
udp_disconnect(upcb);
udp_remove(upcb); //断开UDP连接