zoukankan      html  css  js  c++  java
  • stm32+lwip动态链路处理!!!

    研究了好几天stm32+lwip动态链路的处理方法,发现大多是写一些lwip移植,tcp/ip移植之类的东西,没有与实际项目相关的内容,今天发些干货,说说这些天stm32+lwip+ucosii实际项目的一些问题:

    1,怎么实现系统网线的热插拔?

     以我的项目为例,PHY为lan8720a。首先要介绍一个重要的函数---GET_PHY_LINK_STATUS();

     其实这个函数就是一个宏,用于读取lan8720a的一个寄存器来查看网线连接状态,返回值为0x04为连接状态,0 未连接。

    #define GET_PHY_LINK_STATUS() (ETH_ReadPHYRegister(LAN8720_PHY_ADDRESS, PHY_BSR) & 0x00000004)
    

     物理层初始化部分,这样处理

     物理层包括LAN8720a和stm32 eth DMA+MAC。系统初始化的时候不要初始化MAC和DMA

     1 void LAN8720_Init(void)
     2 { 
     3         /*打开该打开的时钟*/
     4     /*网络引脚设置 RMII接口 初始化 不写了。。。。*/ 
     5     LAN8720_RST=0;                    //硬件复位LAN8720
     6     delay_ms(50);    
     7     LAN8720_RST=1;                     //复位结束 
     8     ETHERNET_NVICConfiguration();    //设置中断优先级
     9           ETH_MACDMA_Config();
    10 }    
    11 
    12 void ETH_MACDMA_Config(void)
    13 {
    14 //    u8 rval;
    15     //使能以太网MAC以及MAC接收和发送时钟
    16     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_ETH_MAC | RCC_AHB1Periph_ETH_MAC_Tx |RCC_AHB1Periph_ETH_MAC_Rx, ENABLE);
    17     ETH_DeInit();                                  //AHB总线重启以太网
    18     ETH_SoftwareReset();                          //软件重启网络
    19     while (ETH_GetSoftwareResetStatus() == SET);//等待软件重启网络完成 
    20 //    rval = MAC_DMA_Init(); 这些就不在这初始化了 
    21 //    return rval;
    22 }
    23 u8 MAC_DMA_Init(void)
    24 {
    25     u8 rval;
    26     ETH_StructInit(&ETH_InitStructure);          //初始化网络为默认值  
    27     ///网络MAC参数设置 
    28     ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable;               //开启网络自适应功能
    29     ETH_InitStructure.ETH_LoopbackMode = ETH_LoopbackMode_Disable;                    //关闭反馈
    30     ETH_InitStructure.ETH_RetryTransmission = ETH_RetryTransmission_Disable;         //关闭重传功能
    31     ETH_InitStructure.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable;     //关闭自动去除PDA/CRC功能 
    32     ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Disable;                        //关闭接收所有的帧
    33     ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable;//允许接收所有广播帧
    34     ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable;            //关闭混合模式的地址过滤  
    35     ETH_InitStructure.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect;//对于组播地址使用完美地址过滤   
    36     ETH_InitStructure.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect;    //对单播地址使用完美地址过滤 
    37 #ifdef CHECKSUM_BY_HARDWARE
    38     ETH_InitStructure.ETH_ChecksumOffload = ETH_ChecksumOffload_Enable;             //开启ipv4和TCP/UDP/ICMP的帧校验和卸载   
    39 #endif
    40     //当我们使用帧校验和卸载功能的时候,一定要使能存储转发模式,存储转发模式中要保证整个帧存储在FIFO中,
    41     //这样MAC能插入/识别出帧校验值,当真校验正确的时候DMA就可以处理帧,否则就丢弃掉该帧
    42     ETH_InitStructure.ETH_DropTCPIPChecksumErrorFrame = ETH_DropTCPIPChecksumErrorFrame_Enable; //开启丢弃TCP/IP错误帧
    43     ETH_InitStructure.ETH_ReceiveStoreForward = ETH_ReceiveStoreForward_Enable;     //开启接收数据的存储转发模式    
    44     ETH_InitStructure.ETH_TransmitStoreForward = ETH_TransmitStoreForward_Enable;   //开启发送数据的存储转发模式  
    45 
    46     ETH_InitStructure.ETH_ForwardErrorFrames = ETH_ForwardErrorFrames_Disable;         //禁止转发错误帧  
    47     ETH_InitStructure.ETH_ForwardUndersizedGoodFrames = ETH_ForwardUndersizedGoodFrames_Disable;    //不转发过小的好帧 
    48     ETH_InitStructure.ETH_SecondFrameOperate = ETH_SecondFrameOperate_Enable;          //打开处理第二帧功能
    49     ETH_InitStructure.ETH_AddressAlignedBeats = ETH_AddressAlignedBeats_Enable;      //开启DMA传输的地址对齐功能
    50     ETH_InitStructure.ETH_FixedBurst = ETH_FixedBurst_Enable;                        //开启固定突发功能    
    51     ETH_InitStructure.ETH_RxDMABurstLength = ETH_RxDMABurstLength_32Beat;             //DMA发送的最大突发长度为32个节拍   
    52     ETH_InitStructure.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32Beat;            //DMA接收的最大突发长度为32个节拍
    53     ETH_InitStructure.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_2_1;
    54     rval=ETH_Init(&ETH_InitStructure,LAN8720_PHY_ADDRESS);        //配置ETH 这一步 如果网线没插 会等很长时间
    55     if(rval==ETH_SUCCESS)//配置成功
    56     {
    57         ETH_DMAITConfig(ETH_DMA_IT_NIS|ETH_DMA_IT_R,ENABLE);      //使能以太网接收中断    
    58     }
    59     return rval;
    60 }

    是时候编写链路动态处理函数了:

     1 void CableLink_changed(void *pdata)
     2 {
     3     u8 Cable_state = 0;//初始化网线没插
     4     u8 Link_state = 0; //网线连接状态 中间变量
     5     u8 Link_mode = WorkMode;//开启DHCP了吗 
     6     Link_state=GET_PHY_LINK_STATUS();      //先检测了一次
     7     if(Link_state==0x04) Cable_state = 1; //网线连接了  Cable_state 置 1  
     8     while(1)
     9     {
    10         Link_state = GET_PHY_LINK_STATUS();//检测了网线连接
    11         if((Link_state == 0)&&(Cable_state == 1)) //网线断开了(以前是连接着的) 
    12         {
    13             Cable_state = 0;
    14             netif_set_link_down(&lwip_netif);
    15             if(Link_mode == LINK_DHCP)
    16             {
    17                  lwipdev.dhcpstatus = DHCP_LINK_DOWN;
    18                #if LWIP_DHCP
    19                 dhcp_stop(&lwip_netif);
    20                 #endif
    21           }
    22             LCD_ShowString(400,30,60,20,12,"         "); 
    23             LCD_ShowString(400,30,60,20,12,"LINK Down"); 
    24         }
    25         if((Link_state == 0x04)&&(Cable_state == 0))//网线重新连上了
    26         {
    27             Cable_state = 1;
    28             MAC_DMA_Init();                          //重新配置MAC和DMA  甭管是第一次 还是第N次 都要重新配置一次
    29             if(Link_mode == LINK_STATIC)             //静态IP
    30             {
    31                     IP4_ADDR(&(lwip_netif.ip_addr),lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]);
    32                     IP4_ADDR(&(lwip_netif.netmask),lwipdev.netmask[0],lwipdev.netmask[1],lwipdev.netmask[2],lwipdev.netmask[3]);
    33                     IP4_ADDR(&(lwip_netif.gw),lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]);
    34                     netif_set_link_up(&lwip_netif);
    35                     OSSemPost(Comm_Dis);//这里 只在静态IP 释放信号 因为DHCP任务中会释放  给显示任务发信号
    36             }
    37             else                                     //开启了DHCP
    38             {
    39                     IP4_ADDR(&(lwip_netif.ip_addr),0,0,0,0);//这几步很重要 
    40                     IP4_ADDR(&(lwip_netif.netmask),0,0,0,0);//当网络环境发生变化 比如路由器dhcp允许分配的IP发送变化或者系统网线插到别的路由器了
    41                     IP4_ADDR(&(lwip_netif.gw),0,0,0,0);     //重新开启了dhcp_start(&gnetif),会重新分配IP,不然申请不下来
    42                     lwip_netif.flags |= NETIF_FLAG_LINK_UP; //关于这里,感觉只用把NETIF_FLAG_LINK_UP置一就行了,开启dhcp_start后,随后会调用
    43                     //netif_set_link_up(&lwip_netif);       //netif_set_up() 来刷存在感
    44                     lwip_comm_dhcp_Resume();                //开启dhcp管理任务
    45             }
    46             LCD_ShowString(400,30,60,20,12,"         "); //dchp 打开
    47             LCD_ShowString(400,30,60,20,12,"LINK ON"); //dchp 打开    
    48         }
    49         delay_ms(500);
    50     }
    51 }

    这是一个ucos任务,差不多 1秒执行2次。

    这样就可以处理动态连理的情况了。

    2 静态IP情况下系统上电刷两次存在感?

    先上图:

    会有两个Gratutious arp request,一个mac是02:00:00:2a:00:2a 一个是02:00:00:42:00:42 而且他们一个是16进制 1个是十进制。他们都是系统发出的吗?

    我查看了好多文档,仿真查看寄存器,都不知道为什么,无意中我发现了路由器中的静态arp绑定设置。

    原来是当初手贱绑定了。

     正在试验阶段,写的比较粗糙。将就看吧。

    懒惰不会让你一下子跌到 但会在不知不觉中减少你的收获; 勤奋也不会让你一夜成功 但会在不知不觉中积累你的成果 越努力,越幸运。
  • 相关阅读:
    D
    洛谷P2002 消息扩散
    洛谷P5058 [ZJOI2004]嗅探器
    洛谷P2746 校园网Network of Schools
    洛谷P3388 【模板】割点(割顶)
    洛谷P1407 [国家集训队]稳定婚姻
    2018年12月18日
    洛谷P1547 Out of Hay
    洛谷P4018 Roy&October之取石子
    洛谷P1318 积水面积
  • 原文地址:https://www.cnblogs.com/Rainingday/p/5987945.html
Copyright © 2011-2022 走看看