900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > stm32 USB HID+CDC 鼠标键盘串口 组合设备配置解析

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

时间:2023-05-01 00:21:21

相关推荐

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 describingmanufacturer */2,/*Index of string descriptor describingproduct*/3,/*Index of string descriptor describing thedevice serial number */0x01 /*bNumConfigurations*/}; /* Mouse_DeviceDescriptor */

其一,组合设备需要对设备描述符修改为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/*如果有多个接口 下面还可以继续添加*/...}

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

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 describingthe configuration*/字符串索引,若没有字符串描述符,这个字段为00x80, /*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功能时,设备符中的bDeviceClass0x00, //bFunctionSubClass:同单HID功能时,设备符中的bDeviceSubClass0x00, //bFunctionProtocol:同单HID功能时,设备符中的bDeviceProtocol0x01, //iFunction:字符串描述中关于此设备的索引(个人理解是一个字符串描述符中有比如0~5是功能1的字符串,//6~10是功能2的字符串,如果是功能2的话,此值为6)/*******************第一个接口描述符*********************/0x09,//bLength字段0x04,//bDescriptorType字段0x00,/*bInterfaceNumber字段*/从0开始编号0x00,/*bAlternateSetting字段*/必须为0x000x02,/*bNumEndpoints字段*/表示接口描述符有多少个端点0x03,/*bInterfaceClass字段*/设备类型,例如HID、VCP、CDC0x01,/*bInterfaceSubClass字段*/0x00代表No subclass,0x01代表Boot Interface subclass0x01,/*bInterfaceProtocol字段*/0x00 None,0x01 keyboard,0x02 mouse,3~255 reserved0x00,//iConfiguration字段/******************HID描述符************************/0x09,//bLength字段0x21,//bDescriptorType字段0x10,/*bcdHID字段*/设备遵循的HID版本号0x01,0x21,/*bCountyCode字段*/语言0x01,/*bNumDescriptors字段*/下级报告描述符数量,至少为1,0x010x22,/*bDescriptorType字段*/报告描述符必须为0x22//bDescriptorLength字段。//下级描述符的长度。下级描述符为键盘报告描述符。sizeof(KeyboardReportDescriptor)&0xFF,(sizeof(KeyboardReportDescriptor)>>8)&0xFF,/**********************输入端点描述符***********************/0x07,//bLength字段0x05,//bDescriptorType字段0x81,/*bEndpointAddress字段*/端口的地址bit 3~0:端口号bit 7 :0 输入端口(主机到设备)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功能时,设备符中的bDeviceClass0x00, //bFunctionSubClass:同单HID功能时,设备符中的bDeviceSubClass0x00, //bFunctionProtocol:同单HID功能时,设备符中的bDeviceProtocol0x01, //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、 配置描述符中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)//630x09, 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.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};

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);}

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;elseCopyRoutine = Mouse_GetReportDescriptor;}else if (pInformation->USBwValue1 == HID_DESCRIPTOR_TYPE){if (pInformation->USBwIndex0 == 0)CopyRoutine = KP_GetHIDDescriptor;elseCopyRoutine = 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;}

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

ONE_DESCRIPTOR KP_Hid_Descriptor =//{//(u8*)Mouse_ConfigDescriptor + KP_OFF_HID_DESC,//Mouse_SIZ_HID_DESC//};

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)

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);}

最后看一下效果

接入stm32 USB接口时

资源地址 /download/weixin_44748127/85983409?spm=1001..3001.5501

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。