基于STM32F103xx的USB转多路串口(USB-Multiple-CDC)测试已完成,全部开启DMA自动发送功能。简要说明如下:
1. 支持通过DMA方式连续发送超过64字节大小的数据包。而且在DMA发送的同时,继续接收来自PC主机的数据。发完64字节后,RS485不换向,可以立即发送剩余的数据。
2. USB转多路串口(USB-Multiple-CDC)支持在大虾103核心板,USB-Dual-RS485板上运行,代码无需修改。在其它板子上运行,需要修改USB控制脚和RS485控制脚。
3. 三路CDC串口,均支持DMA发送功能,接收仍为中断方式。TLL通信使用时,波特率不要超过921600bps。RS232/RS485通信时,硬件限制一般不能超过250000/500000bps。
STM32_USB-FS-Device_Lib_V7.0.0.2014.12.20_3CDC_for_DX103.zip 可不用修改直接运行在大虾103核心板上。其它STM32F103xx板子需要修改。
备注: USB-Dual-RS485板的通信部分为专用磁耦隔离的RS485芯片,只需要一个USB端口,就能同时连接两台PLC 刷新程序。目前USB-Dual-RS485板处于缺货状态,但有大虾103核心板大量供应。
附录:“USB复合设备”和“USB组合设备”的区别
关键字 Communication Device Class,简称CDC
USB Compound Device,USB复合设备 USB Composite Device,USB组合设备
摘要 Compound Device内嵌Hub和多个Function,每个Function都相当于一个独立的USB外设,有自己的PID/VID/DID。 Composite Device内只有一个Function,只有一套PID/VID/DID,通过将不同的interface定义为不同的类来实现 多个功能的组合。
正文 Compound Device内嵌Hub和多个Function,每个Function都相当于一个独立的USB外设,有自己的PID/VID/DID。
Composite Device内只有一个Function,只有一套PID/VID/DID,通过将不同的interface定义为不同的类来实现多个功能的组
合。很多人认为一个USB接口上实现多个设备,就是指复合设备,其实,这是不确切的,虽然USB Compound Device和USB Composite Device 都会被百度翻译为USB复合设备。
在一个USB接口上实现多个设备有2中方法,一种是Compound Device,就是复合设备;另一种是Composite Device,就是组合设备。 在USB2.0的标准协议中,定义如下:
When multiple functions are combined with a hub in a single package, they are referred to as a compound device.
![]()
A device that has multiple interfaces controlled independently of each other is referred to as a
composite device.
所以,复合设备其实就是几个设备通过一个USB Hub形成的单一设备;组合设备也就是具有多个接口的设备,每个接口代表一个独立的设备。显然,如果是想同样的功能的话,组合设备的方法要简单很多(可以去看一下USB2.0协议中,USB2.0 Hub的复杂度)。
附录:USB Serial Tools工具软件的特殊功能介绍
一般的串口调试工具,不会针对USB插拔做专门的检测和处理,比较容易崩溃,例如微软收购的超级终端等。 USB Serial Tools 是本人自2009-2012年,个人业余时间开发的一个带有USB插拔检测的串口调试软件。 和其它串口调试工具相比,是专用软件,值得一提的功能如下: 1 支持高波特率。(支持该功能的串口调试工具屈指可数,大部分串口调试工具仅支持到115200) 2 支持USB插拔检测。(支持该功能的串口调试工具屈指可数,大部分串口调试工具都会因此崩溃) 3 支持STM32虚拟串口的USB端点号显示(该工具特有的支持,和嵌入式及PC的底层驱动相关)。
![]()
![]()
1. USB数据接收及阻塞式串口发送,部分源代码浏览如下: /* USB的OUT端点 通过物理串口向外发送数据(阻塞方式) */ #define EPx_OUT_Callback(ENDPx, USARTx, GPIOx, GPIO_Pin_x) { uint32_t i; uint16_t USB_Rx_Cnt; USB_Rx_Cnt = USB_SIL_Read(ENDPx | 0x00, USB_Rx_Buffer); GPIOx->BSRR = GPIO_Pin_x; for (i = 0; i < USB_Rx_Cnt; i++) { USARTx->DR = *(USB_Rx_Buffer + i); while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET); } SetEPRxValid(ENDPx); while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET); USART_ClearFlag(USARTx, USART_FLAG_TC); GPIOx->BRR = GPIO_Pin_x; } 2. USB数据接收及DMA式串口发送,部分源代码浏览如下 /* USB的OUT端点 通过物理串口向外发送数据(DMA方式) */ #define EPx_OUT_Callback_DMA(Flag_VCPx_Tx_Buf_Use, ENDPx, VCPx_Tx_Buffer1,VCPx_Tx_Buffer2, GPIOx, GPIO_Pin_x, DMA1_Channelx, VCPx_Tx_Buffer_Cnt, Flag_VCPx_Tx_Buf_Full) { uint16_t USB_Rx_Cnt; if(Flag_VCPx_Tx_Buf_Use == 0){ USB_Rx_Cnt = GetEPRxCount(ENDPx & 0x7F); PMAToUserBufferCopy(&VCPx_Tx_Buffer1[0], GetEPRxAddr(ENDPx & 0x7F), USB_Rx_Cnt); SetEPRxValid(ENDPx); GPIOx->BSRR = GPIO_Pin_x; DMA1_Channelx->CNDTR = USB_Rx_Cnt; DMA_Cmd(DMA1_Channelx, ENABLE); Flag_VCPx_Tx_Buf_Use = 1; VCPx_Tx_Buffer_Cnt = 0; } else { USB_Rx_Cnt = GetEPRxCount(ENDPx & 0x7F); if(VCPx_Tx_Buffer_Cnt < (1024-128)){ PMAToUserBufferCopy(&VCPx_Tx_Buffer2[VCPx_Tx_Buffer_Cnt], GetEPRxAddr(ENDPx & 0x7F), USB_Rx_Cnt); VCPx_Tx_Buffer_Cnt += USB_Rx_Cnt; SetEPRxValid(ENDPx); } else { PMAToUserBufferCopy(&VCPx_Tx_Buffer2[VCPx_Tx_Buffer_Cnt], GetEPRxAddr(ENDPx & 0x7F), USB_Rx_Cnt); VCPx_Tx_Buffer_Cnt += USB_Rx_Cnt; Flag_VCPx_Tx_Buf_Full = 1; } } }
以上两段代码是带参数的宏,由于是多个USB端点和串口之间的通信数据转发,思路是一样的,但写代码的时候, 就非常容易写错,因此用带参数的宏代替。每个虚拟串口通信函数内,都插入这些带参数的宏,编译器在编译预 处理时,会将这些宏展开, 然后再进行编译。只要调好了一个虚拟串口,另外两个就调好了,非常方便。编译器 是不会出现书写错误的。
One CDC function requires 2 IN / 1 OUT endpoints (interrupt IN/ bulk IN/ bulk OUT), other than the default EP. Available endpoints of each STM32F family are,
STM32F102/103 - FS Device core: 7 IN / 7 OUT
STM32F105/107 - OTG_FS: 3 IN / 3 OUT
STM32F2xx/4xx - OTG_FS: 3 IN / 3 OUT - OTG_HS: 5 IN / 5 OUT
STM32F102/103 - 3x CDC composite STM32F105/107 - just one CDC STM32F2xx/4xx - 2x CDC composite on OTG_HS
|