USB传输、事务、包是从不同层次上去说明一次数据交互的三个概念。
举个例子可能更好些,"某领导和一个早起的程序员进行了一次交流,说了5件事"。
其实这里的"这次交流"就相当于USB的一次传输,"说了5件事"就相当于这次传输过程中的5个事务,当然每件事肯定有若干句对话,就相当于每个事务里面的各种包。
下面三个概念难理解一点
配置(Configuration)
对设备的配置,这种配置作为数据结构可以存在多个,主机可以控制设备选择哪个具体的配置,但是设备当前只能选择一个配置。我们来想想,一个领导招聘了一个小弟,可以让这个小弟去写代码(配置1),或者让这个小弟去画电路图(配置2)等等,我们就举两个例子说明问题。由上面我们可以知道,USB设备可能有一个或者多个配置,我们常见到的USB设备一般都只有一个配置。
就像一个员工的"工作模式 "。比如,一个 USB 设备可以有"正常工作模式"和"低功耗模式"。我们通常只关心"正常工作模式",也就是配置1。
接口(Interface)
好了,领导让这个小弟去写代码,可以只写C++软件,当然为了提高效率,有时候既要写C++软件,也要写C#软件,还得写Python软件。其实每个配置信息里面包含了接口的数量,一个接口就是一个功能,一个配置可以有多个接口(一个小弟可以会多种语言),也就是一个USB设备通过接口可以扩展多个功能。
对于 CDC 虚拟串口 这个具体的例子来说,它必须 同时提供**"通信管理"和"数据收发"**这两种功能角色(两个接口),才能被操作系统正确地识别和使用。
通信管理:就是约定波特率,数据位之类的,USB通信其实用不到,这是在物理接口上面用的,但是为了兼容老设备,还是会使用,电脑向stm32发送波特率为9600,但是STM32收到这个数据不处理而已
端点(Endpoint)
一个接口完成一种功能,每种接口(功能)配有1个或者多个端点。 端点是主机与设备之间通讯数据的接收或来源,要实现通讯功能,接口必须有端点的配备才可以,主机要给设备发送数据,端点就是数据的接收器,主机要给设备要数据,端点就是数据的发送器,然后通过多个端点配合接收和发送各种数据实现某个接口的某种功能。所以大家注意了,端点的依附于接口上的。其实一个端点就是一段存放接收和发送数据的缓冲区。这段缓冲区有一定的属性,在USB设备中,我们用端点描述符来描述这段缓冲区的属性。后期看代码。

- 四种传输类型 :
- 控制传输 (Control) : 用于设备枚举和管理。就像"注册、认证、发身份证"的过程,可靠但慢。
- 中断传输 (Interrupt) : 用于传输小、快、固定 的数据。比如鼠标、键盘的坐标和按键信息。它不是 CPU 中断,而是 Host 会"定期轮询"设备。
- 批量传输 (Bulk) : 用于传输大块、可靠但对实时性要求不高的数据。比如 U 盘读写、打印机打印。它会利用总线上所有可用的带宽。
- 同步传输 (Isochronous) : 用于传输大块、实时性要求极高但允许少量错误的数据。比如 USB 摄像头、麦克风的音视频流。出错了就直接丢掉,保证流畅性。
事务 通常由两三个包组成:令牌包 ,数据包 和握手包。为什么说是通常呢?因为有一个特例同步传输的事务中没有握手包,只有令牌包和数据包。事务就是完成一件事的意思,完成一个事务需要发送或者接受几包数据。
下面是USB传输的最小单位--------USB包

1. SOP (Start of Packet) - 帧头
2. SYNC (Synchronization) - "同步校准信号"
- 作用 : 帮助接收方的"时钟"和发送方的"时钟"对齐节奏。
- 物理实现 : 它是一串固定的
0和1交替的序列(比如01010100)。接收端可以通过这串信号,精确地调整自己的时钟,确保后续能以正确的节拍来"采样"和读取数据。 - 大白话: 就像乐队演出前,指挥会先敲几下指挥棒,让所有乐手都跟上同一个节拍。
3. Packet Content - 【【【 核心 】】】"集装箱"里的"货物"和"运单"
这是"集装箱"里真正有意义的部分,它又被分成了几个标准格子:
PID(Packet Identifier) - "运单类型"- 作用 : 这是一个 4 位的标识符(为了可靠性,会发送两次,共 8 位),它定义了这个"集装箱"的类型和用途。
- 大白话: 就像快递单上必须勾选的"文件"、"包裹"、"生鲜"、"加急"等选项。
- 例子 :
PID = TOKEN: 表示这是一个"令牌包 ",是 Host(老板)发出的指令 ,比如"7号员工,我要**接收(IN)你的数据"或"7号员工,你准备接收(OUT)**我的数据"。PID = DATA: 表示这是一个"数据包 ",里面装着真正的货物(比如 "Hello World" 的 ASCII 码)。PID = HANDSHAKE: 表示这是一个"握手包 ",是接收方给发送方的回执 ,比如ACK("收到了,没问题") 或NAK("我现在忙,请稍后重发")。
- 重要性: PID 是理解一次 USB 事务(Transaction)流程的关键。
地址 (Address)+端点 (Endpoint):- 作用 : "收件人地址"。
- 大白话 :
地址: "这箱货是送给7号员工的。"端点: "具体送到7号员工的3号收件窗口。"
- 注意 : 只有令牌包 (TOKEN) 里才包含地址和端点信息,因为指令必须是明确的。
帧号 (Frame Number):- 作用 : "时间戳" 。只存在于一种特殊的、由 Host 定时广播的
SOF(Start of Frame) 包中。 - 大白话 : Host 每隔 1 毫秒(对于 Full-Speed)就会在高速公路上喊一嗓子:"现在是第 XXX 毫秒!"
- 用途: 为同步传输(比如音频、视频)提供一个统一的时间基准。
- 作用 : "时间戳" 。只存在于一种特殊的、由 Host 定时广播的
数据 (Data):- 只有数据包 (DATA) 里才包含这个字段。
4. EOP (End of Packet) - 帧尾
描述符
描述符 其实就是C语言里面的结构体或者数组,数组包含的信息说明当前的设备具有哪些特征。USB描述符有设备描述符 、配置描述符 、接口描述符 、端点描述符 、字符串描述符 ,HID设备有HID描述符 、报告描述符 和物理描述符。
下面以小u招聘为例来讲解各种描述符的概念
当"新员工小U"(USB 设备)来"公司"(电脑 Host)报到时,他随身携带了一个厚厚的"简历档案袋 "。"HR 经理"(Host)在枚举过程中,会依次向他索要并阅读这些档案。
A. 标准描述符 (所有 USB 设备通用)
这部分是"通用简历模板",所有来应聘的员工都必须填写。
- 设备描述符 (Device Descriptor)
- 档案类型 : "个人基本信息表" (第一页,最重要的)
- 内容 :
idVendor&idProduct: "我的身份证号是 Vxxxx Pxxxx (厂商ID, 产品ID)。"bDeviceClass/SubClass/Protocol: "我的职业大类是'通信设备'(CDC) / '存储设备'(U盘) / '人机交互设备'(HID)。"iManufacturer,iProduct,iSerialNumber: "我的'制造商名称'、'产品名称'、'序列号'分别对应'字符串档案'里的第1、2、3号档案。"bNumConfigurations: "我总共有 1 种工作模式(配置)。"
- 配置描述符 (Configuration Descriptor)
- 档案类型 : "工作模式与能力清单"
- 内容 :
bNumInterfaces: "在我的'正常工作模式'下,我能同时扮演 2 个不同的'角色'(接口)。"bmAttributes: "我的供电方式是'总线供电 ',并且支持'远程唤醒'。"MaxPower: "我最多需要从你这里获取 100mA 的电流。"
- 重要性 : 这是一个"打包"描述符 。它的后面,会紧跟着它所包含的所有"接口描述符"和"端点描述符"。
- 接口描述符 (Interface Descriptor)
- 档案类型 : "岗位职责说明书"
- 内容 :
bInterfaceNumber: "这是我的 0 号岗位。"bInterfaceClass/SubClass/Protocol: "这个岗位的具体职能是'通信接口' / '数据接口' / 'HID 接口'。"bNumEndpoints: "要完成这个岗位的工作,我需要配备 2 个'数据收发窗口'(端点)。"iInterface: "这个岗位的文字说明,在'字符串档案'的第 4 号。"
- 端点描述符 (Endpoint Descriptor)
- 档案类型 : "数据收发窗口规格单"
- 内容 :
bEndpointAddress: "这个窗口的编号是 1 号 ,方向是 IN (发给你)。"bmAttributes: "这个窗口的传输类型是'批量传输 (Bulk)'。"wMaxPacketSize: "这个窗口的'篮子'一次最多能装 64 字节。"bInterval: "(如果是中断传输)请每隔 10ms 来我这里取一次数据。"
- 字符串描述符 (String Descriptor)
- 档案类型 : "多语言名词解释附录"
- 内容 :
- 这是一个索引-字符串的键值对列表。
索引 1: 对应字符串 "STMicroelectronics" (Unicode 编码)索引 2: 对应字符串 "STM32 Virtual COM Port" (Unicode 编码)
- 作用 : 当 HR 看到"设备描述符"里写着
iManufacturer = 1,他就知道应该再来索要"字符串描述符"的第 1 号档案,来获取厂商的具体名字。
B. HID 类特定描述符 (只有 HID 设备,如鼠标、键盘、手柄才有)
这部分是"特殊岗位(人机交互)的补充材料"。
- HID 描述符 (HID Descriptor)
- 档案类型 : "HID 岗位补充说明"
- 位置 : 它紧跟在 HID 接口描述符的后面。
- 内容 :
bNumDescriptors: "关于我这个 HID 岗位,我还有 1 份更详细的说明材料(报告描述符)。"bDescriptorType: "那份材料的类型是'报告描述符'。"wDescriptorLength: "那份材料总共有 XX 字节长。"
- 作用 : 告诉 HR:"别急,关于我怎么上报数据,还有一份最重要的'数据格式说明书',你得再问我要一次。"
- 报告描述符 (Report Descriptor) - 【HID 的灵魂!】
- 档案类型 : "数据上报格式说明书"
- 内容 : 这不是一个简单的表格,而是一段用**"HID 专用语法"**写成的、极其灵活的"脚本 "。它定义了设备发送给电脑的数据包里,每一个 bit 代表什么意思。
- 例子 (一个简单的鼠标) :
- "第 1 个字节的第 0 位,代表'左键'是否按下。"
- "第 1 个字节的第 1 位,代表'右键'是否按下。"
- "第 2 个字节,代表'X 轴的相对位移',范围是 -127 到 +127。"
- "第 3 个字节,代表'Y 轴的相对位移'。"
- 作用 : 它是主机(电脑)用来解析 HID 设备数据包的"唯一秘钥" 。没有它,主机收到一串
01001010,完全不知道是什么意思。有了它,主机就知道"哦,这是左键按下了,并且鼠标向右移动了一点"。
- 物理描述符 (Physical Descriptor)
- 档案类型 : "人体工学参数(可选)"
- 内容: 描述身体的哪个部位在使用这个设备(比如"右手"、"左手食指")。
- 作用: 比较少用,主要用于一些特殊的力反馈或人体工程学应用。
总结
这套"档案系统"的设计非常精妙:
- 层层嵌套: 配置描述符"包含"接口描述符,接口描述符"包含"端点描述符。
- 按需索取 : 主机(HR)通过一系列标准的
GET_DESCRIPTOR请求,像剥洋葱一样,一层一层地获取它需要的信息。 - 通用与专用结合: 所有设备都有标准描述符,而像 HID 这样的特殊设备,则在标准描述符的基础上,附加了自己专用的描述符,来定义其独特的行为。
理解了这套"档案"体系,你就理解了 USB 设备是如何在几百毫秒内,向一个完全不认识它的电脑,清晰地"自我介绍"并被正确识别的。