目的:能够实时的检测网线的插拔状态。并能够根据网线的插拔状态通知到到应用层,让应用层做相应的处理。
1.解决问题的根本方法就是看lan8720的数据手册!!!!
如果说你用过一款芯片,而没有去研究过它的数据手册时,可以说你没有用过这个芯片。
在Lan8720数据手册的第48页给出了这个芯片的控制和状态寄存器资料。因为我们是要用来检测lan8720连接网线的状态,所以这个状态应该是属于Basic Status Register这个类别的。
我们跳转到这个寄存器的说明:
红色框框圈出来的是Lan8720的速度以及状态,因为这个是一款10/100M自适应的以太网芯片,所以就有了10M和100M的速度模式的检测。我们可以看到LinK Status状态位是这个寄存器的第2位,我们只需要读取这个寄存器得到的值,然后对这个值的第二位进行与1运算,该位与1得到1则说明网线连接正常,该位与1得到0则说明网线连接断开。
在刚开始验证RTT的这部分代码时,没有细看这个功能,后来想到这个问题的时候,重新看了一遍代码,发现RTT也做了这部分的检测,只是我们没有把调试日志打开,所以没有看到这部分的功能。
检测的代码如下:[摘自RTT]
/* PHY: LAN8720 */ static uint8_t phy_speed = 0; #define PHY_LINK_MASK (1<<0) //1左移0位,结果还是1 #define PHY_100M_MASK (1<<1) //1左移1位,结果是2 #define PHY_DUPLEX_MASK (1<<2) //1左移2位,结果是4 static void phy_monitor_thread_entry(void *parameter) { uint8_t phy_addr = 0xFF; uint8_t phy_speed_new = 0; /* phy search */ { rt_uint32_t i; rt_uint16_t temp; for(i=0; i<=0x1F; i++) { temp = ETH_ReadPHYRegister(i, 0x02); if( temp != 0xFFFF ) { phy_addr = i; break; } } } /* phy search */ if(phy_addr == 0xFF) { STM32_ETH_PRINTF("phy not probe!\r\n"); return; } else { STM32_ETH_PRINTF("found a phy, address:0x%02X\r\n", phy_addr); } /* RESET PHY */ STM32_ETH_PRINTF("RESET PHY!\r\n"); ETH_WritePHYRegister(phy_addr, PHY_BCR, PHY_Reset); rt_thread_delay(RT_TICK_PER_SECOND * 2); ETH_WritePHYRegister(phy_addr, PHY_BCR, PHY_AutoNegotiation); while(1) { uint16_t status = ETH_ReadPHYRegister(phy_addr, PHY_BSR);//读取Basic Status Register的值 STM32_ETH_PRINTF("LAN8720 status:0x%04X\r\n", status); phy_speed_new = 0; if(status & (PHY_AutoNego_Complete | PHY_Linked_Status)) { uint16_t SR; SR = ETH_ReadPHYRegister(phy_addr, 31); STM32_ETH_PRINTF("LAN8720 REG 31:0x%04X\r\n", SR); SR = (SR >> 2) & 0x07; /* LAN8720, REG31[4:2], Speed Indication. */ phy_speed_new = PHY_LINK_MASK; if((SR & 0x03) == 2) { phy_speed_new |= PHY_100M_MASK; } if(SR & 0x04) { phy_speed_new |= PHY_DUPLEX_MASK; } } /* linkchange */ if(phy_speed_new != phy_speed) { if(phy_speed_new & PHY_LINK_MASK)//和1进行&运算,得1,则代表连接。否则,断开 { STM32_ETH_PRINTF("link up "); if(phy_speed_new & PHY_100M_MASK) { STM32_ETH_PRINTF("100Mbps"); stm32_eth_device.ETH_Speed = ETH_Speed_100M; } else { stm32_eth_device.ETH_Speed = ETH_Speed_10M; STM32_ETH_PRINTF("10Mbps"); } if(phy_speed_new & PHY_DUPLEX_MASK) { STM32_ETH_PRINTF(" full-duplex\r\n"); stm32_eth_device.ETH_Mode = ETH_Mode_FullDuplex; } else { STM32_ETH_PRINTF(" half-duplex\r\n"); stm32_eth_device.ETH_Mode = ETH_Mode_HalfDuplex; } rt_stm32_eth_init((rt_device_t)&stm32_eth_device); /* send link up. */ //网线正常连接,通知上层应用 //可以根据自己的需求进行修改 eth_device_linkchange(&stm32_eth_device.parent, RT_TRUE); } /* link up. */ else { STM32_ETH_PRINTF("link down\r\n"); /* send link down. */ //网线断开,通知上层应用 可以根据自己的需求进行修改 eth_device_linkchange(&stm32_eth_device.parent, RT_FALSE); } /* link down. */ phy_speed = phy_speed_new; } /* linkchange */ rt_thread_delay(RT_TICK_PER_SECOND); } /* while(1) */ }只需要其一个线程来实时监测即可。
如果是裸机代码,把while循环去掉,里面相关延时去掉。将其放入主程序的大循环中,定时器起一个标志定时检测即可。
