目的:能够实时的检测网线的插拔状态。并能够根据网线的插拔状态通知到到应用层,让应用层做相应的处理。
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循环去掉,里面相关延时去掉。将其放入主程序的大循环中,定时器起一个标志定时检测即可。