USB 协议①
与 RS-232 这类未定义数据发送格式的串行接口不同,USB 由几层协议共通组成。这听起来有些复杂,不过无需担心,一旦明白了内中种种,你会发现自己只需关注上层协议。实际上,大部分情况下,下层协议由 USB 控制器 IC 处理,对终端设计者(end designer)来说这部分相当于黑盒。
每个 USB 数据包都包含:
- 令牌包(Token Packet)
- 可选的数据包(Optional Data Packet,内含数据负载)
- 状态包(Status Packet),用于提供回应(Acknowledge)或错误检测
正如我们已经知道的,USB 是以主机为中心的总线。主机启动所有事务。主机生成的第一个数据包(也称为令牌),令牌包描述了后续是什么格式的数据、数据是读取还是写入、设备的地址信息、指定的端点信息。下一个数据包通常是负载数据,后续接一个握手数据包(handshaking packet),握手数据包用来报告数据或令牌是否成功接收、端点是否停止、端点是否无法接受数据。
USB 数据包字段(USB Packet Fields)
USB 总线上的数据是 LSBit 优先。USB 数据包包含如下字段:
- Sync
所有数据包都必须以同步字段开头。对于低速和全速,Sync 字段为 8-bit,对于高速则为 32-bit,用于将接收器的时钟与发送器的时钟同步。Sync 字段的最后两位指示PID字段的起始位置。
- PID
Group | PID Value | Packet Identifier |
Token | 0001 | OUT Token |
1001 | IN Token | |
0101 | SOF Token | |
1101 | SETUP Token | |
Data | 0011 | DATA0 |
1011 | DATA1 | |
0111 | DATA2 | |
1111 | MDATA | |
Handshake | 0010 | ACK Handshake |
1010 | NAK Handshake | |
1110 | STALL Handshake | |
0110 | NYET (No Response Yet) | |
Special | 1100 | PREamble |
1100 | ERR | |
1000 | Split | |
0100 | Ping |

- ADDR
- ENDP
- CRC
- EOP
USB 数据包类型(USB Packet Types)
USB 有四种不同的数据包类型。令牌包指示要遵循的事务类型,数据包包含数据负载,握手包用于确认数据或报告错误,帧开始包指示新帧的开始。
- 令牌包
(1)In - 主机从 USB 设备读取信息
(2)Out - 主机向 USB 设备发送信息
(3)Setup - 开始控制传输
令牌数据包格式:
Sync | PID | ADDR | ENDP | CRC5 | EOP |
- 数据包
(1)Data0
(2)Data1
高速模式定义了另外两种数据 PID,DATA2 and MDATA。
数据包格式:
Sync | PID | Data | CRC16 | EOP |
(1)低速设备最大数据负载 8 字节
(2)全速设备最大数据负载 1023字节
(3)高速设备最大数据负载 1024字节
(4)数据必须以多字节方式发送
- 握手包
(2)NAK - 通知对方设备暂时无法发送/接收数据,也用于(中断传输下)告知主机目前设备没有数据需要发生
(3)STALL - 设备处于需要主机干预的状态。
握手包格式:
Sync | PID | EOP |
- SOF(Start of Frame)包
Sync | PID | Frame Number | CRC5 | EOP |
USB 功能(USB Functions)
当我们想到 USB 设备时,我们想到的是 USB 外围设备。但是 USB 设备(USB device)可能是主机或外设上使用的 USB 收发器,也可能是一个 USB 集线器或主机控制器 IC,还可能是一个 USB 外设设备(USB peripheral device)。所以标准定义了一个“USB 功能”的术语,用于描述具有的某一项能力(capability)或功能(function)的 USB 设备,比如打印机,Zip驱动器,扫描仪,调制解调器或其他外围设备。
USB 功能图示:

大多数功能都有一系列缓冲区,缓冲区长度通常为 8 个字节。每个缓冲区隶属于一个端点——EP0 IN,EP0 OUT等等。举例来说,主机发送一个设备描述符请求。功能硬件(function hardware)将读取设置数据包(setup packet),解析后判断该数据包是否是发给自己的,如果是,则将后续数据包的有效负载复制到合适的端点缓冲区中——端点由设置令牌(setup token)的端点字段标明。然后功能硬件回复一个握手数据包,以确认该字节的接收,并在微控制器内为合适的端点产生一个中断,通知端点设备已经收到数据包。通常,这都是在硬件中完成的。
至此,软件获得中断事件,然后应读取端点缓冲区的内容并解析设备描述符请求。
端点(Endpoints)
端点可以描述为数据的发送端(sources)或接收端(sinks)。由于总线是以主机为中心的,因此端点出现在 USB 功能的通信通道末端。例如,在软件层,您的设备驱动程序可以将数据包发送到设备 EP1。随着数据从主机流出,它将最终进入 EP1 OUT 缓冲区。然后,您的固件将在空闲的时候读取此数据。如果要返回数据,功能(function)不能直接把数据写入总线,因为总线是由主机控制的。它只能将数据写入位于缓冲区的 EP1 IN,由主机发起 IN 数据包以请求数据。端点也可以视为功能设备的硬件与功能设备上运行的固件之间的接口。
所有设备必须支持 “0” 端点。“0” 端点用于接收枚举期间、设备在总线上运行时的整个时间内的所有设备的控制和状态请求。
总结:端点是设备与主机之间进行数据传输的逻辑接口,除配置使用的端点 0(控制端点,一般一个设备只有一个控制端点)为双向端口外,其它均为单向。端点描述符描述了数据的传输类型、传输方向、数据包大小和端点号(也可称为端点地址)等。
管道(Pipes)
设备在一系列的端点上完成数据的发送和接收,客户端软件则通过管道传输数据。管道是主机和端点之间的逻辑连接。管道自身也关联了一组参数,例如分配给管道的带宽,使用的传输类型(控制,批量,同步或中断),数据流的方向,最大的数据包/缓冲区大小。默认管道是双向管道,由具有控制传输类型的“0”输入端点和“0”输出端点组成.
USB定义了两种类型的管道:
- 流管道(Stream Pipes ),它没有定义 USB 数据格式,也就是说,您可以用它发送任何类型的数据,并且可以从另一端解析数据。数据按顺序发送,并具有预先定义的方向,要么流入,要么流出。流管道将支持批量、同步、中断传输类型。流管道可以由主机或设备控制。
- 消息管道(Message Pipes)具有定义的 USB 数据格式。这类管道由主机控制,通过主机发送请求进行初始化。数据按照指定的方向传输,传输方向定义在主机发送的请求中。因此,消息管道允许数据双向传输,但仅支持控制传输。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!