Skip to content

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虚拟串口配置

  1. 打开STM32CubeMX,选择你的STM32芯片型号,并创建一个新的项目。
  2. 在“Pinout & Configuration”选项卡中,找到“Connectivity”部分,点击“USB”选项。
  3. 在“Configuration”选项卡中,找到“Device(FS)”选项,并勾选“Device”选项。
  4. 在 "Middlewares and software packages" 选项卡中,找到 "USB Device" 选项,并点击.
  5. 在 "Class For FS IP" 下拉菜单中选择 "Communication Device Class(Virtual Port Com)"。 选项。
  6. 下面的选项部分一般不需要修改。
需要注意的是: USB接口,需要配置时钟为48MHZ.

四.STM32CUBEMX中USB CDC虚拟串口代码生成

只需要通过 STM32CubeMX 生成代码,不需要添加或是修改任何代码.将USB插入电脑,就可以看到一个虚拟串口(ttyusbACM0).其实这个时候就可以使用了.

五.关键代码:

  1. 核心代码在 这个文件中,重点写了CDC的相关描述符. 这些描述符是USB设备必须的,否则USB设备无法识别.由于CDC的功能比较单一,所以CDC描述符基本不需要修改就可以正常使用.

  2. 虚拟串口数据发送代码:

在单片机中使用串口进行数据收发,也非常简单,只需要在串口接收中断中处理数据即可.

c
uint8_t result = CDC_Transmit_FS((uint8_t*)msg, strlen(msg)); //发送数据

需要注意的是 ,发送数据之前,需要判断一下USB是否已经连接了.如果USB没有连接,那么发送数据就会失败.

c
if (hUsbDeviceFS.dev_state == USBD_STATE_CONFIGURED) //判断USB是否已经连接
{
    //发送数据
}

需要注意的是 编译烧写芯片后 ,原来连接的USB设备,就会断开连接,但是不会自动再次连接.需要手动重新插入USB设备,才会再次连接.

以下是发送数据的示例代码:

c
// 等待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"); // 打印未连接信息
    }
  1. 虚拟串口数据接收代码:

虚拟串口的接收,不是直接从串口中读取数据, USB的虚拟串口是通过回调函数来接收数据的. 这个回调函数在 usbd_cdc_if.c 文件中定义.

这个函数名叫: CDC_Receive_FS()

c
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 中. 这个函数里面原有的二行代码,不要删除,这两行代码是为了在接收完数据之后,为下次再次接收数据做准备用的. 我们写接收数据的代码应该在这两行代码之前.