问题描述
在学习正点原子STM407探索者的网络实验时发现示例代码运行时要求上电前网线必须要接上,而且好像还存在连接后无法热插拔网线的问题。简单实验时没觉得奇怪,但是后来在应用中很多情况上电时我们不可能接着网线,而且无法热插拔也很麻烦。
LWIP示例原代码中只检测了LWIP初始化时的网络连接状态,如正常网线正常连接,则正常初始化;如未连接网线则无法开启网络。原代吗在LWIP运行过程中也不再对网口状态进行检测,且不具备重启netif的功能,所以没有正常初始化则无法再次连接网络。
LWIP初始化代码
void MX_LWIP_Init(void)
{
/* IP addresses initialization */
IP_ADDRESS[0] = 192;
IP_ADDRESS[1] = 168;
IP_ADDRESS[2] = 1;
IP_ADDRESS[3] = 30;
NETMASK_ADDRESS[0] = 255;
NETMASK_ADDRESS[1] = 255;
NETMASK_ADDRESS[2] = 255;
NETMASK_ADDRESS[3] = 0;
GATEWAY_ADDRESS[0] = 192;
GATEWAY_ADDRESS[1] = 168;
GATEWAY_ADDRESS[2] = 1;
GATEWAY_ADDRESS[3] = 1;
/* Initilialize the LwIP stack without RTOS */
lwip_init();
/* IP addresses initialization without DHCP (IPv4) */
IP4_ADDR(&ipaddr, IP_ADDRESS[0], IP_ADDRESS[1], IP_ADDRESS[2], IP_ADDRESS[3]);
IP4_ADDR(&netmask, NETMASK_ADDRESS[0], NETMASK_ADDRESS[1] , NETMASK_ADDRESS[2], NETMASK_ADDRESS[3]);
IP4_ADDR(&gw, GATEWAY_ADDRESS[0], GATEWAY_ADDRESS[1], GATEWAY_ADDRESS[2], GATEWAY_ADDRESS[3]);
/* add the network interface (IPv4/IPv6) without RTOS */
netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input);
/* Registers the default network interface */
netif_set_default(&gnetif);
if (netif_is_link_up(&gnetif))
{
/* When the netif is fully configured this function must be called */
netif_set_up(&gnetif);
}
else
{
/* When the netif link is down this function must be called */
netif_set_down(&gnetif);
}
/* Set the link callback function, this function is called on change of link status*/
netif_set_link_callback(&gnetif, ethernetif_update_config);
/* Create the Ethernet link handler thread */
}
原代码的LWIP并未检测网口状体,如果突然断开连接并无恢复或者提示机制
LWIP运行代码
void MX_LWIP_Process(void)
{
ethernetif_input(&gnetif);
/* Handle timeouts */
sys_check_timeouts();
}
解决方法
针对上述问题,在基本的LWIP连接示例代码中增加网口检测代码,如此我们可以知晓网络状态依次随时调整LWIP的设置以保证网络的稳定。
1.网口状态读取
DP83848_ReadPHY为STM连接的PHY芯片寄存器读取函数,通过寄存器变化可以知道网线连接的状态。
//代码放初始化MX_LWIP_Init函数中的netif_is_link_up检测函数后,添加的这部分代码为物理层的检测。
//初始化时确定实际连接状态
RJ45state1=DP83848_ReadPHY(1)&PHY_LINKED_STATUS;
if(RJ45state1) //Check the network cable status after initialization
{
StateMachine_IP=1; //network work
}
else
{
StateMachine_IP=2; // No network cable needs to check
}
2.网口检测函数
按照图示流程去检测网络
函数对应的代码如下,该函数添加在LWIP运行代码中运行
void netcheck()
{
if(StateMachine_IP==2 && netcheck_1s==1) //check net
{
netcheck_1s=0;
RJ45state1=DP83848_ReadPHY(1)&PHY_LINKED_STATUS;
HAL_Delay(50);
RJ45state2=DP83848_ReadPHY(1)&PHY_LINKED_STATUS;
if((RJ45state1&RJ45state2)==PHY_LINKED_STATUS)
{
Reset_network();
printf("network recovery\r\n");
StateMachine_IP=1;
}
}
3.网口重起函数
掉线或者初始化不成功都可以调用该函数重启网络
void Reset_network() //Allow active Settings
{
IP4_ADDR(&ipaddr, IP_ADDRESS[0], IP_ADDRESS[1], IP_ADDRESS[2], IP_ADDRESS[3]);
IP4_ADDR(&netmask, NETMASK_ADDRESS[0], NETMASK_ADDRESS[1] , NETMASK_ADDRESS[2], NETMASK_ADDRESS[3]);
IP4_ADDR(&gw, GATEWAY_ADDRESS[0], GATEWAY_ADDRESS[1], GATEWAY_ADDRESS[2], GATEWAY_ADDRESS[3]);
printf("静态IP地址........................%d.%d.%d.%d\r\n",IP_ADDRESS[0], IP_ADDRESS[1], IP_ADDRESS[2], IP_ADDRESS[3]);
printf("子网掩码..........................%d.%d.%d.%d\r\n",NETMASK_ADDRESS[0], NETMASK_ADDRESS[1] , NETMASK_ADDRESS[2], NETMASK_ADDRESS[3]);
printf("默认网关..........................%d.%d.%d.%d\r\n",GATEWAY_ADDRESS[0], GATEWAY_ADDRESS[1], GATEWAY_ADDRESS[2], GATEWAY_ADDRESS[3]);
netif_set_down(&gnetif);
netif_set_gw(&gnetif, &gw);//Reloading the IP
netif_set_netmask(&gnetif, &netmask);
netif_set_ipaddr(&gnetif, &ipaddr);
netif_set_up(&gnetif);
printf("Restarting the NIC\r\n");
}
实验结果
初始化时无需接网线并且可以热插拔网线,基于该实验代码还可以实现IP地址的修改等功能。