嵌入式开发--STM32G431的USB设备掉线检测--设备端

发布于:2025-06-20 ⋅ 阅读:(16) ⋅ 点赞:(0)

问题描述

STM32开发USB设备,一般是将其模拟为CDC设备,也就是虚拟串口设备Vitual Port Com,如果在使用的过程中设备掉线了,通讯也就中断了。

解决方案

如何检测自身与电脑的连接是否正常呢?

方案1 检测VBUS

可以通过VBUS检测电压,当检测不到VBUS电压时,会触发中断,通过检测这个中断就可以判断设备是否掉线了。这个是硬件检测,系统开销比较小。

方案2 分压电路

也可以搭一个分压电路,另用一个引脚检测分压电路的下降沿。
但是方案1和方案2都是检测5V电压的,如果USB的差分线短路导致设备连接失败的话,是检测不了的。

方案3 SOF检测

STM32G431是不支持VBUS检测的,这时我们可以通过帧首包SOF(start of frame)来实现。对于USB的差分信号线故障造成的断连,也可以检测出来。安全性是最好的,但是系统开销会增大。

USB主设备会定时发送SOF包,全速设备是1ms,高速设备是125us,持续不断的发送信号出来。同时STM32的USB支持包,会检测SOF,并输出中断。我们只需要响应这个中断,并记录收到SOF包的时间即可。

在任何时刻都可以查询这个时间,如果一旦超时,就可以认为USB设备掉线,这时可以重启USB模块,重新进行连接。

使能USB模块,并开启SOF

在这里插入图片描述

中间件的设置

开启中间件的支持,并选择CDC设备
在这里插入图片描述

增加堆栈的长度

这一步非常重要,否则会在设备管理器中出现感叹号,一般0x400和0x800就够了,我习惯设大一点,放心。 在这里插入图片描述

代码

在usb_conf.c文件中,需要做修改,我增加的代码,都有中文注释

void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd)
{
  /* USER CODE BEGIN HAL_PCD_SetupStageCallback_PreTreatment */

  /* USER CODE END  HAL_PCD_SetupStageCallback_PreTreatment */
  USBD_LL_SetupStage((USBD_HandleTypeDef*)hpcd->pData, (uint8_t *)hpcd->Setup);
  /* USER CODE BEGIN HAL_PCD_SetupStageCallback_PostTreatment */
  LED1(1); 					//点亮LED
  usb_enum_ok_flag = 1;		//枚举成功的标志
  /* USER CODE END  HAL_PCD_SetupStageCallback_PostTreatment */
}
void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd)
{
  /* USER CODE BEGIN HAL_PCD_SOFCallback_PreTreatment */

  /* USER CODE END HAL_PCD_SOFCallback_PreTreatment */
  USBD_LL_SOF((USBD_HandleTypeDef*)hpcd->pData);
  /* USER CODE BEGIN HAL_PCD_SOFCallback_PostTreatment */
  
  //会每1ms进一次这个中断,增加系统开销
  last_sof_time = HAL_GetTick();	//记录最后一次收到SOF的时间

  /* USER CODE END HAL_PCD_SOFCallback_PostTreatment */
}
void Check_USB_Connection()
{
  u32 offset;
  
  offset = HAL_GetTick();
  if((offset - last_sof_time) > 100) // 正常应为1或0,以100ms作为超时时间
  {
    // USB连接可能已断开
    LED1(0);
    LL_usb_reload();	//重启USB模块
  }
}
//重新初始化
void LL_usb_reload(void)  
{
  __HAL_RCC_USB_FORCE_RESET();
  delay_us(1);
  __HAL_RCC_USB_RELEASE_RESET();

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  GPIO_InitStruct.Pin = GPIO_PIN_12;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLDOWN;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  HAL_GPIO_WritePin(GPIOA,GPIO_PIN_12,GPIO_PIN_RESET);
  HAL_Delay(300);    
  HAL_GPIO_WritePin(GPIOA,GPIO_PIN_12,GPIO_PIN_SET);
  HAL_Delay(300);    
  
  MX_USB_Device_Init();
  HAL_Delay(300);    
}

最后,在主程序中运行

Check_USB_Connection();

运行现象

正常工作时,LED1会亮。

设备拔掉,或人为模拟USB差分线故障,比如短路USB的2根信号线时时,LED会灭。
这时程序会不停的尝试重启USB模块,并连接主机。如果成功后,LED会点亮。


网站公告

今日签到

点亮在社区的每一天
去签到