🔥作者简介: 一个平凡而乐于分享的小比特,中南民族大学通信工程专业研究生,研究方向无线联邦学习
🎬擅长领域:驱动开发,嵌入式软件开发,BSP开发
❄️作者主页:一个平凡而乐于分享的小比特的个人主页
✨收录专栏:通信协议,本专栏为记录项目中用到的知识点,以及一些硬件常识总结
欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖

USB CDC串口通信详解:把USB变成"智能串口线"
一、CDC是什么?------USB时代的串口革命
CDC(Communications Device Class,通信设备类) 是一种USB设备类规范,它让USB设备可以模拟传统的串口(COM口),但性能大幅提升。
传统串口 vs USB CDC串口
传统串口(RS-232)时代:
┌─────────┐ 串口线(9针) ┌─────────┐
│ 单片机 │←---慢速+大电压--→│ 电脑 │
└─────────┘ 最大115.2Kbps └─────────┘
问题:速度慢、需要专用接口、电压高
USB CDC时代:
┌─────────┐ USB CDC虚拟 ┌─────────┐
│ 嵌入式 │←---高速+即插即用--→│ 电脑 │
└─────────┘ 可达12Mbps └─────────┐
优势:快、简单、标准、可供电
二、CDC在USB体系中的位置
USB设备类体系:
┌─────────────────────────────────┐
│ USB标准设备类 │
├─────────────────────────────────┤
│ 1️⃣ 大容量存储类(U盘、移动硬盘) │
│ 2️⃣ HID类(键盘、鼠标) │
│ 3️⃣ **CDC类(串口、网卡、调制解调器)**│ ← 今天的主角
│ 4️⃣ 音频类(耳机、麦克风) │
│ 5️⃣ 视频类(摄像头) │
└─────────────────────────────────┘
CDC子类(重点看串口):
• CDC ACM(Abstract Control Model):虚拟串口
• CDC ECM(Ethernet Control Model):虚拟网卡
• CDC NCM(Network Control Model):网络聚合
• CDC PCC(Phone Control Model):电话控制
三、CDC-ACM虚拟串口架构
CDC-ACM设备内部结构图
CDC-ACM设备内部端点配置:
┌─────────────────────────────────┐
│ CDC-ACM设备 │
│ │
│ 控制接口(端点0 - 必需) │ ← 管理命令
│ ├─ 类特定描述符 │
│ └─ 端点0(双向控制端点) │
│ │
│ 数据接口(端点1、2 - 数据传输) │
│ ├─ 端点1 IN(设备→主机) │ ← 发送数据
│ └─ 端点2 OUT(主机→设备) │ ← 接收数据
│ │
│ 可选的端点3 IN(通知端点) │ ← 状态变化通知
└─────────────────────────────────┘
四、CDC-ACM通信协议栈
CDC-ACM通信层次:
应用层(用户程序)
↓
串口API(COM1, COM2...)
↓
USB CDC驱动程序(usbser.sys / cdc_acm.ko)
↓
USB核心驱动
↓
USB主机控制器
↓
物理USB连接
五、CDC-ACM描述符详解(设备的"身份证")
描述符集合结构
标准USB描述符 + CDC类特定描述符:
1. 设备描述符:我是CDC设备
┌─────────────────────────┐
│ bDeviceClass: 0x02 │ ← 通信设备类
│ bDeviceSubClass: 0x00 │
│ bDeviceProtocol: 0x00 │
└─────────────────────────┘
2. 配置描述符:我有两个接口
┌─────────────────────────┐
│ 接口0:通信控制接口 │ ← 管理串口参数
│ 接口1:数据接口 │ ← 实际数据传输
└─────────────────────────┘
3. CDC类特定描述符(关键!):
┌─────────────────────────────────┐
│ 头部功能描述符 │
│ • bDescriptorType: 0x24 │
│ • bDescriptorSubtype: 0x00 │
├─────────────────────────────────┤
│ 呼叫管理功能描述符 │
│ • bmCapabilities: 0x00 │
│ • bDataInterface: 0x01 │ ← 指向数据接口
├─────────────────────────────────┤
│ ACM功能描述符 │
│ • bmCapabilities: 0x02 │ ← 支持线路控制
├─────────────────────────────────┤
│ 联合功能描述符 │
│ • bControlInterface: 0x00 │ ← 控制接口编号
│ • bSubordinateInterface: 0x01 │ ← 数据接口编号
└─────────────────────────────────┘
六、CDC-ACM控制命令(串口参数设置)
标准串口控制命令表
| 命令代码 | 功能 | 参数 | 对应传统串口操作 |
|---|---|---|---|
| 0x00 | SET_LINE_CODING | 波特率、数据位等 | 配置串口参数 |
| 0x01 | GET_LINE_CODING | 读取当前设置 | 读取串口配置 |
| 0x02 | SET_CONTROL_LINE_STATE | RTS/DTR控制 | 硬件流控 |
| 0x03 | SEND_BREAK | 发送Break信号 | 特殊通信信号 |
| 0x04-0x1F | 保留 | - | - |
| 0x20-0xFF | 类特定命令 | 厂商自定义 | 扩展功能 |
关键命令详解:SET_LINE_CODING
数据格式(7字节):
┌─────────┬─────────┬─────────┬─────────┬─────────┐
│ 波特率 │ 停止位 │ 校验位 │ 数据位 │ 特殊位 │
│ (4字节) │ (1字节) │ (1字节) │ (1字节) │ (1字节) │
├─────────┼─────────┼─────────┼─────────┼─────────┤
│ 115200 │ 1位 │ 无校验 │ 8位 │ 0 │
│ 0x0001C200│ 0x00 │ 0x00 │ 0x08 │ 0x00 │
└─────────┴─────────┴─────────┴─────────┴─────────┘
常用波特率对应值:
• 9600 → 0x00002580
• 115200 → 0x0001C200
• 921600 → 0x000E1000
• 1000000 → 0x000F4240
七、完整通信流程示例
场景:STM32通过CDC虚拟串口发送"Hello"
时间线分析:
┌─[设备插入]─────────────────────────────┐
│ 1. 主机枚举设备,识别为CDC-ACM │
│ 2. 加载usbser.sys驱动 │
│ 3. 创建COM3虚拟串口 │
├─[用户打开串口助手]─────────────────────┤
│ 4. 串口助手打开COM3,设置115200-8-N-1 │
│ 5. 发送SET_LINE_CODING命令 │
│ 6. 发送SET_CONTROL_LINE_STATE(1,1) │
├─[STM32发送数据]───────────────────────┤
│ 7. STM32准备数据 "Hello\r\n" │
│ 8. 通过端点1 IN发送数据包 │
│ PID=IN, 地址=xx, 端点=0x81 │
│ DATA=[0x48,0x65,0x6C,0x6C,0x6F,0x0D,0x0A]│
│ 9. 主机回复ACK │
├─[用户发送数据]────────────────────────┤
│ 10. 用户输入"AT\r" │
│ 11. 主机通过端点2 OUT发送 │
│ DATA=[0x41,0x54,0x0D] │
│ 12. STM32接收并回复ACK │
└───────────────────────────────────────┘
八、CDC-ACM数据端点工作机制
数据流示意图
双向全双工通信:
┌─────────────┐ ┌─────────────┐
│ 主机 │ │ 设备 │
│ (Windows/Linux)│ │(STM32/ESP32)│
├─────────────┤ ├─────────────┤
│ 串口应用 │ │ 应用程序 │
│ ↓ │ │ ↓ │
│ CDC驱动 │ │ CDC固件 │
│ ↓ │ │ ↓ │
│ USB核心 │←---USB总线--→│ USB控制器 │
└─────────────┘ └─────────────┘
端点使用:
• 端点0:控制传输(配置命令)
• 端点1 IN:设备→主机(TX)
• 端点2 OUT:主机→设备(RX)
• 端点3 IN:通知(可选)
数据包大小优化
USB全速模式(12Mbps):
• 最大包大小:64字节
• 实际有效数据:≤63字节(1字节状态)
• 建议:一次发送≤60字节,避免碎片
USB高速模式(480Mbps):
• 最大包大小:512字节
• 可批量传输大块数据
九、实际开发:嵌入式CDC实现
STM32 CDC固件示例(简化)
c
// 1. USB设备描述符配置
const uint8_t CDC_DeviceDescriptor[] = {
0x12, // 描述符长度
0x01, // 设备描述符类型
0x00, 0x02, // USB 2.0
0x02, // 设备类:通信设备
0x00, // 设备子类
0x00, // 设备协议
0x40, // 端点0最大包大小
// ... 厂商ID、产品ID等
};
// 2. CDC类特定描述符
const uint8_t CDC_ClassDescriptor[] = {
// 头部功能描述符
0x05, // 长度
0x24, // 描述符类型:CS_INTERFACE
0x00, // 头部功能描述符子类型
0x10, 0x01, // USB CDC规范1.10
// ACM功能描述符
0x04, // 长度
0x24, // CS_INTERFACE
0x02, // ACM功能描述符
0x02, // 能力:支持线路控制
// 联合功能描述符
0x05, // 长度
0x24, // CS_INTERFACE
0x06, // 联合功能描述符
0x00, // 控制接口编号
0x01, // 数据接口编号
};
// 3. 处理控制命令
void CDC_ControlRequest(uint8_t cmd) {
switch(cmd) {
case 0x00: // SET_LINE_CODING
// 读取波特率、数据位等参数
USBD_CDC_SetLineCoding(&line_coding);
break;
case 0x01: // GET_LINE_CODING
// 返回当前串口配置
USBD_CDC_GetLineCoding(&line_coding);
break;
case 0x02: // SET_CONTROL_LINE_STATE
// 设置RTS/DTR状态
USBD_CDC_SetControlLineState();
break;
}
}
// 4. 数据发送函数
void CDC_Transmit_DATA(uint8_t* data, uint16_t length) {
// 通过端点1 IN发送数据
USBD_CDC_TransmitPacket(CDC_IN_EP, data, length);
}
十、CDC与其他通信方式对比
| 特性 | CDC-ACM虚拟串口 | 传统UART串口 | USB HID | USB大容量存储 |
|---|---|---|---|---|
| 速度 | 12Mbps(全速) | 115.2Kbps | 1.5Mbps(低速) | 480Mbps(高速) |
| 驱动需求 | 系统自带 | 系统自带 | 系统自带 | 系统自带 |
| 开发复杂度 | 中等 | 简单 | 中等 | 复杂 |
| 实时性 | 好(有中断端点) | 最好 | 好 | 差 |
| 典型延迟 | 1-10ms | 可变 | 1-10ms | 100ms+ |
| 适用场景 | 调试、配置、通信 | 板间通信 | 人机交互 | 文件传输 |
十一、常见CDC设备实例
1. CP2102/CH340 USB转串口芯片
工作流程:
电脑 ←USB(CDC)→ CP2102 ←UART(串口)→ 单片机
↓ ↓
虚拟COM口 真实串口信号
特点:
• 成本低(几元钱)
• 驱动广泛
• 支持多种波特率
2. STM32内置USB CDC
STM32F4系列:
┌─────────────────┐
│ STM32F407 │
│ │
│ 应用程序 │
│ ↓ │
│ USB CDC固件库 │
│ ↓ │
│ USB OTG控制器 │←USB线→电脑
│ ↓ │
│ UART外设 │←可连接其他设备
└─────────────────┘
优势:节省外部芯片,成本更低
3. ESP32-S2/S3 USB CDC
ESP32-S3双芯片模式:
┌─────────────────┐
│ ESP32-S3 │
│ │
│ 主CPU:运行用户程序 │
│ ↓ │
│ USB CDC协议栈 │
│ ↓ │
│ USB外设 │←用于程序下载+调试
│ ↓ │
│ UART0 │←连接外部设备
└─────────────────┘
十二、CDC通信的性能优化技巧
优化建议表
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 数据丢失 | 缓冲区溢出 | 增加端点缓冲区大小 |
| 延迟大 | 轮询间隔长 | 使用中断传输代替批量 |
| 吞吐量低 | 小包发送 | 合并数据,使用最大包大小 |
| CPU占用高 | 频繁中断 | 使用DMA传输 |
| 兼容性问题 | 描述符不规范 | 严格按照CDC规范 |
高级特性:USB CDC双通道
双虚拟串口设备(STM32示例):
端点分配:
• 端点0:控制端点
• 端点1 IN:CDC1 TX
• 端点2 OUT:CDC1 RX
• 端点3 IN:通知端点
• 端点4 IN:CDC2 TX
• 端点5 OUT:CDC2 RX
应用场景:
1. 调试日志输出(CDC1)
2. AT命令通信(CDC2)
3. 互不干扰,独立波特率
十三、调试与故障排查
常见问题及解决
| 现象 | 可能原因 | 排查步骤 |
|---|---|---|
| 设备无法识别 | 描述符错误 | 使用USB分析仪查看枚举过程 |
| 串口不显示 | 驱动问题 | 检查设备管理器,重新安装驱动 |
| 数据乱码 | 波特率不匹配 | 检查SET_LINE_CODING命令 |
| 发送数据丢失 | 缓冲区满 | 检查NAK响应,调整发送间隔 |
| 只能单向通信 | 端点配置错误 | 检查IN/OUT端点配置 |
USB分析仪看到的CDC通信
典型CDC通信分析:
[时间] [方向] [PID] [内容]
00:00.001 主机→设备 SETUP GET_DESCRIPTOR(设备)
00:00.002 设备→主机 DATA0 设备描述符
00:00.003 主机→设备 ACK 确认
00:00.010 主机→设备 SETUP SET_CONFIGURATION(1)
00:00.011 设备→主机 ACK 确认
00:00.100 主机→设备 SETUP SET_LINE_CODING
00:00.101 主机→设备 OUT 波特率115200数据
00:00.102 设备→主机 ACK 确认
00:00.200 设备→主机 IN 请求数据
00:00.201 设备→主机 DATA0 "Hello World"
00:00.202 主机→设备 ACK 确认
十四、CDC协议的未来发展
新特性与趋势
- 高速CDC:USB 3.0+支持,速度达5Gbps
- 多功能复合设备:CDC+大容量存储+HID集成
- 无线CDC:通过蓝牙或Wi-Fi模拟CDC
- WebUSB CDC:浏览器直接访问USB CDC设备
- 安全增强:加密通信,防窃听
十五、实用项目示例:DIY USB-CDC数据记录仪
硬件组成
┌─────────────┐ USB CDC ┌─────────────┐
│ 传感器 │←---数据---→│ STM32F103 │
│ (温湿度/DHT11)│ │ (USB CDC设备)│
└─────────────┘ └──────┬──────┘
│ USB线
┌───────┴───────┐
│ 电脑 │
│ 串口助手/Python│
└───────────────┘
固件关键代码
c
// 数据采集并发送
void DataLogger_Task(void) {
float temperature, humidity;
// 1. 读取传感器
DHT11_Read(&temperature, &humidity);
// 2. 格式化数据
char buffer[64];
sprintf(buffer, "Temp:%.1fC, Hum:%.1f%%\r\n",
temperature, humidity);
// 3. 通过CDC发送
CDC_Transmit_DATA((uint8_t*)buffer, strlen(buffer));
// 4. 延时
HAL_Delay(1000); // 每秒发送一次
}
总结:CDC的核心价值
CDC-ACM成功的关键 在于它在USB的现代化优势 和串口的简单易用之间找到了完美平衡:
- 对用户透明:看起来、用起来都和传统串口一样
- 性能大幅提升:速度从Kbps提升到Mbps级别
- 即插即用:无需额外电源,自动安装驱动
- 标准化:所有操作系统都支持
- 灵活性:可软件配置波特率等参数
CDC本质上是一个翻译官:
- 对电脑说:"我是标准串口设备"
- 对USB硬件说:"请以高速USB协议传输数据"
- 在中间进行协议转换
这使得无数基于串口的传统设备(工业控制器、传感器、老式设备)能够平滑迁移到USB时代,而无需改变上位机软件。正是这种"承上启下"的设计,让CDC成为嵌入式开发中最重要、最常用的USB设备类之一。
下次使用Arduino、STM32或ESP32的USB功能时,你会知道,这简单的"串口"背后,是一套完整、精巧的USB CDC协议栈在工作!