USB协议基础详解:从系统架构到端点通信 📅 发布时间:2026/9/8 13:26:28 👁 浏览次数: 做硬件调试的兄弟应该都有过这样的经历拿一根 USB 转串口线连上开发板打开串口助手看日志一切岁月静好。可一旦遇到 USB 设备枚举失败、摄像头在别的机器上频繁掉线、或者自己画的板子 USB 识别不稳定这类问题光靠“插上能不能用”的经验完全不够用。这个时候USB 协议本身的知识就成了绕不开的坎。这篇文章想用尽量直白的方式把 USB通用串行总线这套协议从历史背景、系统架构到端点通信完整串一遍。注意这是“上篇”聚焦基础框架协议是怎么来的、系统里各个角色怎么分工、数据从主机到设备走的是怎样一条路、端点通信又是怎么运作的。适合刚接触 USB 开发的嵌入式工程师、驱动开发者也适合平时只停留在应用层、偶尔被 USB 问题卡住的朋友。枚举的具体时序、描述符抓包解读、批量传输和中断传输的代码层面处理我放到“下篇”单独展开。1. 从一堆接口的混战说起USB 是怎么被逼出来的1.1 九十年代的外设接口乱象谈 USB 历史得先把时间拨回上世纪九十年代中期看看当时一台普通 PC 的后背板是什么光景。串口RS-232通常叫 COM 口、并口LPT打印机专用、PS/2 键鼠口、MIDI 游戏杆接口、SCSI 接口五花八门。每一种外设几乎都有专属接口打印机走并口鼠标键盘走 PS/2调制解调器走串口扫描仪走 SCSI。你要是想在外置光驱和电脑之间传数据还得先研究主板上剩了哪种接口可用。这种局面带来的麻烦是非常现实的。接口标准不统一外设厂商得针对不同接口做不同型号的硬件带宽也低得可怜串口标准波特率一般到 115200bps 就到头了并口理论速率 1MB/s 上下传一个稍大点的文件能等到怀疑人生。最让人崩溃的是不能热插拔串口并口设备基本都要先关机再插拔真要在带电状态下去插运气差一点就直接把主板上的接口控制芯片烧掉。所以 Intel、Microsoft、Compaq、NEC、IBM 这几家凑到一起决心搞一个真正意义上的“通用”串行总线。1994 年 USB 规范开始起草1996 年 USB 1.0 正式发布通用串行总线Universal Serial Bus这个名号正式登上历史舞台。注意里面这个“Universal”就是冲着统一天下接口去的。1.2 从 USB 1.0 到 USB4一部带宽翻倍和命名混乱史USB 1.0 发布之后真正开始大规模普及是 1998 年的 USB 1.1 修正版。这个阶段的速度分两档Low Speed1.5Mbps和 Full Speed12Mbps。低速模式专为鼠标键盘这类对带宽要求极低的外设设计好处是线缆成本低、实现简单。2000 年 USB 2.0 发布引入了 High Speed480Mbps这是很多人最熟悉的版本。USB 2.0 向下兼容 1.1但它的电气信号标准和 1.1 时代完全拉开了差距后来大量的兼容性疑难杂症都埋在这个过渡里。再往后就是大家更熟悉的命名大战了。USB 3.0 在 2008 年发布速度跳到 5Gbps后来被 USB-IF 改名叫 USB 3.1 Gen 1到了 USB 3.2 时代又变成 USB 3.2 Gen 1×1。USB 3.1 的 10Gbps 版本叫过 USB 3.1 Gen 2后来也改叫 USB 3.2 Gen 2×1。USB 3.2 时代还冒出个 20Gbps 的 USB 3.2 Gen 2×2。最后 USB4 直接整合了 Thunderbolt 3 的协议基础带宽来到 40Gbps。这段命名史真是一言难尽连很多老工程师都要查表才能说清楚。版本曾经/常用市场名带宽发布年份核心变化USB 1.0/1.1USB1.5Mbps / 12Mbps1996 / 1998取代串并口最初版本USB 2.0Hi-Speed480Mbps2000新增高速模式引入充电规范USB 3.0SuperSpeed5Gbps2008新增SDP差分对全双工USB 3.1SuperSpeed10Gbps2013编码从8/10b升级为128/132bUSB 3.2SuperSpeed20Gbps2017双通道复用USB4USB440Gbps2019基于Thunderbolt 3支持隧道协议1.3 向后兼容的底层思路加信号而不改信号我实际调试中见过不少标注 USB 3.0 的设备插到 USB 2.0 口依然能用这个兼容性不是天上掉下来的而是物理层设计一开始就留下了退路。USB 3.x 的插头里除了沿用 USB 2.0 的 D/D- 一对差分线之外额外加了两对 SuperSpeed 差分线一对发送、一对接收。如果主机和设备都是 3.x 但连接线只支持 2.0系统就自动降级到 480Mbps上层协议照跑不误。这种“加信号而不是改信号”的思路贯穿了 USB 的整个演进史。每一代新版本都在物理层上做加法协议栈和软件框架保持兼容让老设备在新总线上能继续工作。这也是为什么 USB 能成为统治级接口的底层原因之一——它几乎不给用户制造迁移成本。2. 一棵以主机为根的树USB 系统的角色分工与拓扑限制2.1 USB 拓扑跟以太网、RS-485 完全不一样很多人刚接触 USB 时会下意识拿它跟以太网或者 RS-485 总线对比。这其实是理解 USB 的第一道坎USB 的拓扑是一棵以主机为根的树不是星型也不是总线型。所有通信都严格发生在主机Host和设备Device之间设备与设备之间不能直接对话。你在 USB 总线上绝对看不到“A 设备给 B 设备发数据”这种操作因为协议在架构层面就不允许。这棵树的最顶端是主机。主机内部有一个 USB 主机控制器Host Controller负责生成总线上所有的事务。主机控制器下面挂根集线器Root Hub根集线器伸出几个物理端口每个端口可以再接一个设备或者下一级集线器。USB 规范里对层叠集线器的数量有硬性限制包括根集线器在内最多 7 层。超过这个层数设备不会被枚举。2.2 主机总线唯一的“话事人”USB 总线没有仲裁机制这一点和 CAN 总线的 CSMA/CR 完全不同。所有传输都由主机发起设备永远不能主动往总线上发数据只能被动响应主机的请求。这个设计让设备端变得非常便宜——设备不需要做冲突检测不需要调度重传只要监听总线上的地址认领属于自己的事务就行。主机侧的控制器标准从 UHCI、OHCI、EHCI 一路走到现在的 xHCI。xHCI 是当前主流同时兼容 USB 2.0 和 USB 3.x。它的工作方式蛮有意思的把对设备的访问抽象成“命令”和“事件”两个环形队列操作系统驱动把命令塞进队列控制器异步处理完用事件回报结果。这种异步机制让 USB 3.0 时代的多设备并发吞吐比 USB 2.0 时代好了一大截。2.3 集线器不只是扩展端口还负责信号中继和事件上报集线器Hub的作用常被低估。它不只是物理上多插几个口还要承担三件事信号中继、速度协商、电源管理。集线器把上游端口upstream port接主机方向和下游端口downstream port接设备方向分开管理。当下游端口检测到设备插入会通过一个状态位变化告诉主机“端口事件来了”。主机收到通知后再发查询请求去了解具体是什么事件。这个“事件上报”机制是后面理解设备枚举的重要前置知识。你可以把集线器想象成公司前台有人来了它先按铃通知老板老板问清楚是谁、什么事再决定怎么接待。2.4 设备侧分类功能设备、复合设备与组合设备USB 设备端可以分成三类这个概念我见过不少驱动新手搞混。功能设备Function只实现一个功能比如一个普通 U 盘或者一个鼠标。复合设备Composite Device指一个物理设备内部有多个功能最典型的例子是带麦克风的摄像头——它内部有一个视频功能还有一个音频功能共用一个物理设备地址但对外暴露多个接口Interface每个接口描述一个功能。组合设备Compound Device则是物理外壳里集成了一颗集线器和多个独立功能设备比如一体式 USB 键盘键盘本身是一个设备键盘上自带的集线器又扩展出鼠标接口。这三者的差异直接影响驱动匹配逻辑。以 Linux 的 usbhid 驱动为例复合设备在枚举时会出现多个接口而组合设备则表现为一个集线器下挂了多个地址完全不同的设备。分不清这两者写驱动时很容易在设备/配置/接口的层级关系上栽跟头。3. 物理层里藏着的秘密D/D-、上拉电阻和 5V 供电3.1 差分信号USB 抗干扰的看家本领USB 2.0 及以下的信号跑在一对差分线上D 和 D-。所谓差分传输就是信号电平不是单端对地而是用两根线之间的电压差来表达 0 和 1。发送端发逻辑 1 时D 拉高、D- 拉低两根线之间形成正压差发逻辑 0 时反过来。接收端把两根线做减法还原数据。这么做最大的好处是抗共模干扰。外部噪声、串扰通常会同时叠加在两根线上接收端做减法时噪声被直接抵消有用的差分信号被保留下来。这也是工业现场里 USB、RS-485、CAN 这些总线普遍采用差分信号的原因。当然差分线不是随便拉两根就能跑高速的。PCB 布线时 D 和 D- 要尽量等长、保证差分阻抗 90ΩUSB 2.0或 85ΩUSB 3.x就是为了让差分对在传输中保持同步、减少信号反射。我自己画板子时踩过高速 USB 布线的坑后来总结下来只要做到等长、包地、走线别太长信号基本都能接受。3.2 速度识别靠硬件电阻不是软件配置出来的USB 设备插入后主机怎么第一时间知道它是高速、全速还是低速答案就在 D 和 D- 的上拉电阻上。全速设备在 D 线上接一个 1.5kΩ 上拉电阻到 3.3V低速设备则在 D- 线上接同样的上拉电阻。集线器的每个下游端口内部都有一对 15kΩ 下拉电阻。设备一插上去对应数据线的电平被拉高集线器检测到这个跳变就知道有设备来了并且通过看哪根线被拉高就能分辨出是全速还是低速设备。高速设备的情况更特殊它上电初期伪装成全速设备D 上拉跟主机握手之后再通过 chirp 信号协商切到高速模式。所以 USB 2.0 高速设备的识别过程不是一次性完成的而是“先假装全速再协商升级”。调试时如果高速设备被当成全速设备枚举问题大概率出在 chirp 信号处理上而不是驱动配置。3.3 连接器和线缆物理层家族越来越庞大USB 连接器从早期的 Type-A、Type-B发展到 Mini、Micro再到现在的 Type-C品类非常多。Type-A 是那个长方形扁平口Type-B 是方形的常用于打印机和开发板Micro-B 曾经是安卓手机的标准充电口Type-C 则是现在几乎一统天下的形态。Type-C 能做的远比老接口多。除了正反插都是对称的它的 CC 引脚还承担了检测插拔方向、供电能力协商、Alternate Mode比如 DP 视频输出等功能。但从协议角度讲USB 协议本身并不关心你用的是哪种连接器——它就是一堆电气信号连接器只是信号的物理载体。这一点很重要否则看到那么多转接线材会被绕晕。3.4 VBUS 供电能供 5V 不代表能随便拉电流USB 端口不只是传数据还对外供电。USB 2.0 标准端口默认供电能力是 5V/500mAUSB 3.0 单端口可以到 900mAType-C 默认模式可以到 1.5A。如果设备需要更大的电流比如 3A、5A就必须走 USB PDPower Delivery协商用 CC 线做协议握手。这里我想强调一个很多人栽过的跟头USB 口能输出 5V 电压不代表能无限量输出电流。总线供电设备如果电流超标轻则端口保护掉线重则烧掉主板上的 USB 供电电路。我做开发时亲眼见过一个人把笔记本主板的 USB 供电模块干烧了原因是做了一个 2A 的自制小设备直接插总线供电且没有任何限流保护。做 USB 设备时电流预算一定要心里有数。4. 包、事务与传输把 USB 的对话方式拆给你看4.1 包Packet总线上最小的信息单元USB 协议是典型的包驱动协议。一次通信由若干个包组成每个包内部有固定结构。USB 2.0 的一个典型数据包由五段组成同步域SYNC、包标识符PID、数据字段、CRC、包结束EOP。SYNC 域用来让接收端跟发送端的时钟对齐PID 码标识包的类型数据字段承载有效负载可以是 0 字节CRC 做校验令牌包用 CRC5数据包用 CRC16EOP 标记一个包的物理结束。PID 本身是 8 位低 4 位是类型码高 4 位是低 4 位的反码用于校验。常见的 PID 类型包括 OUT、IN、SOF帧起始、SETUP、DATA0、DATA1、ACK、NAK、STALL 等。我第一次学的时候被这些缩写搞得一头雾水后来发现只要抓住“数据传输就是令牌、数据、握手三个阶段”这条主线每个 PID 该出现在哪个阶段就非常容易推出来。4.2 事务Transaction主机发起的一次完整问询一次事务Transaction通常包含两到三个包。最完整的事务有三个阶段令牌阶段Token Phase主机发出 OUT、IN 或 SETUP 包包里带设备地址和端点号相当于点名一个设备的某个端点告诉它接下来要干什么。数据阶段Data Phase对 OUT/SETUP 事务主机发送 DATA0/DATA1 数据包对 IN 事务设备向主机发送数据包。握手阶段Handshake Phase接收方返回 ACK确认收到、NAK暂时没准备好或 STALL端点出错/不支持整个事务到此结束。为什么要有令牌阶段因为 USB 是共享总线所有设备都挂在同一对差分线上必须有一个机制决定当前时刻谁有资格占用总线。令牌就是总线的通行证只有被令牌点名的设备才能开口说话。4.3 四种传输类型控制、批量、中断、等时USB 协议定义了四种传输类型覆盖不同的应用场景和带宽需求。传输类型是否周期可靠性带宽占用典型应用控制传输非周期高带重试和校验小设备枚举、命令配置批量传输非周期高带重试和校验大U盘、USB转串口、打印机中断传输周期中出错可重试中鼠标、键盘、HID设备等时传输周期低无重传机制大音频、摄像头、实时传感器控制传输是唯一每台 USB 设备都必须支持的传输类型。设备只要上电枚举就得通过端点 0 跑控制传输。批量传输适合大数据量且要求可靠的场景比如 U 盘读写但它的优先级最低总线繁忙时必须给中断和等时传输让路。等时传输最特殊。它保证带宽但不保证送达——因为没有重传机制丢了一个包就丢了。为什么音频视频走等时因为音视频最怕的是延迟和抖动。一个数据包传丢了可以接受但要让扬声器停下来等重传那声音就会卡顿。这是“保带宽不保正确”和“保正确不保时间”之间的经典取舍。这里分享一个经验我抓 USB 包时一开始总被海量小包淹没后来学会了按 PID 过滤、按端点过滤整个通信过程立刻清爽。我强烈建议学 USB 协议的朋友别只盯着文档看一定要配合 USB 抓包工具比如 Wireshark 配合 USBPcap或者 Bus Hound去观察真实的数据流尤其是控制传输里的 SETUP 包里面包含设备地址和请求类型比任何文档都直白。5. 端点和管道USB 数据流动的门牌号与通路5.1 端点设备内部的数据出入口端点Endpoint是理解 USB 通信最核心的概念没有之一。你可以把端点想成设备内部的一个数据缓冲区所有数据进出设备都必须经过端点。每个端点有一个地址由“端点号 方向”组成。端点号范围 0~15方向分 IN 和 OUT方向定义站在主机视角IN 端点设备向主机方向传数据主机“读”设备。OUT 端点主机向设备方向写数据主机“写”设备。一个 USB 设备理论上最多支持 32 个端点16 个 IN 16 个 OUT但绝大多数实际设备用不到这么多。比如一个 HID 鼠标通常只需要一个中断 IN 端点就够了。5.2 管道主机软件与端点之间的逻辑通路管道Pipe是主机侧对端点的“访问通道”。规范把管道分成两种流管道Stream Pipe和消息管道Message Pipe。批量、中断、等时传输使用流管道数据没有内部结构就是连续字节流控制传输使用消息管道报文有固定格式主机必须按“请求/响应”的结构来访问。一句话总结端点是设备侧的硬件概念管道是主机软件侧的抽象视图。同一端点同一时刻只能由一种传输类型访问你永远不会在驱动里看到某个端点既能做批量又能做中断。5.3 端点 0所有 USB 设备故事的起点端点 0 是所有 USB 设备与生俱来的端点方向是双向的承载控制传输。设备上电后主机做的第一件事就是通过端点 0 发一个 GET_DESCRIPTOR 请求读取设备描述符。这一步拿不到数据后续所有配置都无从谈起。端点 0 的最大包长在不同速度下不同低速设备固定 8 字节全速设备可以是 8、16、32、64 字节最常见的是 64 字节高速设备固定 64 字节。这个数字直接影响控制传输的分包逻辑。我排查枚举失败问题时第一件事就是检查端点的最大包长配置是否和速度匹配。很多国产设备的枚举问题最后查下来都是这里填错了。5.4 描述符设备递给主机的自我介绍书描述符Descriptor是 USB 世界里最“面向对象”的部分。设备用标准格式的二进制数据向上汇报自己的属性主机按固定结构去解析就能做到“不认识厂商也能用上通用驱动”。描述符是分层的树形结构从上到下依次为设备描述符Device Descriptor一个设备只有一个包含 VID/PID、设备类、端点 0 最大包长等。配置描述符Configuration Descriptor一个设备可以有多个配置比如“总线供电”一个”自供电”一个由主机选择激活哪个。接口描述符Interface Descriptor一个配置下面可以有多个接口每个接口代表一个独立功能。端点描述符Endpoint Descriptor接口下面列出各端点的地址、传输类型、最大包长、轮询间隔等参数。拿一枚典型的 USB 鼠标举例设备描述符里标明自己是 HID 设备配置描述符下面有一个接口描述符接口下面描述了一个中断 IN 端点最大包长 8 字节轮询间隔 1 到 8 毫秒。驱动读完这套东西就知道该创建一个什么样的输入设备节点了。5.5 主机视角从枚举到驱动绑定从驱动开发者的视角看USB 设备插入后操作系统做的事情是先枚举再读描述符然后匹配驱动最后驱动拿到的是一个个端点的集合。以大家熟悉的 USB 转串口芯片为例CH340、FT232R热搜词里总有人找 ft231x/ft232r 驱动这类芯片本质上就是在设备里开了一对批量端点端点把主机发来的串口数据转发给 UART 逻辑再把 UART 收到的数据通过另一个端点传回主机。操作系统驱动层把这对端点抽象成 ttyACM0 或 COM3。理解了这个映射关系调试“USB 转串口不识别”时就有了清晰的排查顺序先看设备枚举是否成功设备描述符有没有读到再看驱动是否正确绑定最后看端点配置和实际工厂设置是否匹配。很多人第一步枚举没过却一直在操作系统驱动层反复卸载重装方向就反了。最后分享一个我自己的经历。前阵子帮同事排查一个 USB 摄像头间歇性掉线大家第一反应是线材和供电问题换了三根线也没解决。最后用抓包工具盯了一阵子发现低速控制事务一直在重传配合 XHCI 的等时调度才定位到主控固件在特定带宽分配下的调度缺陷。如果没有对 USB 事务、端点、传输类型这些概念的积累这种问题大概率只能靠换设备这种玄学手段去解决。所以说USB 协议这套东西表面看是规范和寄存器实际上是你排查一切 USB 相关问题的思维框架。这篇“上篇”把 USB 的历史背景、系统拓扑、物理层基础、传输类型和端点通信框架讲清楚了。枚举的完整时序、各类描述符的实际抓包解读、对应的 Linux 驱动代码实现、以及常见 USB 调试手段的实操细节我会在“下篇”里继续拆。如果你手边正好有个 U 盘或者 USB 转串口模块我强烈建议你现在就用抓包工具把它的端点信息读出来对照本文过一遍。你会发现之前那些“玄学”一样的识别问题很多其实都有清晰的技术解释。