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绑定设置。

原来是当初手贱绑定了。

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

懒惰不会让你一下子跌到 但会在不知不觉中减少你的收获; 勤奋也不会让你一夜成功 但会在不知不觉中积累你的成果 越努力,越幸运。
原文地址:https://www.cnblogs.com/Rainingday/p/5987945.html