• stm32 USB HID+CDC 鼠标键盘串口 组合设备配置解析


    前言

    查阅网上的博客与代码,很多都是关于USB的鼠标配置、USB的键盘配置、USB的虚拟串口配置,稍微深入一点的会将鼠标键盘合在一起,但移植起来就会报很多错误,要么是检测不到,要么是警告,这很正常,因为不理解这些数字代表着什么。但只要理解每个数字代表什么意思,想错都难,干货满满,和我一起学习吧


    1、STM32 usbdesc.c USB描述符配置

    1.1、设备描述符

    /* USB Standard Device Descriptor */
    const uint8_t Mouse_DeviceDescriptor[Mouse_SIZ_DEVICE_DESC] =
      {
        0x12,                       /*bLength */
        USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType*/
        
        0x00,                       /*bcdUSB */
        0x02,
        
        0xEF,                       /*bDeviceClass*/
        0x02,                       /*bDeviceSubClass*/
        0x01,                       /*bDeviceProtocol*/
        
        0x40,                       /*bMaxPacketSize40*/
        
        0x83,                       /*idVendor (0x0483)*/
        0x04,
        
        0x10,                       /*idProduct = 0x5710*/
        0x57,
        
        0x00,                       /*bcdDevice rel. 2.00*/
        0x02,
        
        1,                          /*Index of string descriptor describing
                                                      manufacturer */
        2,                          /*Index of string descriptor describing
                                                     product*/
        3,                          /*Index of string descriptor describing the
                                                     device serial number */
        0x01                        /*bNumConfigurations*/
      }
      ; /* Mouse_DeviceDescriptor */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    其一,组合设备需要对设备描述符修改为0xEF,0x02,0x01,若想了解这三个参数可以百度了解一下,里面有详细的介绍,这里不做说明。
    请添加图片描述
    看起来很懵对吧,其实很多值是固定的不需要修改,只有几项需要修改而已。而且这个配置不随着增加设备或减少设备而改变,配置好后不需要修改,嫌麻烦直接复制上面设备描述符代码就好,兼容性很强。

    1.2、配置描述符

    const uint8_t Mouse_ConfigDescriptor[Mouse_SIZ_CONFIG_DESC] =
    {
      配置描述符   //Configuration Descriptor 只能有1个
    
      /*功能1 HID键盘*/
      IAD描述符    //复合设备才有 在单接口的设备这个可以不要
    		  接口1描述符   //Interface Descriptor
    		  类描述符    //Class Desdriptor
    		  端点描述符  //Endpoint Descriptor
      
      /*功能2 HID鼠标*/
      IAD描述符    //复合设备才有 在单接口的设备这个可以不要
    		  接口2描述符   //Interface Descriptor
    		  类描述符    //Class Desdriptor
    		  端点描述符  //Endpoint Descriptor
    		  
      /*功能3 虚拟串口*/  
      IAD描述符    //复合设备才有 在单接口的设备这个可以不要
    		  接口3描述符   //Interface Descriptor
    		  类描述符    //Class Desdriptor
    		  端点描述符  //Endpoint Descriptor
    
      /*如果有多个接口 下面还可以继续添加*/
      ...
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    举例说明:鼠标+键盘+虚拟串口

    const uint8_t Mouse_ConfigDescriptor[Mouse_SIZ_CONFIG_DESC] =
      {
        0x09, /* bLength: Configuation Descriptor size */
        USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
        Mouse_SIZ_CONFIG_DESC,
        /* wTotalLength: Bytes returned */
        0x00,
        0x04,         /*bNumInterfaces: 4 interface*/设备总数
        0x01,         /*bConfigurationValue: Configuration value*/必须为0x01,或者更高
        0x00,         /*iConfiguration: Index of string descriptor describing
                                         the configuration*/字符串索引,若没有字符串描述符,这个字段为0
        0x80,         /*bmAttributes: bus powered */
        0x32,         /*MaxPower 100 mA: this current is used for detecting Vbus*/
    
    	  
    	  
    	  
    	/*************************************功能1 HID键盘**************************************/
    	/*IAD描述符*/
    	0x08,   //bLength:IAD描述符大小 
    	0x0B,   //bDescriptorType:IAD描述符类型
    	0x00,   //bFirstInterface:功能1 HID键盘的第一个接口描述符是在总的配置描述符中的第几个从0开始数
    	0x01,   //bInferfaceCount:功能1 HID键盘有1个接口描述符
    	0x03,   //bFunctionClass:同单HID功能时,设备符中的bDeviceClass
    	0x00,   //bFunctionSubClass:同单HID功能时,设备符中的bDeviceSubClass
    	0x00,   //bFunctionProtocol:同单HID功能时,设备符中的bDeviceProtocol
    	0x01,   //iFunction:字符串描述中关于此设备的索引(个人理解是一个字符串描述符中有比如0~5是功能1的字符串,
    			//6~10是功能2的字符串,如果是功能2的话,此值为6)
    								
    								
    								
    								
    					 /*******************第一个接口描述符*********************/
    				 0x09,	//bLength字段
    				 0x04,	//bDescriptorType字段
    				 0x00,	/*bInterfaceNumber字段*/0开始编号
    				 0x00,	/*bAlternateSetting字段*/必须为0x00
    				 0x02,	/*bNumEndpoints字段*/表示接口描述符有多少个端点
    				 0x03,	/*bInterfaceClass字段*/设备类型,例如HID、VCP、CDC
    				 0x01,	/*bInterfaceSubClass字段*/0x00代表No subclass,0x01代表Boot Interface subclass
    				 0x01,	/*bInterfaceProtocol字段*/0x00 None,0x01 keyboard,0x02 mouse,3~255 reserved
    				 0x00,	//iConfiguration字段
    				 
    				 /******************HID描述符************************/
    				 0x09,	//bLength字段
    				 0x21,	//bDescriptorType字段
    				 0x10,	/*bcdHID字段*/设备遵循的HID版本号
    				 0x01,
    				 0x21,	/*bCountyCode字段*/语言
    				 0x01,	/*bNumDescriptors字段*/下级报告描述符数量,至少为10x01
    				 0x22,	/*bDescriptorType字段*/报告描述符必须为0x22
    				 
    				 //bDescriptorLength字段。
    				 //下级描述符的长度。下级描述符为键盘报告描述符。
    				 sizeof(KeyboardReportDescriptor)&0xFF,
    				 (sizeof(KeyboardReportDescriptor)>>8)&0xFF,
    				 
    				 /**********************输入端点描述符***********************/
    				 0x07,	//bLength字段
    				 0x05,	//bDescriptorType字段
    				 0x81,	/*bEndpointAddress字段*/端口的地址
    				 								bit 3~0:端口号
    				 								bit 70 输入端口(主机到设备)
    				 										 1 输出端口(设备到主机)
    				 0x03,	//bmAttributes字段
    				 0x10,	//wMaxPacketSize字段
    				 0x00,
    				 0x0A,	//bInterval字段
    				 
    				 /**********************输出端点描述符***********************/
    				 0x07,	//bLength字段
    				 0x05,	//bDescriptorType字段
    				 0x01,	//bEndpointAddress字段
    				 0x03,	//bmAttributes字段
    				 0x10,	//wMaxPacketSize字段
    				 0x00,
    				 0x0A,	//bInterval字段  
    	  
    				 
    				 
    	/*IAD描述符*/
    	0x08,   //bLength:IAD描述符大小 
    	0x0B,   //bDescriptorType:IAD描述符类型
    	0x01,   //bFirstInterface:功能1 HID键盘的第一个接口描述符是在总的配置描述符中的第几个从0开始数
    	0x01,   //bInferfaceCount:功能1 HID键盘有1个接口描述符
    	0x03,   //bFunctionClass:同单HID功能时,设备符中的bDeviceClass
    	0x00,   //bFunctionSubClass:同单HID功能时,设备符中的bDeviceSubClass
    	0x00,   //bFunctionProtocol:同单HID功能时,设备符中的bDeviceProtocol
    	0x01,   //iFunction:字符串描述中关于此设备的索引(个人理解是一个字符串描述符中有比如0~5是功能1的字符串,
    			//6~10是功能2的字符串,如果是功能2的话,此值为6)
    				/************** Descriptor of Mouse Mouse interface ****************/
    				/* 09 */
    				0x09,         /*bLength: Interface Descriptor size*/
    				USB_INTERFACE_DESCRIPTOR_TYPE,/*bDescriptorType: Interface descriptor type*/
    				0x01,         /*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*/
    				/******************** Descriptor of Mouse Mouse HID ********************/
    				/* 18 */
    				0x09,         /*bLength: HID Descriptor size*/
    				HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
    				0x10,         /*bcdHID: HID Class Spec release number*/
    				0x01,
    				0x21,         /*bCountryCode: Hardware target country*/
    				0x01,         /*bNumDescriptors: Number of HID class descriptors to follow*/
    				0x22,         /*bDescriptorType*/
    				Mouse_SIZ_REPORT_DESC,/*wItemLength: Total length of Report descriptor*/
    				0x00,
    				/******************** Descriptor of Mouse Mouse endpoint ********************/
    				/* 27 */
    				0x07,          /*bLength: Endpoint Descriptor size*/
    				USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/
    
    				0x82,          /*bEndpointAddress: Endpoint Address (IN)*/
    				0x03,          /*bmAttributes: Interrupt endpoint*/
    				0x40,          /*wMaxPacketSize: 4 Byte max */
    				0x00,
    				0x0A,          /*bInterval: Polling Interval (32 ms)*/
    				/* 34 */
    	
    	
    	/*IAD描述符 66*/
    	/* Interface Association Descriptor(IAD Descriptor)  */ 
    	0x08,   /*  bLength  */
    	0x0B,   /*  bDescriptorType*/
    	0x02,   /*  bFirstInterface*/
    	0x02,   /*  bInterfaceCount*/
    	0x02,   /*  bFunctionClass --CDC*/
    	0x02,   /*  bFunctionSubClass*/
    	0x01,   /*  bFunctionProtocoll*/
    	0x00,   /*  iFunction */  
    	  
    					/*Interface Descriptor*/
    					0x09,   /* bLength: Interface Descriptor size */
    					USB_INTERFACE_DESCRIPTOR_TYPE,  /* bDescriptorType: Interface */
    					/* Interface descriptor type */
    					0x02,   /* bInterfaceNumber: Number of Interface */
    					0x00,   /* bAlternateSetting: Alternate setting */
    					0x01,   /* bNumEndpoints: One endpoints used */
    					0x02,   /* bInterfaceClass: Communication Interface Class */
    					0x02,   /* bInterfaceSubClass: Abstract Control Model */
    					0x01,   /* bInterfaceProtocol: Common AT commands */
    					0x00,   /* iInterface: */
    					/*Header Functional Descriptor*/
    					0x05,   /* bLength: Endpoint Descriptor size */
    					0x24,   /* bDescriptorType: CS_INTERFACE */
    					0x00,   /* bDescriptorSubtype: Header Func Desc */
    					0x10,   /* bcdCDC: spec release number */
    					0x01,
    					/*Call Managment Functional Descriptor*/
    					0x05,   /* bFunctionLength */
    					0x24,   /* bDescriptorType: CS_INTERFACE */
    					0x01,   /* bDescriptorSubtype: Call Management Func Desc */
    					0x00,   /* bmCapabilities: D0+D1 */
    					0x01,   /* bDataInterface: 1 */
    					/*ACM Functional Descriptor*/
    					0x04,   /* bFunctionLength */
    					0x24,   /* bDescriptorType: CS_INTERFACE */
    					0x02,   /* bDescriptorSubtype: Abstract Control Management desc */
    					0x02,   /* bmCapabilities */
    					/*Union Functional Descriptor*/
    					0x05,   /* bFunctionLength */
    					0x24,   /* bDescriptorType: CS_INTERFACE */
    					0x06,   /* bDescriptorSubtype: Union func desc */
    					0x00,   /* bMasterInterface: Communication class interface */
    					0x01,   /* bSlaveInterface0: Data Class Interface */
    					/*Endpoint 2 Descriptor*/
    					0x07,   /* bLength: Endpoint Descriptor size */
    					USB_ENDPOINT_DESCRIPTOR_TYPE,   /* bDescriptorType: Endpoint */
    					0x85,   /* bEndpointAddress: (IN5) */
    					0x03,   /* bmAttributes: Interrupt */
    					0x40,      /* wMaxPacketSize: */
    					0x00,
    					0xFF,   /* bInterval: */
    					/*Data class interface descriptor*/
    					0x09,   /* bLength: Endpoint Descriptor size */
    					USB_INTERFACE_DESCRIPTOR_TYPE,  /* bDescriptorType: */
    					0x03,   /* bInterfaceNumber: Number of Interface */
    					0x00,   /* bAlternateSetting: Alternate setting */
    					0x02,   /* bNumEndpoints: Two endpoints used */
    					0x0A,   /* bInterfaceClass: CDC */
    					0x00,   /* bInterfaceSubClass: */
    					0x00,   /* bInterfaceProtocol: */
    					0x00,   /* iInterface: */
    					/*Endpoint 3 Descriptor*/
    					0x07,   /* bLength: Endpoint Descriptor size */
    					USB_ENDPOINT_DESCRIPTOR_TYPE,   /* bDescriptorType: Endpoint */
    					0x06,   /* bEndpointAddress: (OUT6) */
    					0x02,   /* bmAttributes: Bulk */
    					0x40,             /* wMaxPacketSize: */
    					0x00,
    					0x00,   /* bInterval: ignore for Bulk transfer */
    					/*Endpoint 1 Descriptor*/
    					0x07,   /* bLength: Endpoint Descriptor size */
    					USB_ENDPOINT_DESCRIPTOR_TYPE,   /* bDescriptorType: Endpoint */
    					0x87,   /* bEndpointAddress: (IN7) */
    					0x02,   /* bmAttributes: Bulk */
    					0x40,             /* wMaxPacketSize: */
    					0x00,
    					0x00    /* bInterval */
    	
    	
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207

    需要注意的点
    1、 配置描述符中0x04, /*bNumInterfaces: 4 interface*/ 必须与设备个数相等。
    2、 每个设备都需要一个IAD描述符。
    3、 bFirstInterface:功能1 HID键盘的第一个接口描述符是在总的配置描述符中的第几个从0开始数
    4、 bNumEndpoints端点数量必须与下面配置的端点数量相同
    5、 bEndpointAddress需要注意地址

    1.3、HID报告描述符

    例如:HID键盘,建议直接复制。

     //USB键盘报告描述符的定义
    const u8 KeyboardReportDescriptor[KP_ReportDescriptor_Size]=
    {
        0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)	//63
        0x09, 0x06,                    // USAGE (Keyboard)
        0xa1, 0x01,                    // COLLECTION (Application)
        0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
        0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
        0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
        0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
        0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
        0x75, 0x01,                    //   REPORT_SIZE (1)
        0x95, 0x08,                    //   REPORT_COUNT (8)
        0x81, 0x02,                    //   INPUT (Data,Var,Abs)
        0x95, 0x01,                    //   REPORT_COUNT (1)
        0x75, 0x08,                    //   REPORT_SIZE (8)
        0x81, 0x03,                    //   INPUT (Cnst,Var,Abs)
        0x95, 0x05,                    //   REPORT_COUNT (5)
        0x75, 0x01,                    //   REPORT_SIZE (1)
        0x05, 0x08,                    //   USAGE_PAGE (LEDs)
        0x19, 0x01,                    //   USAGE_MINIMUM (Num Lock)
        0x29, 0x05,                    //   USAGE_MAXIMUM (Kana)
        0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)
        0x95, 0x01,                    //   REPORT_COUNT (1)
        0x75, 0x03,                    //   REPORT_SIZE (3)
        0x91, 0x03,                    //   OUTPUT (Cnst,Var,Abs)
        0x95, 0x06,                    //   REPORT_COUNT (6)
        0x75, 0x08,                    //   REPORT_SIZE (8)
        0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
        0x25, 0x65,                    //   LOGICAL_MAXIMUM (101)
        0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
        0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))
        0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)
        0x81, 0x00,                    //   INPUT (Data,Ary,Abs)
        0xc0,                           // END_COLLECTION
    	//0xc0,
      }; /* KeyboardMouse_ReportDescriptor */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    1.4、字符串描述符

    说明一下,一般这里不会出错,不做解释。

    /* USB String Descriptors (optional) */
    const uint8_t Mouse_StringLangID[Mouse_SIZ_STRING_LANGID] =
      {
        Mouse_SIZ_STRING_LANGID,
        USB_STRING_DESCRIPTOR_TYPE,
        0x09,
        0x04
      }
      ; /* LangID = 0x0409: U.S. English */
    
    const uint8_t Mouse_StringVendor[Mouse_SIZ_STRING_VENDOR] =
      {
        Mouse_SIZ_STRING_VENDOR, /* Size of Vendor string */
        USB_STRING_DESCRIPTOR_TYPE,  /* bDescriptorType*/
        /* Manufacturer: "STMicroelectronics" */
        'S', 0, 'T', 0, 'M', 0, 'i', 0, 'c', 0, 'r', 0, 'o', 0, 'e', 0,
        'l', 0, 'e', 0, 'c', 0, 't', 0, 'r', 0, 'o', 0, 'n', 0, 'i', 0,
        'c', 0, 's', 0
      };
    
    const uint8_t Mouse_StringProduct[Mouse_SIZ_STRING_PRODUCT] =
      {
        Mouse_SIZ_STRING_PRODUCT,          /* bLength */
        
        USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
       	 'S', 0, 'T', 0, 'M', 0, '3', 0, '2', 0, '1', 0, '0', 0
      };
    uint8_t Mouse_StringSerial[Mouse_SIZ_STRING_SERIAL] =
      {
        Mouse_SIZ_STRING_SERIAL,           /* bLength */
        USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
        'S', 0, 'T', 0, 'M', 0, '3', 0, '2', 0, '1', 0, '0', 0
      };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    2、STM32 usbprop.c USB应用相关的属性配置

    主要包括两个函数的修改,参考此模板进行添加,如下

    void Mouse_Reset(void)
    {
      /* Set Mouse_DEVICE as not configured */
      pInformation->Current_Configuration = 0;
      pInformation->Current_Interface = 0;/*the default Interface*/
    
      /* Current Feature initialization */
      pInformation->Current_Feature = Mouse_ConfigDescriptor[7];
    
      SetBTABLE(BTABLE_ADDRESS);
    
      /* Initialize Endpoint 0 */
      SetEPType(ENDP0, EP_CONTROL);
      SetEPTxStatus(ENDP0, EP_TX_STALL);
      SetEPRxAddr(ENDP0, ENDP0_RXADDR);
      SetEPTxAddr(ENDP0, ENDP0_TXADDR);
      Clear_Status_Out(ENDP0);
      SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);
      SetEPRxValid(ENDP0);
    
      /* Initialize Endpoint 1 */
      SetEPType(ENDP1, EP_INTERRUPT);
      SetEPTxAddr(ENDP1, ENDP1_TXADDR);
      SetEPTxCount(ENDP1, 4);
      SetEPRxStatus(ENDP1, EP_RX_DIS);
      SetEPTxStatus(ENDP1, EP_TX_NAK);
    
    
    	/* Initialize Endpoint Out 1 */
      SetEPRxAddr(ENDP1, ENDP1_RXADDR); //设置接收数据的地址
      SetEPRxCount(ENDP1, 2);  //设置接收长度
      SetEPRxStatus(ENDP1, EP_RX_VALID); //设置端点有效,可以接收数据
    
      /* Initialize Endpoint In 2 */
      SetEPType(ENDP2, EP_INTERRUPT); //初始化为中断端点类型
      SetEPTxAddr(ENDP2, ENDP2_TXADDR); //设置发送数据的地址
      SetEPTxCount(ENDP2, 5); //设置发送的长度
      SetEPTxStatus(ENDP2, EP_TX_NAK); //设置端点处于忙状态
      
      
      
      
      
      
      /* Initialize Endpoint 1 */
      SetEPType(ENDP7, EP_BULK);
      SetEPTxAddr(ENDP7, ENDP7_TXADDR);
      SetEPTxStatus(ENDP7, EP_TX_NAK);
      SetEPRxStatus(ENDP7, EP_RX_DIS);
    
      /* Initialize Endpoint 2 */
      SetEPType(ENDP5, EP_INTERRUPT);
      SetEPTxAddr(ENDP5, ENDP5_TXADDR);
      SetEPRxStatus(ENDP5, EP_RX_DIS);
      SetEPTxStatus(ENDP5, EP_TX_NAK);
    
      /* Initialize Endpoint 3 */
      SetEPType(ENDP6, EP_BULK);
      SetEPRxAddr(ENDP6, ENDP6_RXADDR);
      SetEPRxCount(ENDP6, 64);
      SetEPRxStatus(ENDP6, EP_RX_VALID);
      SetEPTxStatus(ENDP6, EP_TX_DIS);
      
      
      
      bDeviceState = ATTACHED;
    
      /* Set this device to response on default address */
      SetDeviceAddress(0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    RESULT Mouse_Data_Setup(uint8_t RequestNo)
    {
      uint8_t *(*CopyRoutine)(uint16_t);
    
      CopyRoutine = NULL;
      if ((RequestNo == GET_DESCRIPTOR)
          && (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))
          && (pInformation->USBwIndex0 < 4))
      {
    
        if (pInformation->USBwValue1 == REPORT_DESCRIPTOR)
        {
    		
    		if (pInformation->USBwIndex0 == 0)
    			CopyRoutine = KP_GetReportDescriptor;
    		else
    			CopyRoutine = Mouse_GetReportDescriptor;
    		
        }
        else if (pInformation->USBwValue1 == HID_DESCRIPTOR_TYPE)
        {
    		if (pInformation->USBwIndex0 == 0)
    			CopyRoutine = KP_GetHIDDescriptor;
    		else
    			CopyRoutine = Mouse_GetHIDDescriptor;
        }
    
      } /* End of GET_DESCRIPTOR */
    
      /*** GET_PROTOCOL ***/
      else if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
               && RequestNo == GET_PROTOCOL)
      {
        CopyRoutine = Mouse_GetProtocolValue;
      }
    
      
      
      
      
      
      
    if (RequestNo == GET_LINE_CODING)
      {
        if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
        {
          CopyRoutine = Virtual_Com_Port_GetLineCoding;
        }
      }
      else if (RequestNo == SET_LINE_CODING)
      {
        if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
        {
          CopyRoutine = Virtual_Com_Port_SetLineCoding;
        }
        Request = SET_LINE_CODING;
      }
      
      
      
      
      
      
    
      if (CopyRoutine == NULL)
      {
        return USB_UNSUPPORT;
      }
    
      pInformation->Ctrl_Info.CopyData = CopyRoutine;
      pInformation->Ctrl_Info.Usb_wOffset = 0;
      (*CopyRoutine)(0);
      return USB_SUCCESS;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    需要注意的点:KP_OFF_HID_DESC必须与配置描述符中HID对应的类描述符的地址相等,可以理解为地址偏移量

    ONE_DESCRIPTOR KP_Hid_Descriptor =									//
      {																	//
        (u8*)Mouse_ConfigDescriptor + KP_OFF_HID_DESC,					//
        Mouse_SIZ_HID_DESC												//
      };
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3、STM32 usb conf.h USB配置文件

    主要做配置端点基地址

    #define BTABLE_ADDRESS      (0x00)
    
    /* EP0  */
    /* rx/tx buffer base address */
    #define ENDP0_RXADDR        (0x18)
    #define ENDP0_TXADDR        (0x58)
    
    /* EP1  */
    /* tx buffer base address */
    #define ENDP1_TXADDR        (0x100)
    #define ENDP1_RXADDR		(0x110)
    /* EP2  */
    /* tx buffer base address */
    #define ENDP2_TXADDR        (0x120)
    
    
    #define ENDP7_TXADDR        (0x140)
    #define ENDP5_TXADDR        (0x180)
    #define ENDP6_RXADDR        (0x1C0)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    4、STM32 usb istr.c USB中断处理函数

    在文件最后添加对应端点的中断处理函数
    例如如下代码

    u8 EP1BUSY=0;
    u8 EP2BUSY=0;
    void EP1_IN_Callback(void)
    {
    //	EP1BUSY=0;
    }
    void EP2_IN_Callback(void)
    {
    //	EP2BUSY=0;
    }
    void EP1_OUT_Callback(void)
    {
    //	SetEPRxValid(ENDP1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    最后看一下效果

    未接入stm32 usb接口时
    请添加图片描述
    接入stm32 USB接口时
    请添加图片描述

  • 相关阅读:
    手撕Vue-数据驱动界面改变下
    Shell脚本基本使用
    Mutated 源代码解析 client (一)
    Java教程之高阶源码分析-ConcurrentHashMap
    绕过命令过滤器:探索UnixLinux中的Bypass技术
    Double 4 VR仿真情景实训教学系统在商务谈判课堂上的应用
    c++(25)STL:类型转换、异常机制
    面试突击70:什么是粘包和半包?怎么解决?
    SeaTunnel 入门到精通(一)
    Replicate + ngrok云端大模型API实现教程
  • 原文地址:https://blog.csdn.net/weixin_44748127/article/details/125610738