全文目录

  • 创建CubeMX工程
  • 一、新建工程
  • 二、USB
  • 三、生成代码
  • 四、了解usbd_hid.c
  • 更改代码实现鼠标改键盘
  • 键码值(keyCode)
  • 补充


参考文章

STM32CubeMX学习笔记(45)——USB接口使用(HID鼠标)STM32-USB学习系列(六):USB-HID键盘的实现以及键盘报文描述符的简介HID设备(USB键鼠/扫码枪)转串口(UART)键盘键值及字符处理示例——CH9350本文对在以上三篇文章中引用的内容进行整合,并通过实践验证了各个步骤的可行性,增加了代码修改方面的相关细节

创建CubeMX工程

一、新建工程

  1. 打开 STM32CubeMX 软件,点击“新建工程”
  2. 选择 MCU 和封装
  3. 配置时钟
    RCC 设置,选择 HSE(外部高速时钟) 为 Crystal/Ceramic Resonator(晶振/陶瓷谐振器)

    选择 Clock Configuration,配置系统时钟 SYSCLK 为 72MHz
    修改 HCLK 的值为 72 后,输入回车,软件会自动修改所有配置
  4. 配置调试模式
    非常重要的一步,否则会造成第一次烧录程序后续无法识别调试器
    SYS 设置,选择 Debug 为 Serial Wire

二、USB

  1. 参数配置
    Connectivity 中选择 USB 设置,并勾选 Device (FS) 激活 USB 设备。
    “FS” stands for “Full Speed”.
  2. bios 键盘鼠标唤醒 bios鼠标唤醒什么意思_键盘

  3. Parameter Settings 进行具体参数配置。
  4. bios 键盘鼠标唤醒 bios鼠标唤醒什么意思_计算机外设_02

  5. Speed: Full Speed 12MBit/s(固定为全速)
    Low Power: 默认 Disabled(在任何不需要使用usb模块的时候,通过写控制寄存器总可以使usb模块置于低功耗模式(low power mode ,suspend模式)。在这种模式下,不产生任何静态电流消耗,同时usb时钟也会减慢或停止。通过对usb线上数据传输的检测,可以在低功耗模式下唤醒usb模块。也可以将一特定的中断输入源直接连接到唤醒引脚上,以使系统能立即恢复正常的时钟系统,并支持直接启动或停止时钟系统。)
  6. 引脚配置
    USB 的 DP 引脚必须上拉 1.5K 欧的电阻,电脑才能检测到 USB,否则检测不到。
  7. bios 键盘鼠标唤醒 bios鼠标唤醒什么意思_计算机外设_03

  8. 野火:需要将 PD6 配置为低电平使能 USB
  9. bios 键盘鼠标唤醒 bios鼠标唤醒什么意思_键盘_04

  10. 在右边图中找到 PD6 引脚,选择 GPIO_Output
  11. bios 键盘鼠标唤醒 bios鼠标唤醒什么意思_计算机外设_05

  12. GPIO output level 中选择 Low 输出低电平。
  13. bios 键盘鼠标唤醒 bios鼠标唤醒什么意思_键盘_06

  14. 正点原子:只需将排针4–6和3–5分别用跳线帽相连
  15. bios 键盘鼠标唤醒 bios鼠标唤醒什么意思_bios 键盘鼠标唤醒_07

  16. 由于本次需要实现USB HID keyboard,故需要使用开关KEY0~2。可参照以上的GPIO配置步骤将相应的引脚配置为GPIO_Input,Pull_up。
  17. 配置时钟
    选择 Clock Configuration,USB 时钟配置为 48MHz,且来源最好是外部晶振分频得到。
  18. bios 键盘鼠标唤醒 bios鼠标唤醒什么意思_计算机外设_08

  19. USB Device

USB有主机(Host)和设备(Device)之分。一般电脑的USB接口为主机接口,而键盘、鼠标、U盘等则为设备。
部分型号的STM32芯片有1~2个USB接口。像STM32F103系列的有一个USB
Device接口,STM32F407系列的有2个USB接口,既可以作为HOST,又可以作为Device,还可以作为OTG接口。

  1. Middleware 中选择 USB_DEVICE 设置,在 Class For FS IP 设备类别选择 Human Interface Device Class (HID)人机接口设备。
  2. bios 键盘鼠标唤醒 bios鼠标唤醒什么意思_bios 键盘鼠标唤醒_09

  3. 参数配置保持默认。
  4. bios 键盘鼠标唤醒 bios鼠标唤醒什么意思_键盘_10

  5. HID_FS_BINTERVAL(主机读取设备数据时间间隔)0xA(STM32将数据发送到一个缓存区,而不是直接发送到上位机,而上位机每隔一端时间会来访问缓冲区读取数据。读取时间间隔过快会导致多次数据发送,过慢会导致数据丢失)
    USBD_MAX_NUM_INTERFACES (Maximum number of supported interfaces)(最大支持HID设备的接口数)1(应为现在只有鼠标,所以1就行,如果是需要同时键盘,鼠标,手柄之类的,根据数量选择即可)
    设备描述符保持默认。
  6. bios 键盘鼠标唤醒 bios鼠标唤醒什么意思_bios 键盘鼠标唤醒_11

三、生成代码

  1. 输入项目名和项目路径
  2. 选择应用的 IDE 开发环境 MDK-ARM V5
  3. 每个外设生成独立的 ’.c/.h’ 文件
    不选:所有初始化代码都生成在 main.c
    勾选:初始化代码生成在对应的外设文件。 如 GPIO 初始化代码生成在 gpio.c 中。
  4. 点击 GENERATE CODE 生成代码

四、了解usbd_hid.c

打开工程文件夹Middlewares/USB_Device_Libraryusbd_hid.c文件

bios 键盘鼠标唤醒 bios鼠标唤醒什么意思_嵌入式硬件_12

  1. USB HID描述符
    HID设备的描述符除了5个USB的标准描述符(设备描述符、配置描述符、接口描述符、端点描述符、字符串描述符)外,还包括3个HID设备类特定的描述符:HID描述符、报告描述符(Report)、实体描述符(Physical)。
    他们之间的层次关系如图:

    打开usbd_hid.c文件,找到USBD_HID_CfgFSDesc配置全速(Full Speed)描述符数组定义处(由于配置USB设备时将其置为了全速,所以不用管USBD_HID_CfgHSDesc(High Speed))
    • 配置描述符
    bNumInterfaces表示这个设备有多少个接口。
    MaxPower 100 mA表示这个设备需要从总线上获取100mA电流。
/* USB HID device FS Configuration Descriptor */
__ALIGN_BEGIN static uint8_t USBD_HID_CfgFSDesc[USB_HID_CONFIG_DESC_SIZ]  __ALIGN_END =
{
  0x09, /* bLength: Configuration Descriptor size */
  USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
  USB_HID_CONFIG_DESC_SIZ,
  /* wTotalLength: Bytes returned */
  0x00,
  0x01,         /*bNumInterfaces: 1 interface*/
  0x01,         /*bConfigurationValue: Configuration value*/
  0x00,         /*iConfiguration: Index of string descriptor describing
  the configuration*/
  0xE0,         /*bmAttributes: bus powered and Support Remote Wake-up */
  0x32,         /*MaxPower 100 mA: this current is used for detecting Vbus*/

• 接口描述符
bInterfaceClass的值必须是 0x03
bInterfaceSubClass的值为 0 或 1, 为1表示HID设备是一个启动设备(BootDevice, 一般对PC机有意义,意思是BIOS启动时能识别所使用的HID设备,且只有标准鼠标或者键盘才能称为BootDevice),为0表示HID设备是操作系统启动厚才能识别使用的设备。
bInterfaceProtocol的值为 2 表示鼠标接口:(0 — NONE,1 — Keyboard(键盘),2 — Mouse (鼠标),3~255 Reserved)

/************** Descriptor of Joystick Mouse interface ****************/
  /* 09 */
  0x09,         /*bLength: Interface Descriptor size*/
  USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
  0x00,         /*bInterfaceNumber: Number of Interface*/
  0x00,         /*bAlternateSetting: Alternate setting*/
  0x01,         /*bNumEndpoints*/
  0x03,         /*bInterfaceClass: HID*/
  0x01,         /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
  0x02,         /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
  0,            /*iInterface: Index of string descriptor*/

• HID描述符
HID描述符关联于接口描述符,因而如果一个设备只有一个接口描述符,则无论它有几个端点描述符,HID设备只有一个HID描述符。HID设备描述符主要描述HID规范的版本号, HID通信所使用的额外描述符,报告描述符的长度等。

/******************** Descriptor of Joystick Mouse HID ********************/
  /* 18 */
  0x09,         /*bLength: HID Descriptor size*/
  HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
  0x11,         /*bcdHID: HID Class Spec release number*/
  0x01,
  0x00,         /*bCountryCode: Hardware target country*/
  0x01,         /*bNumDescriptors: Number of HID class descriptors to follow*/
  0x22,         /*bDescriptorType*/
  HID_MOUSE_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
  0x00,

• 端点描述符
bEndpointAddress表示端点地址,表示当前这个接口所需要的端点资源,输入(相对于主机而言)端点最高位为1,输出(相对于主机而言)端点最高位为0。HID设备一般都是使用中断端点进行数据传输。
wMaxPacketSize表示该端点上数据传输的数量。
bInterval表示主机查询设备数据的时间间隔,如果设置的太长,则键盘输入延迟很高。

  1. 报告描述符
    下载 HID Descriptor Tool (DT) HID描述符工具:
    官网下载:https://usb.org/sites/default/files/documents/dt2_4.zip 百度网盘:https://pan.baidu.com/s/1ayjdQtc7e9NWwYJqdp0pXA?pwd=4ghb 提取码:4ghb
    打开 FileOpen...mouse.hid (键盘应该使用keybrd.hid,但本文为在程序中保留鼠标相关内容,故在mouse.hid中直接进行修改)
  2. bios 键盘鼠标唤醒 bios鼠标唤醒什么意思_键盘_13

  3. 我们可以看到HID鼠标的描述符情况:
  4. bios 键盘鼠标唤醒 bios鼠标唤醒什么意思_键盘_14

  5. 打开usbd_hid.c文件,找到HID_MOUSE_ReportDesc数组定义处(默认生产HID设备为Mouse,所以需要增加键盘数组)。
  6. bios 键盘鼠标唤醒 bios鼠标唤醒什么意思_计算机外设_15

更改代码实现鼠标改键盘

  1. 修改HID的接口描述符与报文描述符
    注意:端点描述符不做修改!即 HID_EPIN_SIZE 还是0x04 (对应4字节大小,后面在发送键盘报文的时候,需要将键盘的报文大小修改为 4个字节的数组或者结构体)
    usbd_hid.h中引入宏定义USE_KEYBOARD_HIDHID_KEYBOARD_REPORT_DESC_SIZE
#define USE_KEYBOARD_HID 1	//WY: 1=enable; 0=disable
		
#define HID_EPIN_ADDR                 0x81U
#define HID_EPIN_SIZE                 0x04U
	
#define USB_HID_CONFIG_DESC_SIZ       34U
#define USB_HID_DESC_SIZ              9U
#define HID_MOUSE_REPORT_DESC_SIZE    74U
#define HID_KEYBOARD_REPORT_DESC_SIZE	63U	//WY: for keyboard

USBD_HID_CfgFSDesc中修改

/************** Descriptor of Joystick Mouse interface ****************/
  /* 09 */
  0x09,         /*bLength: Interface Descriptor size*/
  USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
  0x00,         /*bInterfaceNumber: Number of Interface*/
  0x00,         /*bAlternateSetting: Alternate setting*/
  0x01,         /*bNumEndpoints*/
  0x03,         /*bInterfaceClass: HID*/
  0x01,         /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
#if(USE_KEYBOARD_HID)
  0x01,         //WY: nInterfaceProtocol: keyboard
#else
  0x02,		/*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
#endif
  0,            /*iInterface: Index of string descriptor*/
/******************** Descriptor of Joystick Mouse HID ********************/
  /* 18 */
  0x09,         /*bLength: HID Descriptor size*/
  HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
  0x11,         /*bcdHID: HID Class Spec release number*/
  0x01,
  0x00,         /*bCountryCode: Hardware target country*/
  0x01,         /*bNumDescriptors: Number of HID class descriptors to follow*/
  0x22,         /*bDescriptorType*/
#if(USE_KEYBOARD_HID)
  HID_KEYBOARD_REPORT_DESC_SIZE,
#else
  HID_MOUSE_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
#endif
  0x00,
  1. 修改USBD_HID_Setup函数
    在HID Setup的过程中会获取对应键盘报文描述符
case USB_REQ_GET_DESCRIPTOR:
          if (req->wValue >> 8 == HID_REPORT_DESC)
          {
#if(USE_KEYBOARD_HID)
			len = MIN(HID_KEYBOARD_REPORT_DESC_SIZE, req->wLength);
            pbuf = HID_KEYBOARD_ReportDesc;
#else
            len = MIN(HID_MOUSE_REPORT_DESC_SIZE, req->wLength);
            pbuf = HID_MOUSE_ReportDesc;
#endif
          }
  1. 添加以及修改键盘报文描述符
    注意:修改部分为最后面按键输入描述部分,将后面6个按键缩减为2个按键(即:从6个字节缩减到2个字节),配合上前面2个字节的输入报告,正好是4个字节,刚好符合原来HID端点描述符一次最多发送的大小
    将原有HID_MOUSE_ReportDesc的内容注释掉,并在其后增加以下定义
__ALIGN_BEGIN static uint8_t HID_KEYBOARD_ReportDesc[HID_KEYBOARD_REPORT_DESC_SIZE]  __ALIGN_END =
{
	0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
	0x09, 0x06,                    // USAGE (Keyboard)		   /* 用途为键盘 */
	0xa1, 0x01,                    // COLLECTION (Application) /* 表示应用结合,必须以END_COLLECTION来结束 */
	0x05, 0x07,                    //   USAGE_PAGE (Keyboard)  /* 用途页为按键 */
	0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)  /* 用途最小值 左Ctrl */
	0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)	  /* 用途最大值 右GUI */
	0x15, 0x00,                    //   LOGICAL_MINIMUM (0)	   /* 逻辑最小值 0 */
	0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)	   /* 逻辑最大值 1 */
	0x75, 0x01,                    //   REPORT_SIZE (1)      /* 报告位大小(这个字段的宽度为1bit) */
	0x95, 0x08,                    //   REPORT_COUNT (8) 	 /* 输入报告第一个字节(报告位大小 8bit) */
	0x81, 0x02,                    //   INPUT (Data,Var,Abs) /* 报告为输入用 , 从左ctrl到右GUI 8bit刚好构成1个字节*/
	 
	0x95, 0x01,                    //   REPORT_COUNT (1)	 /* 报告位数量  1个 */
	0x75, 0x08,                    //   REPORT_SIZE (8)      /* 输入报告的第二给字节(报告位大小 8bit) */
	0x81, 0x03,                    //   INPUT (Cnst,Var,Abs) /* 输入用的保留位,设备必须返回0 */
	 
	0x95, 0x05,                    //   REPORT_COUNT (5)     /* 报告位数量 5个 */
	0x75, 0x01,                    //   REPORT_SIZE (1)		 /* 报告位大小,1bit */
	0x05, 0x08,                    //   USAGE_PAGE (LEDs)    /* 用途为LED */
	0x19, 0x01,                    //   USAGE_MINIMUM (Num Lock) /* 用途最小值 NUM Lock LED灯 */
	0x29, 0x05,                    //   USAGE_MAXIMUM (Kana)  /* 用途最大值 Kana 灯 */
	0x91, 0x02,                    //   OUTPUT (Data,Var,Abs) /* 输出用途,用于控制LED等 */
	 
	0x95, 0x01,                    //   REPORT_COUNT (1)     /* 报告位数量 1个 */
	0x75, 0x03,                    //   REPORT_SIZE (3)      /* 报告位大小 3bit */
	0x91, 0x03,                    //   OUTPUT (Cnst,Var,Abs)/* 用于字节补齐,跟前面5个bit进行补齐 */
	 
	0x95, 0x02,                    //   REPORT_COUNT (6)  /* 报告位数量 6个*/
	0x75, 0x08,                  	//   REPORT_SIZE (8)		 /* 报告位大小 8bit */
	0x15, 0x00,                    //   LOGICAL_MINIMUM (0)		 /* 逻辑最小值0 */
	0x25, 0xFF,                    //   LOGICAL_MAXIMUM (255)    /* 逻辑最大值255 */
	0x05, 0x07,                    //   USAGE_PAGE (Keyboard)    /* 用途页为按键 */
	0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated)) /* 使用值最小为0 */
	0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)		  /* 使用值最大为65 */
	0x81, 0x00,                    //   INPUT (Data,Ary,Abs)	 /* 输入用,变量,数组,绝对值 */
	0xc0  						   								 /* END_COLLECTION */
};

键码值(keyCode)

  1. 以键盘为例(扫码枪一般模拟键盘输入)报文示例如下:

    报文前三个字节的固定内容可自动生成,故代码中只需通过后8个字节传递正确的键码值,例如在main.c中定义:
uint8_t txbuffer[8]= {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uint8_t sendbuffer_Enter[8]={0x00,0x00,0x28,0x00,0x00,0x00,0x00,0x00};
uint8_t sendbuffer_Aa[8]={0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00};
uint8_t sendbuffer_Space[8]={0x00,0x00,0x2C,0x00,0x00,0x00,0x00,0x00};

发送报文使用USBD_HID_SendReport函数,为使代码友好易读,故在usb_device.c中对此函数进行封装,以便在main函数中直接调用:

uint8_t MX_USB_DEVICE_Send(uint8_t *sendbuffer)
{	
	return USBD_HID_SendReport(&hUsbDeviceFS,sendbuffer,8);	//Full speed
}
  1. 全键盘码值表如下提供参考:
//Keybord keyvalue define
#define KEY_NULL 0x00          // NULL
#define KEY_A 0x04             // A
#define KEY_B 0x05             // B
#define KEY_C 0x06             // C
#define KEY_D 0x07             // D
#define KEY_E 0x08             // E
#define KEY_F 0x09             // F
#define KEY_G 0x0A             // G
#define KEY_H 0x0B             // H
#define KEY_I 0x0C             // I
#define KEY_J 0x0D             // J
#define KEY_K 0x0E             // K
#define KEY_L 0x0F             // L
#define KEY_M 0x10             // M
#define KEY_N 0x11             // N
#define KEY_O 0x12             // O
#define KEY_P 0x13             // P
#define KEY_Q 0x14             // Q
#define KEY_R 0x15             // R
#define KEY_S 0x16             // S
#define KEY_T 0x17             // T
#define KEY_U 0x18             // U
#define KEY_V 0x19             // V
#define KEY_W 0x1A             // W
#define KEY_X 0x1B             // X
#define KEY_Y 0x1C             // Y
#define KEY_Z 0x1D             // Z
#define KEY_1 0x1E             // 1 and !
#define KEY_2 0x1F             // 2 and @
#define KEY_3 0x20             // 3 and #
#define KEY_4 0x21             // 4 and $
#define KEY_5 0x22             // 5 and %
#define KEY_6 0x23             // 6 and ^
#define KEY_7 0x24             // 7 and &
#define KEY_8 0x25             // 8 and *
#define KEY_9 0x26             // 9 and (
#define KEY_0 0x27             // 10 and )
#define KEY_ENTER 0x28         // ENTER
#define KEY_ESC 0x29           // ESC
#define KEY_BACKSPACE 0x2A     // BACKSPACE
#define KEY_TAB 0x2B           // TAB
#define KEY_SPACE 0x2C         // SPACE
#define KEY_SUB 0x2D           // - and _
#define KEY_EQUAL 0x2E         // = and +
#define KEY_LEFT_BRACKET 0x2F  // [ and {
#define KEY_RIGHT_BRACKET 0x30 // ] and }
#define KEY_VERTICAL_LINE 0x31 // "\" and |
#define KEY_WAVE 0x32          // ` and ~
#define KEY_SEMICOLON 0x33     // ; and :
#define KEY_QUOTE 0x34         // ' and "
#define KEY_THROW 0x35         // ~ and `
#define KEY_COMMA 0x36         // , and <
#define KEY_DOT 0x37           // . and >
#define KEY_QUESTION 0x38      // / and ?
#define KEY_CAPS_LOCK 0x39     // CAPS
#define KEY_F1 0x3A
#define KEY_F2 0x3B
#define KEY_F3 0x3C
#define KEY_F4 0x3D
#define KEY_F5 0x3E
#define KEY_F6 0x3F
#define KEY_F7 0x40
#define KEY_F8 0x41
#define KEY_F9 0x42
#define KEY_F10 0x43
#define KEY_F11 0x44
#define KEY_F12 0x45
#define KEY_PRT_SCR 0x46
#define KEY_SCOLL_LOCK 0x47
#define KEY_PAUSE 0x48
#define KEY_INS 0x49
#define KEY_HOME 0x4A
#define KEY_PAGEUP 0x4B
#define KEY_DEL 0x4C
#define KEY_END 0x4D
#define KEY_PAGEDOWN 0x4E
#define KEY_RIGHT_ARROW 0x4F
#define KEY_LEFT_ARROW 0x50
#define KEY_DOWN_ARROW 0x51
#define KEY_UP_ARROW 0x52
//Num Pad
#define KEY_PAD_NUMLOCK 0x53
#define KEY_PAD_DIV 0x54
#define KEY_PAD_MUL 0x55
#define KEY_PAD_SUB 0x56
#define KEY_PAD_ADD 0x57
#define KEY_PAD_ENTER 0x58
#define KEY_PAD_1 0x59
#define KEY_PAD_2 0x5A
#define KEY_PAD_3 0x5B
#define KEY_PAD_4 0x5C
#define KEY_PAD_5 0x5D
#define KEY_PAD_6 0x5E
#define KEY_PAD_7 0x5F
#define KEY_PAD_8 0x60
#define KEY_PAD_9 0x61
#define KEY_PAD_0 0x62
#define KEY_PAD_DOT 0x63
#define KEY_PRESSED 0x00
#define KEY_RELEASED 0x01
// Control
#define KEY_LCTRL 0xE0  // left ctrl // #define KEY_LCTRL 0x01
#define KEY_LALT 0xE2   // left Alt // #define KEY_LALT 0x04
#define KEY_LSHFIT 0xE1 // left Shift // #define KEY_LSHFIT 0x02
#define KEY_LWIN 0xE3   // left windows // #define KEY_LWIN 0x08
#define KEY_RWIN 0xE7   // right windows // #define KEY_RWIN 0x80
#define KEY_RSHIFT 0xE5 // right Shift // #define KEY_RSHIFT 0x20
#define KEY_RALT 0xE6   // right Alt // #define KEY_RALT 0x40
#define KEY_RCTRL 0xE4  // right Ctrl // #define KEY_RCTRL 0x10
#define KEY_APP 0x65    // Application // #define KEY_APP 0x65
#define KEY_K14 0x89    // international key
#define KEY_KR_L 0x91
#define KEY_K107 0x85
#define KEY_K45 0x64
#define KEY_K42 0x32
#define KEY_K131 0x8b
#define KEY_K132 0x8a
#define KEY_K133 0x88
#define KEY_K56 0x87
#define KEY_KR_R 0x90

补充

电脑设备管理器显示“未知USB设备(设备描述符请求失败)”时:
个人经验:
最好在CubeMX程序第一次生成之后(无改动)确认是否能识别设备,若此时识别成功,则之后再遇“未知USB设备(设备描述符请求失败)”问题时,重新插拔USB接口即可恢复正常。