stm32以太网LWIP学习笔记之UDP通信

初始化配置步骤

第一:硬件底层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(); 
  • 1

UDP协议测试的步骤

第一步:如果对方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连接 


--------------------- 
作者:shenlong1356 
来源:CSDN 
原文:https://blog.csdn.net/shenlong1356/article/details/82729690 
版权声明:本文为博主原创文章,转载请附上博文链接!

你可能感兴趣的:(stm32以太网LWIP学习笔记之UDP通信)