USB CDC虚拟串口复合设备
CDC包含一个控制接口和一个数据接口
1、控制接口
必要的有CM功能描述符和接口绑定描述符(IAD/Union)
在我电脑上测试控制接口的中断端点也可以不需要,及控制接口端点数量可以为0
1.1、ACM功能描述符:
在虚拟串口中,控制接口需要处理ACM 功能描述符。如下是一个ACM描述符,描述了虚拟串口的一些类特定请求,比如可以设置和获取的串口的波特率、停止位等等。
参考:STM32 之 USB 虚拟串口_rannar的博客-CSDN博客_stm32 虚拟串口
bFunctionLength : 0x04 (4 bytes)
bDescriptorType : 0x24 (Interface)
bDescriptorSubType : 0x02 (Abstract Control Management Functional Descriptor)
bmCapabilities : 0x0FD7..4: : 0x00 (Reserved)D3 : : 0x01 (supports the notification Network_Connection)D2 : : 0x01 (supports the request Send_Break)D1 : : 0x01 (supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State)D0 : : 0x01 (supports the request combination of Set_Comm_Feature, Clear_Comm_Feature, and Get_Comm_Feature)
Data (HexDump) : 04 24 02 0F .$..
1.2、IAD和Union描述符
IAD 与 Union 类似,Union 是旧版本下实现多个接口对应一个功能的功能描述符,而 IAD 是 USB 协会后来针对多个接口对应 一个功能的情况而扩展的,旧的主机可能只支持 Union 方式,但 IAD 并不会影响旧版本主机对设备的识别,因为旧版本主机 会通过 Union 来识别哪些接口是联合在一起的,对于 IAD 则跳过忽略;而新版主机则可以通过 IAD 来识别,跳过忽略老的 Union,因此两者可以完美兼容,互不影响。因而主机端可以精确地装载对应的驱动。
两者功能相似,互不影响,分别针对新老协议。在我电脑上配置成多个CDC虚拟串口时,需要给定IAD才能正常出现多个串口(有Union并无区别)。

bFirstInterface 第一个接口的序号,CDC的控制接口编号
bInterfaceCount 本CDC的接口数量,固定为2 (控制接口+数据接口)。数据接口必须紧跟控制接口。

bMasterInterface Communication class interface 控制接口的编号
bSlaveInterface0 Data Class Interface 数据接口的编号 (对比IAD 可以接口可以不连续)
2、 数据接口
简单的就包括一个接口描述符+两个断点描述符即可。
//数据接口/*Data class interface descriptor*/0x09, /* bLength: Endpoint Descriptor size */USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */0x01, /* bInterfaceNumber: Number of Interface */0x00, /* bAlternateSetting: Alternate setting */0x02, /* bNumEndpoints: Two endpoints used */0x0A, /* bInterfaceClass: CDC */0x00, /* bInterfaceSubClass: */0x00, /* bInterfaceProtocol: */0x00, /* iInterface: *//*Endpoint 1 Descriptor*/0x07, /* bLength: Endpoint Descriptor size */USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */0x01, /* bEndpointAddress: (OUT1) */0x02, /* bmAttributes: Bulk */VIRTUAL_COM_PORT_DATA_SIZE, /* wMaxPacketSize: */0x00,0x00, /* bInterval: ignore for Bulk transfer *//*Endpoint 1 Descriptor*/0x07, /* bLength: Endpoint Descriptor size */USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */0x81, /* bEndpointAddress: (IN1) */0x02, /* bmAttributes: Bulk */VIRTUAL_COM_PORT_DATA_SIZE, /* wMaxPacketSize: */0x00,0x00, /* bInterval */
3、多虚拟串口
3.1、设备描述符说明
设备描述附中就描述了设备类型,但作为复合设备,显然一个设备描述符肯定是不可以的。
- bDeviceClass : 类型代码(由USB指定)。当它的值是0时,表示所有接口在配置描述符里,并且所有接口是独立的。当它的值是1到FEH时,表示不同的接口关联的。当它的值是FFH时,它是厂商自己定义的.
针对符合设备,bDeviceClass默认给0即可。
0x12, /*bLength */
USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType*/
0x00, /*bcdUSB */
0x02,
0x00, // 0x00, /*bDeviceClass*/
0x0, // 0x00, /*bDeviceSubClass*/
0x0, // 0x00, /*bDeviceProtocol*/
0x40, /*bMaxPacketSize40*/
0x77, /*idVendor ( )*/
0x86,
0x50, /*idProduct = */
0x58,
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*/
3.2、配置描述符
知道了控制接口的功能后,就知道增加CDC设备需要修改的内容了,为了增加兼容性,IAD和Union描述符都加上吧。
uint8_t Custom_ConfigDescriptor[] = // {0x09, /* bLength: Configuration Descriptor size */USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */0, // sizeof(CustomHID_ConfigDescriptor), 动态设置/* wTotalLength: Bytes returned */0x00,4, /* bNumInterfaces: 1 interface 总的接口数量*/0x01, /* bConfigurationValue: Configuration value */0x00, /* iConfiguration: Index of string descriptor describingthe configuration*/0xC0, /* bmAttributes: Self powered */0x32, /* MaxPower 100 mA: this current is used for detecting Vbus */#if 1 //虚拟串口 1// IAD Interface Association Descriptor //IAD描述符需要添加0x08, // bLength: Interface Descriptor size0x0B, // bDescriptorType: IAD0x00, // bFirstInterface //第一个控制接口的序号 控制接口00x02, // bInterfaceCount //本IDA的接口数量 默认20x02, // bFunctionClass: CDC //表明该IAD是一个CDC设备0x02, // bFunctionSubClass //默认0x01, // bFunctionProtocol //控制协议等其他我也不懂,默认就行0x02, // iFunction/*Interface Descriptor 控制接口*/0x09, /* bLength: Interface Descriptor size */USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface *//* Interface descriptor type */0x00, /* bInterfaceNumber: Number of Interface */0x00, /* bAlternateSetting: Alternate setting */0x00, /* 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 Management 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 */0x0F, /* bmCapabilities *//*Union Functional Descriptor 建议加上*/0x05, /* bFunctionLength */0x24, /* bDescriptorType: CS_INTERFACE */0x06, /* bDescriptorSubtype: Union func desc */0x00, /* bMasterInterface: Communication class interface 控制接口0*/0x01, /* bSlaveInterface0: Data Class Interface 数据接口1*/// /*Endpoint 2 Descriptor 非必须项目 当前接口端点数量设置为0*/// 0x07, /* bLength: Endpoint Descriptor size */// USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */// 0x8A, /* bEndpointAddress: (INx) 无效端口*/// 0x03, /* bmAttributes: Interrupt */// 8, /* wMaxPacketSize: */// 0x00,// 0xFF, /* bInterval: *//*Data class interface descriptor 数据接口*/0x09, /* bLength: Endpoint Descriptor size */USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */0x01, /* 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 */0x01, /* bEndpointAddress: (OUT1) */0x02, /* bmAttributes: Bulk */VIRTUAL_COM_PORT_DATA_SIZE, /* wMaxPacketSize: */0x00,0x00, /* bInterval: ignore for Bulk transfer *//*Endpoint 1 Descriptor*/0x07, /* bLength: Endpoint Descriptor size */USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */0x81, /* bEndpointAddress: (IN1) */0x02, /* bmAttributes: Bulk */VIRTUAL_COM_PORT_DATA_SIZE, /* wMaxPacketSize: */0x00,0x00, /* bInterval */
#endif#if 1 虚拟串口 2/*---------------------------------------------------------------------------*/// IAD Interface Association Descriptor0x08, // bLength: Interface Descriptor size0x0B, // bDescriptorType: IAD0x02, // bFirstInterface 控制接口20x02, // bInterfaceCount 默认20x02, // bFunctionClass: CDC0x02, // bFunctionSubClass0x01, // bFunctionProtocol0x02, // 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 */0x00, /* 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 Management 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 */0x0F, /* bmCapabilities *//*Union Functional Descriptor*/0x05, /* bFunctionLength */0x24, /* bDescriptorType: CS_INTERFACE */0x06, /* bDescriptorSubtype: Union func desc */0x02, /* bMasterInterface: Communication class interface 控制接口2*/0x03, /* bSlaveInterface0: Data Class Interface 数据接口3 */// /*Endpoint 2 Descriptor*/// 0x07, /* bLength: Endpoint Descriptor size */// USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */// 0x8B, /* bEndpointAddress: (INx) 无效端口*/// 0x03, /* bmAttributes: Interrupt */// 8, /* 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 */0x02, /* bEndpointAddress: (OUT1) */0x02, /* bmAttributes: Bulk */VIRTUAL_COM_PORT_DATA_SIZE, /* wMaxPacketSize: */0x00,0x00, /* bInterval: ignore for Bulk transfer *//*Endpoint 1 Descriptor*/0x07, /* bLength: Endpoint Descriptor size */USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */0x82, /* bEndpointAddress: (IN1) */0x02, /* bmAttributes: Bulk */VIRTUAL_COM_PORT_DATA_SIZE, /* wMaxPacketSize: */0x00,0x00, /* bInterval */
#endif
}; /* CustomHID_ConfigDescriptor */
另外还需实现虚拟串口类特定请求
case GET_LINE_CODING://虚拟串口专用 获取串口通讯参数CopyRoutine = Virtual_Com_Port_GetLineCoding;break;case SET_LINE_CODING://虚拟串口专用 设置串口通讯参数CopyRoutine = Virtual_Com_Port_SetLineCoding;Request = SET_LINE_CODING;break;
case SET_COMM_FEATURE://虚拟串口专用 {return USB_SUCCESS;}case SET_CONTROL_LINE_STATE://虚拟串口专用{return USB_SUCCESS;}
然后设备就出现了

当然,还可以更多。。。

所以就可以自己做一个USB转6路TTL,大数据量压力测试,就放在后面做吧。
STM32-CDC6路串口.zip-嵌入式文档类资源-CSDN下载枚举6路虚拟串口,端口打开关闭正常,未实现串口部分更多下载资源、学习资料请访问CSDN下载频道.https://download.csdn.net/download/ai5945fei/46935702
4、端口存储和占用问题
WIn10系统会记录每次分配给设备的端口,保证下一次设备接入还是同样的端口。这个功能在自助终端设备上很重要。

但是也会过多的占用我们经常用的靠前的编号,只需要在注册表
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\COM Name Arbiter
把 ComDB 键删,系统会根据实际情况,重新生成这个键的。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
