USB CDC虚拟串口
一.CDC简介
CDC(Communications Device Class)是USB通信设备类,它定义了在USB设备上实现串行通信的协议。CDC协议允许计算机将USB设备识别为串行端口,从而可以使用串行通信协议(如RS-232)与设备进行通信。CDC协议包括多个子类,如抽象控制模型(ACM)、Ethernet控制模型(ECM)和无线控制模型(WCM),每种子类都定义了特定的通信协议和功能。
CDC协议提供了一种方法,将USB设备识别为串行端口,并使用串行通信协议(如RS-232)与设备进行通信。CDC协议定义了通信协议和功能,如数据传输、数据格式转换、数据校验和错误处理等。
安卓开发兼容性
安卓应用开发中,可以很容易的使用USB CDC虚拟串口,实现USB设备与安卓手机之间的通信. 这种方式很方便,不需要任何硬件配置.
二.USB CDC示例程序引脚配置
主要使用的就是 USB引脚: 即 USB_DM、USB_DP。 
三.STM32CUBEMX中USB CDC虚拟串口配置
- 打开STM32CubeMX,选择你的STM32芯片型号,并创建一个新的项目。
- 在“Pinout & Configuration”选项卡中,找到“Connectivity”部分,点击“USB”选项。
- 在“Configuration”选项卡中,找到“Device(FS)”选项,并勾选“Device”选项。
- 在 "Middlewares and software packages" 选项卡中,找到 "USB Device" 选项,并点击.
- 在 "Class For FS IP" 下拉菜单中选择 "Communication Device Class(Virtual Port Com)"。 选项。
- 下面的选项部分一般不需要修改。

需要注意的是: USB接口,需要配置时钟为48MHZ. 
四.STM32CUBEMX中USB CDC虚拟串口代码生成
只需要通过 STM32CubeMX 生成代码,不需要添加或是修改任何代码.将USB插入电脑,就可以看到一个虚拟串口(ttyusbACM0).其实这个时候就可以使用了.
五.关键代码:
核心代码在
这个文件中,重点写了CDC的相关描述符. 这些描述符是USB设备必须的,否则USB设备无法识别.由于CDC的功能比较单一,所以CDC描述符基本不需要修改就可以正常使用.虚拟串口数据发送代码:
在单片机中使用串口进行数据收发,也非常简单,只需要在串口接收中断中处理数据即可.
uint8_t result = CDC_Transmit_FS((uint8_t*)msg, strlen(msg)); //发送数据需要注意的是 ,发送数据之前,需要判断一下USB是否已经连接了.如果USB没有连接,那么发送数据就会失败.
if (hUsbDeviceFS.dev_state == USBD_STATE_CONFIGURED) //判断USB是否已经连接
{
//发送数据
}需要注意的是 编译烧写芯片后 ,原来连接的USB设备,就会断开连接,但是不会自动再次连接.需要手动重新插入USB设备,才会再次连接.
以下是发送数据的示例代码:
// 等待USB连接后才发送数据
if(hUsbDeviceFS.dev_state == USBD_STATE_CONFIGURED)
{
char *msg = "Hello from STM32 CDC!\r\n";
printf("USB CDC 连接成功\n"); // 打印连接成功信息
// 检查传输状态后再发送
USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
if(hcdc->TxState == 0) // 确保上次传输已完成
{
uint8_t result = CDC_Transmit_FS((uint8_t*)msg, strlen(msg));
if(result == USBD_OK) {
// 发送成功
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET); // 点亮LED表示发送成功
} else {
// 发送失败
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET); // 熄灭LED表示发送失败
}
}
}else{
printf("USB CDC 没有连接\n"); // 打印未连接信息
}- 虚拟串口数据接收代码:
虚拟串口的接收,不是直接从串口中读取数据, USB的虚拟串口是通过回调函数来接收数据的. 这个回调函数在 usbd_cdc_if.c 文件中定义.

这个函数名叫: CDC_Receive_FS()
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
return (USBD_OK);
/* USER CODE END 6 */
}在这个函数中,将接收到的数据保存在 Buf 中. 这个函数里面原有的二行代码,不要删除,这两行代码是为了在接收完数据之后,为下次再次接收数据做准备用的. 我们写接收数据的代码应该在这两行代码之前.
