记录STM32F407+CUBEMX+lwip实现检测网线插拔状态
一、 创建CubeMX工程
1.配置ETH外设如下,我使用的PHY芯片为LAN8270,故选择user phy;配置phy芯片寄存器值,默认即可;设置PA8为PHY芯片复位引脚;开启ETH的全局中断
2.配置LWIP协议;使能LWIP;我使用的是静态IP,未用到DHCP;
使能LWIP_NETIF_LINK_CALLBACK选项,使能该选项时,和网线拔掉重连的一些接口函数才会编译,其实质就是一个条件编译选项
3.系统时钟配置,STM32的HSE选用的8MHZ的时钟源;PHY芯片的时钟可由STM32的MCO引脚输出,也可单独给PHY芯片一个外部时钟源,我使用的是外部时钟;
二、生成工程
三、打开MDK工程,修改mian函数
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_UART5_Init();
MX_LWIP_Init();
MX_TIM1_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
MX_LWIP_Process();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
在while(1)中添加MX_LWIP_Process()函数;修改MX_LWIP_Process函数;
void MX_LWIP_Process(void)
{
/* USER CODE BEGIN 4_1 */
/* USER CODE END 4_1 */
ethernetif_input(&gnetif);
/* USER CODE BEGIN 4_2 */
ethernetif_set_link(&gnetif);//添加该函数
/* USER CODE END 4_2 */
/* Handle timeouts */
sys_check_timeouts();
/* USER CODE BEGIN 4_3 */
/* USER CODE END 4_3 */
}
在原本的工程自动生成的MX_LWIP_Process()函数中添加ethernetif_set_link()函数,这个函数会去读取PHY芯片中网口连接状态的寄存器,并更新struct netif网络接口结构体中保存网络连接状态的值。
四 回调函数
当网线拔掉或重插时会触发以下回调函数;
首先在mian函数中调用的MX_LWIP_Init();该函数中会调用 netif_set_link_callback(&gnetif, ethernetif_update_config)函数,这个函数是注册一个回调函数,当网络连接状态发生变化时会执行ethernetif_update_config函数,这个函数原型如下,
void ethernetif_update_config(struct netif *netif)
{
__IO uint32_t tickstart = 0;
uint32_t regvalue = 0;
if(netif_is_link_up(netif))
{
/* Restart the auto-negotiation */
if(heth.Init.AutoNegotiation != ETH_AUTONEGOTIATION_DISABLE)
{
/* Enable Auto-Negotiation */
HAL_ETH_WritePHYRegister(&heth, PHY_BCR, PHY_AUTONEGOTIATION);
/* Get tick */
tickstart = HAL_GetTick();
/* Wait until the auto-negotiation will be completed */
do
{
HAL_ETH_ReadPHYRegister(&heth, PHY_BSR, ®value);
/* Check for the Timeout ( 1s ) */
if((HAL_GetTick() - tickstart ) > 1000)
{
/* In case of timeout */
goto error;
}
} while (((regvalue & PHY_AUTONEGO_COMPLETE) != PHY_AUTONEGO_COMPLETE));
/* Read the result of the auto-negotiation */
HAL_ETH_ReadPHYRegister(&heth, PHY_SR, ®value);
/* Configure the MAC with the Duplex Mode fixed by the auto-negotiation process */
if((regvalue & PHY_DUPLEX_STATUS) != (uint32_t)RESET)
{
/* Set Ethernet duplex mode to Full-duplex following the auto-negotiation */
heth.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
}
else
{
/* Set Ethernet duplex mode to Half-duplex following the auto-negotiation */
heth.Init.DuplexMode = ETH_MODE_HALFDUPLEX;
}
/* Configure the MAC with the speed fixed by the auto-negotiation process */
if(regvalue & PHY_SPEED_STATUS)
{
/* Set Ethernet speed to 10M following the auto-negotiation */
heth.Init.Speed = ETH_SPEED_10M;
}
else
{
/* Set Ethernet speed to 100M following the auto-negotiation */
heth.Init.Speed = ETH_SPEED_100M;
}
}
else /* AutoNegotiation Disable */
{
error :
/* Check parameters */
assert_param(IS_ETH_SPEED(heth.Init.Speed));
assert_param(IS_ETH_DUPLEX_MODE(heth.Init.DuplexMode));
/* Set MAC Speed and Duplex Mode to PHY */
HAL_ETH_WritePHYRegister(&heth, PHY_BCR, ((uint16_t)(heth.Init.DuplexMode >> 3) |
(uint16_t)(heth.Init.Speed >> 1)));
}
/* ETHERNET MAC Re-Configuration */
HAL_ETH_ConfigMAC(&heth, (ETH_MACInitTypeDef *) NULL);
/* Restart MAC interface */
HAL_ETH_Start(&heth);
}
else
{
/* Stop MAC interface */
HAL_ETH_Stop(&heth);
}
ethernetif_notify_conn_changed(netif);
}
在这个函数末尾调用了一个弱定义函数ethernetif_notify_conn_changed;
__weak void ethernetif_notify_conn_changed(struct netif *netif)
所以只用重写这个函数,就可以检测出网线拔掉或者插上
我的重写如下:
void ethernetif_notify_conn_changed(struct netif *netif)
{
if (netif_is_link_up(netif))
{
printf("netif is link up\r\n");
netif_set_up(netif);
}
else
{
printf("netif set down\r\n");
netif_set_down(netif);
}
}
五 、总结
1 、在MX_LWIP_Process()函数中添加ethernetif_set_link(),完成PHY芯片寄存器网口连接状态的读取,
2. 重写ethernetif_notify_conn_changed()函数,实现自己想要的功能
学习记录 完结~~~~