单片机USB 鼠标键盘实验
单片机 :STM32F407
开发板:DMF407电机开发板
平台:keil V5.31
HSE 为8MHZ
HSI为16MHZ
一、初始化
USBH_Init(&g_hUSBHost, USBH_UserProcess, 1);USBH_HandleTypeDef g_hUSBHost; /* USB Host处理结构体 */ /* USB Host handle structure */ typedef struct _USBH_HandleTypeDef { __IO HOST_StateTypeDef gState; /* Host State Machine Value */ ENUM_StateTypeDef EnumState; /* Enumeration state Machine */ CMD_StateTypeDef RequestState; USBH_CtrlTypeDef Control; USBH_DeviceTypeDef device; USBH_ClassTypeDef *pClass[USBH_MAX_NUM_SUPPORTED_CLASS]; USBH_ClassTypeDef *pActiveClass; uint32_t ClassNumber; uint32_t Pipes[16]; __IO uint32_t Timer; uint32_t Timeout; uint8_t id; void *pData; void (* pUser)(struct _USBH_HandleTypeDef *pHandle, uint8_t id); #if (USBH_USE_OS == 1U) #if osCMSIS < 0x20000 osMessageQId os_event; osThreadId thread; #else osMessageQueueId_t os_event; osThreadId_t thread; #endif uint32_t os_msg; #endif } USBH_HandleTypeDef;void USBH_UserProcess(USBH_HandleTypeDef *phost, uint8_t id) { uint8_t dev_type = 0XFF; /* 设备类型,1,键盘;2,鼠标;其他,不支持的设备 */ switch (id) { case HOST_USER_SELECT_CONFIGURATION: break; case HOST_USER_DISCONNECTION: usbh_msg_show(0); /* 显示已经断开连接,准备重新连接 */ App_State = APPLICATION_DISCONNECT; break; case HOST_USER_CLASS_ACTIVE: App_State = APPLICATION_READY; dev_type = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].bInterfaceProtocol; if (dev_type == HID_KEYBRD_BOOT_CODE) /* 键盘设备 */ { g_usb_first_plugin_flag = 1; /* 标记第一次插入 */ usbh_msg_show(1); /* 显示键盘界面 */ } else if (dev_type == HID_MOUSE_BOOT_CODE) /* 鼠标设备 */ { g_usb_first_plugin_flag = 1; /* 标记第一次插入 */ usbh_msg_show(2); /* 显示鼠标界面 */ } else { usbh_msg_show(3); /* 显示不支持 */ } break; case HOST_USER_CONNECTION: App_State = APPLICATION_START; break; default: break; } }USBH_StatusTypeDef USBH_Init(USBH_HandleTypeDef *phost, void (*pUsrFunc)(USBH_HandleTypeDef *phost, uint8_t id), uint8_t id) { /* Check whether the USB Host handle is valid */ if (phost == NULL) { USBH_ErrLog("Invalid Host handle"); return USBH_FAIL; } /* Set DRiver ID */ phost->id = id; /* Unlink class*/ phost->pActiveClass = NULL; phost->ClassNumber = 0U; /* Restore default states and prepare EP0 */ DeInitStateMachine(phost); /* Restore default Device connection states */ phost->device.PortEnabled = 0U; phost->device.is_connected = 0U; phost->device.is_disconnected = 0U; phost->device.is_ReEnumerated = 0U; /* Assign User process */ if (pUsrFunc != NULL) { phost->pUser = pUsrFunc; } #if (USBH_USE_OS == 1U) #if (osCMSIS < 0x20000U) /* Create USB Host Queue */ osMessageQDef(USBH_Queue, MSGQUEUE_OBJECTS, uint16_t); phost->os_event = osMessageCreate(osMessageQ(USBH_Queue), NULL); /* Create USB Host Task */ #if defined (USBH_PROCESS_STACK_SIZE) osThreadDef(USBH_Thread, USBH_Process_OS, USBH_PROCESS_PRIO, 0U, USBH_PROCESS_STACK_SIZE); #else osThreadDef(USBH_Thread, USBH_Process_OS, USBH_PROCESS_PRIO, 0U, 8U * configMINIMAL_STACK_SIZE); #endif /* defined (USBH_PROCESS_STACK_SIZE) */ phost->thread = osThreadCreate(osThread(USBH_Thread), phost); #else /* Create USB Host Queue */ phost->os_event = osMessageQueueNew(MSGQUEUE_OBJECTS, sizeof(uint32_t), NULL); /* Create USB Host Task */ USBH_Thread_Atrr.name = "USBH_Queue"; #if defined (USBH_PROCESS_STACK_SIZE) USBH_Thread_Atrr.stack_size = USBH_PROCESS_STACK_SIZE; #else USBH_Thread_Atrr.stack_size = (8U * configMINIMAL_STACK_SIZE); #endif /* defined (USBH_PROCESS_STACK_SIZE) */ USBH_Thread_Atrr.priority = USBH_PROCESS_PRIO; phost->thread = osThreadNew(USBH_Process_OS, phost, &USBH_Thread_Atrr); #endif /* (osCMSIS < 0x20000U) */ #endif /* (USBH_USE_OS == 1U) */ /* Initialize low level driver */ USBH_LL_Init(phost); return USBH_OK; }USBH_StatusTypeDef USBH_LL_Init(USBH_HandleTypeDef *phost) { /* Init USB_IP */ if (phost->id == HOST_FS) { /* Link the driver to the stack. */ g_hhcd_USB_OTG_FS.Instance = USB_OTG_FS; /* 使用USB_OTG */ g_hhcd_USB_OTG_FS.Init.Host_channels = 11; /* 主机通道数为11个 */ g_hhcd_USB_OTG_FS.Init.speed = HCD_SPEED_FULL; /* USB全速 12M */ g_hhcd_USB_OTG_FS.Init.dma_enable = DISABLE; /* 不使用DMA */ g_hhcd_USB_OTG_FS.Init.phy_itface = HCD_PHY_EMBEDDED; /* 使能内部PHY */ g_hhcd_USB_OTG_FS.Init.Sof_enable = DISABLE; /* 禁止SOF中断 */ g_hhcd_USB_OTG_FS.Init.vbus_sensing_enable = 0; /* 不使能VBUS检测 */ g_hhcd_USB_OTG_FS.Init.lpm_enable = 0; /* 使能连接电源管理 */ g_hhcd_USB_OTG_FS.Init.low_power_enable = 0; /* 不使能低功耗模式 */ g_hhcd_USB_OTG_FS.pData = phost; phost->pData = &g_hhcd_USB_OTG_FS; if (HAL_HCD_Init(&g_hhcd_USB_OTG_FS) != HAL_OK) { printf("USB Init ERROR \r\n"); } else { printf("USB Init OK \r\n"); } USBH_LL_SetTimer(phost, HAL_HCD_GetCurrentFrame(&g_hhcd_USB_OTG_FS)); } return USBH_OK; }HAL_StatusTypeDef HAL_HCD_Init(HCD_HandleTypeDef *hhcd) { USB_OTG_GlobalTypeDef *USBx; /* Check the HCD handle allocation */ if (hhcd == NULL) { return HAL_ERROR; } /* Check the parameters */ assert_param(IS_HCD_ALL_INSTANCE(hhcd->Instance)); USBx = hhcd->Instance; if (hhcd->State == HAL_HCD_STATE_RESET) { /* Allocate lock resource and initialize it */ hhcd->Lock = HAL_UNLOCKED; #if (USE_HAL_HCD_REGISTER_CALLBACKS == 1U) hhcd->SOFCallback = HAL_HCD_SOF_Callback; hhcd->ConnectCallback = HAL_HCD_Connect_Callback; hhcd->DisconnectCallback = HAL_HCD_Disconnect_Callback; hhcd->PortEnabledCallback = HAL_HCD_PortEnabled_Callback; hhcd->PortDisabledCallback = HAL_HCD_PortDisabled_Callback; hhcd->HC_NotifyURBChangeCallback = HAL_HCD_HC_NotifyURBChange_Callback; if (hhcd->MspInitCallback == NULL) { hhcd->MspInitCallback = HAL_HCD_MspInit; } /* Init the low level hardware */ hhcd->MspInitCallback(hhcd); #else /* Init the low level hardware : GPIO, CLOCK, NVIC... */ HAL_HCD_MspInit(hhcd); #endif /* (USE_HAL_HCD_REGISTER_CALLBACKS) */ } hhcd->State = HAL_HCD_STATE_BUSY; /* Disable DMA mode for FS instance */ if ((USBx->CID & (0x1U << 8)) == 0U) { hhcd->Init.dma_enable = 0U; } /* Disable the Interrupts */ __HAL_HCD_DISABLE(hhcd); /* Init the Core (common init.) */ (void)USB_CoreInit(hhcd->Instance, hhcd->Init); /* Force Host Mode*/ (void)USB_SetCurrentMode(hhcd->Instance, USB_HOST_MODE); /* Init Host */ (void)USB_HostInit(hhcd->Instance, hhcd->Init); hhcd->State = HAL_HCD_STATE_READY; return HAL_OK; }void HAL_HCD_MspInit(HCD_HandleTypeDef *hcdHandle) { GPIO_InitTypeDef gpio_init_struct= { 0 }; if (hcdHandle->Instance == USB_OTG_FS) { __HAL_RCC_GPIOA_CLK_ENABLE(); /* 使能GPIOA时钟 */ gpio_init_struct.Pin = GPIO_PIN_11 | GPIO_PIN_12; gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用 */ gpio_init_struct.Pull = GPIO_NOPULL; /* 浮空 */ gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; /* 高速 */ gpio_init_struct.Alternate = GPIO_AF10_OTG_FS; /* 复用为OTG_FS */ HAL_GPIO_Init(GPIOA, &gpio_init_struct); /* 初始化PA11和PA12引脚 */ __HAL_RCC_USB_OTG_FS_CLK_ENABLE(); /* 使能OTG FS时钟 */ HAL_NVIC_SetPriority(OTG_FS_IRQn, 1, 0); HAL_NVIC_EnableIRQ(OTG_FS_IRQn); } }二、注册
USBH_RegisterClass(&g_hUSBHost, USBH_HID_CLASS);#define USBH_HID_CLASS &HID_Class typedef struct { const char *Name; uint8_t ClassCode; USBH_StatusTypeDef(*Init)(struct _USBH_HandleTypeDef *phost); USBH_StatusTypeDef(*DeInit)(struct _USBH_HandleTypeDef *phost); USBH_StatusTypeDef(*Requests)(struct _USBH_HandleTypeDef *phost); USBH_StatusTypeDef(*BgndProcess)(struct _USBH_HandleTypeDef *phost); USBH_StatusTypeDef(*SOFProcess)(struct _USBH_HandleTypeDef *phost); void *pData; } USBH_ClassTypeDef;USBH_StatusTypeDef USBH_RegisterClass(USBH_HandleTypeDef *phost, USBH_ClassTypeDef *pclass) { USBH_StatusTypeDef status = USBH_OK; if (pclass != NULL) { if (phost->ClassNumber < USBH_MAX_NUM_SUPPORTED_CLASS) { /* link the class to the USB Host handle */ phost->pClass[phost->ClassNumber++] = pclass; status = USBH_OK; } else { USBH_ErrLog("Max Class Number reached"); status = USBH_FAIL; } } else { USBH_ErrLog("Invalid Class handle"); status = USBH_FAIL; } return status; }三、启动
USBH_Start(&g_hUSBHost);USBH_StatusTypeDef USBH_Start(USBH_HandleTypeDef *phost) { /* Start the low level driver */ USBH_LL_Start(phost); /* Activate VBUS on the port */ USBH_LL_DriverVBUS(phost, TRUE); return USBH_OK; }USBH_StatusTypeDef USBH_LL_Start(USBH_HandleTypeDef *phost) { HAL_StatusTypeDef hal_status = HAL_OK; USBH_StatusTypeDef usb_status = USBH_OK; hal_status = HAL_HCD_Start(phost->pData); usb_status = USBH_Get_USB_Status(hal_status); return usb_status; }USBH_StatusTypeDef USBH_LL_DriverVBUS(USBH_HandleTypeDef *phost, uint8_t state) { if (phost->id == HOST_FS) { if (state == 0) { } else { } } USBH_Delay(200); return USBH_OK; }HAL_StatusTypeDef HAL_HCD_Start(HCD_HandleTypeDef *hhcd) { __HAL_LOCK(hhcd); __HAL_HCD_ENABLE(hhcd); (void)USB_DriveVbus(hhcd->Instance, 1U); __HAL_UNLOCK(hhcd); return HAL_OK; }USBH_StatusTypeDef USBH_Get_USB_Status(HAL_StatusTypeDef hal_status) { USBH_StatusTypeDef usb_status = USBH_OK; switch (hal_status) { case HAL_OK : usb_status = USBH_OK; break; case HAL_ERROR : usb_status = USBH_FAIL; break; case HAL_BUSY : usb_status = USBH_BUSY; break; case HAL_TIMEOUT : usb_status = USBH_FAIL; break; default : usb_status = USBH_FAIL; break; } return usb_status; }四、处理
while (1) { USBH_Process(&g_hUSBHost); usb_demo(&g_hUSBHost); if(usbh_check_enume_dead(&g_hUSBHost)) /* 检测USB HOST 枚举是否死机了?死机了,则重新初始化 */ { printf("Error! USB HID reconnect!\r\n"); usbh_hid_reconnect(); /* 重连 */ } }USBH_StatusTypeDef USBH_Process(USBH_HandleTypeDef *phost) { __IO USBH_StatusTypeDef status = USBH_FAIL; uint8_t idx = 0U; /* check for Host pending port disconnect event */ if (phost->device.is_disconnected == 1U) { phost->gState = HOST_DEV_DISCONNECTED; } switch (phost->gState) { case HOST_IDLE : if (phost->device.is_connected) { USBH_UsrLog("USB Device Connected"); /* Wait for 200 ms after connection */ phost->gState = HOST_DEV_WAIT_FOR_ATTACHMENT; USBH_Delay(200U); USBH_LL_ResetPort(phost); /* Make sure to start with Default address */ phost->device.address = USBH_ADDRESS_DEFAULT; phost->Timeout = 0U; #if (USBH_USE_OS == 1U) phost->os_msg = (uint32_t)USBH_PORT_EVENT; #if (osCMSIS < 0x20000U) (void)osMessagePut(phost->os_event, phost->os_msg, 0U); #else (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL); #endif #endif } break; case HOST_DEV_WAIT_FOR_ATTACHMENT: /* Wait for Port Enabled */ if (phost->device.PortEnabled == 1U) { USBH_UsrLog("USB Device Reset Completed"); phost->device.RstCnt = 0U; phost->gState = HOST_DEV_ATTACHED; } else { if (phost->Timeout > USBH_DEV_RESET_TIMEOUT) { phost->device.RstCnt++; if (phost->device.RstCnt > 3U) { /* Buggy Device can't complete reset */ USBH_UsrLog("USB Reset Failed, Please unplug the Device."); phost->gState = HOST_ABORT_STATE; } else { phost->gState = HOST_IDLE; } } else { phost->Timeout += 10U; USBH_Delay(10U); } } #if (USBH_USE_OS == 1U) phost->os_msg = (uint32_t)USBH_PORT_EVENT; #if (osCMSIS < 0x20000U) (void)osMessagePut(phost->os_event, phost->os_msg, 0U); #else (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL); #endif #endif break; case HOST_DEV_ATTACHED : if (phost->pUser != NULL) { phost->pUser(phost, HOST_USER_CONNECTION); } /* Wait for 100 ms after Reset */ USBH_Delay(100U); phost->device.speed = USBH_LL_GetSpeed(phost); phost->gState = HOST_ENUMERATION; phost->Control.pipe_out = USBH_AllocPipe(phost, 0x00U); phost->Control.pipe_in = USBH_AllocPipe(phost, 0x80U); /* Open Control pipes */ USBH_OpenPipe(phost, phost->Control.pipe_in, 0x80U, phost->device.address, phost->device.speed, USBH_EP_CONTROL, (uint16_t)phost->Control.pipe_size); /* Open Control pipes */ USBH_OpenPipe(phost, phost->Control.pipe_out, 0x00U, phost->device.address, phost->device.speed, USBH_EP_CONTROL, (uint16_t)phost->Control.pipe_size); #if (USBH_USE_OS == 1U) phost->os_msg = (uint32_t)USBH_PORT_EVENT; #if (osCMSIS < 0x20000U) (void)osMessagePut(phost->os_event, phost->os_msg, 0U); #else (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL); #endif #endif break; case HOST_ENUMERATION: /* Check for enumeration status */ status = USBH_HandleEnum(phost); if (status == USBH_OK) { /* The function shall return USBH_OK when full enumeration is complete */ USBH_UsrLog("Enumeration done."); phost->device.current_interface = 0U; if (phost->device.DevDesc.bNumConfigurations == 1U) { USBH_UsrLog("This device has only 1 configuration."); phost->gState = HOST_SET_CONFIGURATION; } else { phost->gState = HOST_INPUT; } #if (USBH_USE_OS == 1U) phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT; #if (osCMSIS < 0x20000U) (void)osMessagePut(phost->os_event, phost->os_msg, 0U); #else (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL); #endif #endif } break; case HOST_INPUT: { /* user callback for end of device basic enumeration */ if (phost->pUser != NULL) { phost->pUser(phost, HOST_USER_SELECT_CONFIGURATION); phost->gState = HOST_SET_CONFIGURATION; #if (USBH_USE_OS == 1U) phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT; #if (osCMSIS < 0x20000U) (void)osMessagePut(phost->os_event, phost->os_msg, 0U); #else (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL); #endif #endif } } break; case HOST_SET_CONFIGURATION: /* set configuration */ if (USBH_SetCfg(phost, (uint16_t)phost->device.CfgDesc.bConfigurationValue) == USBH_OK) { phost->gState = HOST_SET_WAKEUP_FEATURE; USBH_UsrLog("Default configuration set."); } #if (USBH_USE_OS == 1U) phost->os_msg = (uint32_t)USBH_PORT_EVENT; #if (osCMSIS < 0x20000U) (void)osMessagePut(phost->os_event, phost->os_msg, 0U); #else (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL); #endif #endif break; case HOST_SET_WAKEUP_FEATURE: if ((phost->device.CfgDesc.bmAttributes) & (1U << 5)) { if (USBH_SetFeature(phost, FEATURE_SELECTOR_REMOTEWAKEUP) == USBH_OK) { USBH_UsrLog("Device remote wakeup enabled"); phost->gState = HOST_CHECK_CLASS; } } else { phost->gState = HOST_CHECK_CLASS; } #if (USBH_USE_OS == 1U) phost->os_msg = (uint32_t)USBH_PORT_EVENT; #if (osCMSIS < 0x20000U) (void)osMessagePut(phost->os_event, phost->os_msg, 0U); #else (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL); #endif #endif break; case HOST_CHECK_CLASS: if (phost->ClassNumber == 0U) { USBH_UsrLog("No Class has been registered."); } else { phost->pActiveClass = NULL; for (idx = 0U; idx < USBH_MAX_NUM_SUPPORTED_CLASS; idx++) { if (phost->pClass[idx]->ClassCode == phost->device.CfgDesc.Itf_Desc[0].bInterfaceClass) { phost->pActiveClass = phost->pClass[idx]; break; } } if (phost->pActiveClass != NULL) { if (phost->pActiveClass->Init(phost) == USBH_OK) { phost->gState = HOST_CLASS_REQUEST; USBH_UsrLog("%s class started.", phost->pActiveClass->Name); /* Inform user that a class has been activated */ phost->pUser(phost, HOST_USER_CLASS_SELECTED); } else { phost->gState = HOST_ABORT_STATE; USBH_UsrLog("Device not supporting %s class.", phost->pActiveClass->Name); } } else { phost->gState = HOST_ABORT_STATE; USBH_UsrLog("No registered class for this device."); } } #if (USBH_USE_OS == 1U) phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT; #if (osCMSIS < 0x20000U) (void)osMessagePut(phost->os_event, phost->os_msg, 0U); #else (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL); #endif #endif break; case HOST_CLASS_REQUEST: /* process class standard control requests state machine */ if (phost->pActiveClass != NULL) { status = phost->pActiveClass->Requests(phost); if (status == USBH_OK) { phost->gState = HOST_CLASS; } else if (status == USBH_FAIL) { phost->gState = HOST_ABORT_STATE; USBH_ErrLog("Device not responding Please Unplug."); } else { /* .. */ } } else { phost->gState = HOST_ABORT_STATE; USBH_ErrLog("Invalid Class Driver."); } #if (USBH_USE_OS == 1U) phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT; #if (osCMSIS < 0x20000U) (void)osMessagePut(phost->os_event, phost->os_msg, 0U); #else (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL); #endif #endif break; case HOST_CLASS: /* process class state machine */ if (phost->pActiveClass != NULL) { phost->pActiveClass->BgndProcess(phost); } break; case HOST_DEV_DISCONNECTED : phost->device.is_disconnected = 0U; DeInitStateMachine(phost); /* Re-Initilaize Host for new Enumeration */ if (phost->pActiveClass != NULL) { phost->pActiveClass->DeInit(phost); phost->pActiveClass = NULL; } if (phost->pUser != NULL) { phost->pUser(phost, HOST_USER_DISCONNECTION); } USBH_UsrLog("USB Device disconnected"); if (phost->device.is_ReEnumerated == 1U) { phost->device.is_ReEnumerated = 0U; /* Start the host and re-enable Vbus */ USBH_Start(phost); } else { /* Device Disconnection Completed, start USB Driver */ USBH_LL_Start(phost); } #if (USBH_USE_OS == 1U) phost->os_msg = (uint32_t)USBH_PORT_EVENT; #if (osCMSIS < 0x20000U) (void)osMessagePut(phost->os_event, phost->os_msg, 0U); #else (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL); #endif #endif break; case HOST_ABORT_STATE: default : break; } return USBH_OK; }void usb_demo(USBH_HandleTypeDef *phost) { char c; HID_KEYBD_Info_TypeDef *k_pinfo; HID_MOUSE_Info_TypeDef *m_pinfo; if (App_State == APPLICATION_READY) { if (USBH_HID_GetDeviceType(phost) == HID_KEYBOARD) /* 键盘设备 */ { k_pinfo = USBH_HID_GetKeybdInfo(phost); /* 获取键盘信息 */ if (k_pinfo != NULL) { c = USBH_HID_GetASCIICode(k_pinfo); /* 转换成ASCII码 */ keybrd_data_process(c); /* 在LCD上显示出键盘字符 */ } } else if (USBH_HID_GetDeviceType(phost) == HID_MOUSE)/* 鼠标设备 */ { m_pinfo = USBH_HID_GetMouseInfo(phost); /* 获取鼠标信息 */ if (m_pinfo != NULL) { mouse_data_process(&mouse_info); /* LCD上显示鼠标信息 */ } } } }uint8_t usbh_check_enume_dead(USBH_HandleTypeDef *phost) { static uint16_t errcnt = 0; /* 这个状态,如果持续存在,则说明USB死机了 */ if (phost->gState == HOST_ENUMERATION && (phost->EnumState == ENUM_IDLE || phost->EnumState == ENUM_GET_FULL_DEV_DESC)) { errcnt++; if (errcnt > 2000) /* 死机了 */ { errcnt = 0; return 1; } } else { errcnt = 0; } return 0; }void usbh_hid_reconnect(void) { /* 关闭之前的连接 */ HID_Class.DeInit(&g_hUSBHost); /* 复位HID */ USBH_DeInit(&g_hUSBHost); /* 复位USB HOST */ /* 重新复位USB */ RCC->AHB2RSTR |= 1 << 7; /* USB OTG FS 复位 */ delay_ms(5); RCC->AHB2RSTR &= ~(1 << 7); /* 复位结束 */ memset(&g_hUSBHost, 0, sizeof(g_hUSBHost)); /* 清零数据 */ /* 重新连接USB HID设备 */ USBH_Init(&g_hUSBHost, USBH_UserProcess, 0); USBH_RegisterClass(&g_hUSBHost, USBH_HID_CLASS); USBH_Start(&g_hUSBHost); }测试结果:
1、接键盘
2、接鼠标
