单片机中的USB 一般来说单片机与电脑的通讯常常使用串口,但是串口的速度并不快,想要更加高速的和上位机通讯可以使用USB接口。
USB中的CDC类来虚拟串口Virtual COM Port(VCP)就可以做到这个。
从USB版本来说目前STM32系列MCU可以认为都是USB2.0的(现在还有了UCPD,对外接口外形可以是Type-C的,但是这个是只能用于PD3.0充电使用的,无法用于数据通讯)。
从硬件接口功能上来说STM32系列MCU的USB分为 USB_FS 、 USB_OTG_FS 、 USB_OTG_HS 三种。其中的FS指的是全速(Full Speed),HS指的是高速(High Speed)。OTG指的是既可以作为Device(从设备)使用,也可以作为Host(主机)使用。
Full Speed 理论上速度为12Mbit/s,High Speed 理论上速度为480Mbit/s
对于STM32系列MCU而言,USB FS的使用只要使用 DM / D- 和 DP / D+ 这两个引脚就行了,最多也就加上ID、SOF、VBUS这三个引脚。而使用USB HS大多数还需要外接PHY芯片(比如USB3300),这样使用的引脚就多了,至少也要用到12个引脚。STM32系列MCU中目前只有STM32F723内置USB HS PHY功能,不需要外接PHY芯片。
在HAL库CubeMX上的使用 在CubeMX上使用比较简单这边就先介绍这种用法
使用外部时钟,对于USB_FS来说总线时钟一般为48MHz
设置为Device_Only只作为从设备使用(根据具体使用情况来)
中间件中启用USB_DEVICE库,使用CDC类(Communication Device Class Virtual Port Com)
相关的代码在USB_DEVICE下的App中,最重要的就是 usbd_cdc_if.c 文件
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 #include "usbd_cdc_if.h" uint8_t UserRxBufferFS[APP_RX_DATA_SIZE]; uint8_t UserTxBufferFS[APP_TX_DATA_SIZE]; extern USBD_HandleTypeDef hUsbDeviceFS;static int8_t CDC_Init_FS (void ) { USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0 ); USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS); } static int8_t CDC_DeInit_FS (void ) {}static int8_t CDC_Control_FS (uint8_t cmd, uint8_t * pbuf, uint16_t length) { switch (cmd) { case CDC_SET_LINE_CODING: break ; } } static int8_t CDC_Receive_FS (uint8_t * Buf, uint32_t *Len) { USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0 ]); USBD_CDC_ReceivePacket(&hUsbDeviceFS); } uint8_t CDC_Transmit_FS (uint8_t * Buf, uint16_t Len) { USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData; if (hcdc->TxState != 0 ){ return USBD_BUSY; } USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len); result = USBD_CDC_TransmitPacket(&hUsbDeviceFS); } static int8_t CDC_TransmitCplt_FS (uint8_t *Buf, uint32_t *Len, uint8_t epnum) {}
CDC_Control_FS() 来自主机请求的回调函数CDC_Receive_FS() 接收数据回调函数;CDC_Transmit_FS() 用来发送数据;CDC_TransmitCplt_FS() 发送完成回调函数;
一些需要注意的设置 USB收发数据都是以一个包一个包的形式进行的,包的大小一方面和USB的协议有关,一方面和程序有关,查看usbd_cdc.h文件
1 2 3 4 5 6 7 8 9 10 11 12 #define CDC_DATA_HS_MAX_PACKET_SIZE 512U #define CDC_DATA_FS_MAX_PACKET_SIZE 64U #define CDC_CMD_PACKET_SIZE 8U #define CDC_DATA_HS_IN_PACKET_SIZE CDC_DATA_HS_MAX_PACKET_SIZE #define CDC_DATA_HS_OUT_PACKET_SIZE CDC_DATA_HS_MAX_PACKET_SIZE #define CDC_DATA_FS_IN_PACKET_SIZE CDC_DATA_FS_MAX_PACKET_SIZE #define CDC_DATA_FS_OUT_PACKET_SIZE CDC_DATA_FS_MAX_PACKET_SIZE
在使用的时候要合理设计数据收发逻辑。对于接收而言可以设计特殊字符用于标示一帧数据结束,或是设计超时时间来判断一帧数据结束。对于发送而言通常不会有太大问题,一次性发送大量数据也行,在全部发送完成后会触发发送完成回调函数CDC_TransmitCplt_FS。
用USB虚拟串口的时候真正数据传输用的是USB,串口本身的参数这些已经关系不大了,但是当单片机一方面要用USB虚拟串口又要用串口和其他模块进行通讯的时候就会出现问题。这时候就要对CDC_SET_LINE_CODING节点进行处理了。