




USB 是 Universal Serial Bus 的缩写,中文通常叫通用串行总线。它是电脑、手机、工控机、单片机开发板和各种外设之间最常见的连接方式之一。
在嵌入式开发中,USB 常用于:
很多初学者第一次接触 USB 时会觉得它很复杂,因为 USB 不像普通 UART 那样“发字节、收字节”就结束了。USB 设备接入电脑后,电脑会先询问设备是什么、支持什么功能、需要多少电流、有哪些接口、有哪些端点,然后才开始真正传输数据。
这个“先自我介绍,再通信”的过程,就是 USB 学习的核心。
USB 通信中最重要的两个角色是:

USB 主机是整个 USB 总线的管理者。它负责供电、检测设备插入、发起通信、读取描述符、分配地址、配置设备、调度数据传输。
常见 USB 主机包括:
USB 通信中,绝大多数数据传输都是由主机主动发起的。即使设备想发送数据,也通常需要等主机来询问或调度。
USB 设备是被主机管理的外设。它连接到主机后,需要按照 USB 协议回答主机的问题。
常见 USB 设备包括:
STM32F103C8T6 使用 CherryUSB 做 CDC 虚拟串口时,STM32 就是 USB Device,电脑就是 USB Host。
很多人会把“端口”理解成电脑上的 USB 插孔,这在日常语言里没有问题。但在 USB 协议学习中,需要区分两种概念:

物理端口就是看得见摸得着的 USB 接口,例如电脑上的 USB-A、USB-C 插口,或者开发板上的 Micro USB、Type-C 接口。
它负责电气连接,常见信号包括:
对于 STM32F103C8T6 的 USB FS 设备:
USB 全速设备通常通过 D+ 上拉电阻告诉主机:“有一个全速 USB 设备接入了”。
USB 协议里更常说的是 Endpoint,中文叫端点。端点不是物理插口,而是设备内部用于数据传输的逻辑通道。
可以把 USB 设备想象成一栋办公楼:
电脑并不是随便往设备里写数据,而是往某个端点发送数据,或者从某个端点读取数据。

USB 有不同速度等级,常见如下:
| 速度等级 | 英文 | 速率 | 常见应用 |
|---|---|---|---|
| 低速 | Low Speed | 1.5 Mbps | 鼠标、键盘 |
| 全速 | Full Speed | 12 Mbps | CDC、HID、普通 MCU USB |
| 高速 | High Speed | 480 Mbps | U 盘、摄像头、网卡 |
| 超高速 | SuperSpeed | 5 Gbps 及以上 | 高速存储、扩展坞 |
STM32F103C8T6 内置的是 USB Full Speed Device 控制器,速率是 12 Mbps。它不能直接做 USB High Speed。
USB 全速设备必须有准确的 48 MHz USB 时钟。对于 STM32F103,常见配置是:
如果 USB 时钟不准,电脑可能出现无法识别、设备描述符请求失败、Code 43 等问题。
USB 设备插入电脑后,不能马上开始业务通信。主机会先执行一个过程,叫枚举 Enumeration。

枚举可以理解为主机对设备进行“身份调查”和“建档登记”。
典型枚举流程如下:
0。如果某一步失败,Windows 可能提示:
其中“请求 USB 设备描述符失败”通常说明设备在枚举最早期就没有正确返回 Device Descriptor。
描述符 Descriptor 是 USB 设备给主机看的“说明书”。主机通过描述符了解设备是什么、有哪些功能、如何通信。

USB 设备必须正确提供描述符,否则主机不知道该加载什么驱动,也不知道如何访问设备。
常见描述符包括:
设备描述符说明整个 USB 设备的基本身份。
它包含的信息通常有:
例如 CDC 虚拟串口设备会通过设备描述符告诉电脑:“我是一个 USB 设备,我的 VID/PID 是多少,我有一个配置。”
如果设备描述符返回失败,Windows 就可能报“请求 USB 设备描述符失败”。
一个 USB 设备可以有一个或多个配置。配置描述符说明某个配置下设备需要多少电流、包含多少接口。
配置描述符里常见字段包括:
普通 MCU USB 设备通常只有一个配置。
接口 Interface 表示设备的一个功能单元。
例如:
接口描述符告诉主机:
主机通常根据接口类别加载驱动。例如看到 HID 类,就加载 HID 驱动;看到 CDC ACM 类,就加载虚拟串口相关驱动。
端点描述符说明一个端点的传输方向、传输类型、最大包长和轮询间隔。

端点描述符常见字段包括:
端点地址中最高位表示方向:
0x01:端点 1 OUT,主机到设备0x81:端点 1 IN,设备到主机0x02:端点 2 OUT,主机到设备0x83:端点 3 IN,设备到主机注意:IN 和 OUT 是以主机为视角定义的。
这点对初学者很容易反。比如 0x81 是 IN 端点,意思是设备通过这个端点把数据发给主机。
字符串描述符用于显示人类可读的信息,例如:
例如在 Windows 设备管理器里看到的设备名称,可能就来自产品字符串。
在嵌入式 USB 协议栈中,字符串描述符通常需要以 UTF-16LE 格式返回。很多协议栈允许开发者写 ASCII 字符串,再自动转换成 USB 字符串描述符。
如果直接写 UTF-8 中文,而协议栈只按单字节 ASCII 转换,就可能显示乱码。
端点 0 是 USB 设备必须具备的默认控制端点。
它非常重要,因为枚举过程基本都依赖端点 0 完成。
端点 0 用于:
端点 0 是双向控制端点,既能 IN,也能 OUT。
如果端点 0 不能正常工作,USB 设备通常无法枚举成功。
USB 有四种基本传输类型:
控制传输主要用于设备管理和枚举,端点 0 默认使用控制传输。
典型用途:
控制传输可靠性高,有明确的请求、数据和状态阶段。
批量传输适合大量可靠数据传输,但不保证固定延时。
典型用途:
CDC ACM 虚拟串口的数据端点通常使用 Bulk 传输。
中断传输适合小数据量、低延迟、周期性查询的场景。
典型用途:
这里的“中断”不是 MCU 中断的意思,而是 USB 协议中的一种传输调度方式。
同步传输适合实时数据流,强调固定带宽和实时性,但错误重传能力较弱。
典型用途:
例如 USB 麦克风和摄像头通常会用到同步传输。
USB Class 是 USB 官方定义的一类标准设备功能。主机操作系统可以根据 Class 加载通用驱动。
常见 USB Class:
| 类名 | 作用 | 常见设备 |
|---|---|---|
| CDC | 通信设备类 | 虚拟串口、调制解调器 |
| HID | 人机接口设备类 | 键盘、鼠标、自定义 HID |
| MSC | 大容量存储类 | U 盘、读卡器 |
| DFU | 固件升级类 | USB 升级设备 |
| Audio | 音频类 | USB 声卡、麦克风 |
| Video | 视频类 | USB 摄像头 |
| RNDIS/ECM/NCM | USB 网络类 | USB 网卡 |
使用标准 Class 的好处是:电脑端通常已有驱动,开发者不需要自己写 Windows 驱动。
CDC ACM 虚拟串口是 MCU 项目最常见的 USB 应用。

一个 CDC ACM 设备通常包含:
CDC ACM 通常有两个接口:
通信控制接口用于处理串口参数,例如波特率、DTR、RTS 等。
数据接口用于真正收发串口数据。
CDC ACM 常见端点:
例如你的 STM32F103 CherryUSB 工程中:
0x83:CDC 通知 IN 端点0x02:CDC 数据 OUT 端点0x81:CDC 数据 IN 端点当电脑串口助手发送数据时,数据会通过 OUT 端点到达设备。
当 MCU 回传数据时,数据会通过 IN 端点发送给电脑。
USB 里的 IN 和 OUT 都是站在主机角度看的。
这是 USB 初学者最容易混淆的地方。
| 方向 | 主机视角 | 设备视角 |
|---|---|---|
| IN | 主机读取数据 | 设备发送数据 |
| OUT | 主机写出数据 | 设备接收数据 |
所以:
CDC_IN_EP 0x81 是设备发给电脑的数据通道CDC_OUT_EP 0x02 是电脑发给设备的数据通道USB 主机会向设备发送请求 Request。请求通过端点 0 控制传输完成。
请求大致分为:
标准请求是所有 USB 设备都需要支持的基础请求。
常见标准请求:
枚举过程主要依赖标准请求。
类请求和具体 USB Class 有关。
例如 CDC ACM 中常见类请求:
虽然 CDC 是虚拟串口,但 USB 传输本身并不真的依赖 UART 波特率。波特率更多是为了兼容传统串口软件的概念。
厂商自定义请求由开发者自己定义,适合实现特殊控制功能。
例如:
自定义请求灵活,但主机端也需要自己写对应程序。
VID 是 Vendor ID,厂商 ID。
PID 是 Product ID,产品 ID。
电脑通过 VID/PID 识别不同厂商和不同产品。
正式量产产品应使用合法申请的 VID/PID。学习、测试和内部开发阶段可以使用示例 VID/PID,但不要用于商业量产。
如果多个不同设备使用相同 VID/PID 和相同序列号,Windows 可能会把它们当作同一个设备,导致驱动、COM 号或缓存状态混乱。
USB 接口通常提供 VBUS 5 V。设备可以从 USB 取电,也可以自供电。
描述符里会声明设备供电方式:
还会声明最大电流。例如配置描述符中写 100 mA,主机就认为设备最大从 USB 取 100 mA。
全速 USB 设备通过 D+ 上拉告诉主机设备接入。低速设备通过 D- 上拉告诉主机设备接入。
STM32F103 做 USB 全速设备时,关键硬件点是:
有些 STM32F103 开发板的 D+ 上拉电阻是固定接到 3.3 V 的。这样 MCU 软件复位时,电脑并不会看到 USB 设备真正断开。
结果是:
解决办法是软件模拟断开。
常见做法:
这个过程相当于让 Windows 感知一次“拔出再插入”。
USB 协议栈是帮开发者处理 USB 协议细节的软件模块。
以 CherryUSB 为例,它通常负责:
开发者通常只需要关心:
底层寄存器、端点状态、枚举细节由协议栈处理。

USB 全速设备需要 48 MHz。时钟错误会导致枚举失败。
PA11 是 D-,PA12 是 D+。接反后主机无法正常识别。
没有上拉,主机检测不到设备。固定上拉则可能导致复位后不能重新枚举。
配置描述符总长度、接口数量、端点数量不匹配,可能导致枚举失败或驱动加载异常。
代码里使用的端点地址必须和描述符里的端点地址一致。
USB 中断没有调用协议栈处理函数,设备无法响应主机请求。
例如同时调用 STM32 HAL PCD 和 CherryUSB,会导致 USB 寄存器状态冲突。
ASCII 通常安全。中文需要确保协议栈正确转换为 UTF-16LE。
对于 STM32 FSDEV,PMA 是 USB 专用包缓冲区。PMA 访问方式、端点缓冲区分配错误,会导致设备描述符或数据传输异常。
建议初学者按以下顺序学习:
对于 STM32F103 和 CherryUSB,最推荐从 CDC ACM 虚拟串口开始,因为它能同时覆盖:
USB 不是简单的串口线,而是一套由主机统一管理的分层通信协议。
设备接入后,先通过描述符告诉主机“我是谁、我有什么功能、你该怎么和我通信”,主机完成枚举和驱动加载后,双方才通过端点进行真正的数据传输。
如果能理解“主机、设备、枚举、描述符、接口、端点、传输类型”这几个核心概念,就已经掌握了 USB 协议入门最重要的骨架。

此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。