day01-USB架构与枚举

📖 引言

USB(Universal Serial Bus)是现代计算机系统中最重要的外设接口之一,但其通信机制却常常令人困惑。本文将从最核心的Host主导原则出发,深入解析USB通信的各个层面,包括设备架构、端点机制、枚举过程等关键概念。无论你是嵌入式开发者、系统工程师,还是对USB原理感兴趣的爱好者,本文都将为你提供清晰、系统的理解框架。


1. 🎯 最重要的原则:USB由Host主导

USB不是普通的双向串口,而是一个严格的主从架构总线系统。

1.1 Host与Device的角色

在USB总线上:

  • Host:发起并调度所有通信
  • Device :不能随意向总线发送数据
    • Device只能准备数据,然后等待Host访问相应端点
    • 即使摄像头有新画面,也不能直接"主动推给PC"
    • 实际上是PC按调度周期发起IN Transaction,设备返回已经准备好的数据

1.2 RK3568发送视频的实际流程

#mermaid-svg-EfsiFxMLXPUWVi5W{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-EfsiFxMLXPUWVi5W .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-EfsiFxMLXPUWVi5W .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-EfsiFxMLXPUWVi5W .error-icon{fill:#552222;}#mermaid-svg-EfsiFxMLXPUWVi5W .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-EfsiFxMLXPUWVi5W .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-EfsiFxMLXPUWVi5W .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-EfsiFxMLXPUWVi5W .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-EfsiFxMLXPUWVi5W .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-EfsiFxMLXPUWVi5W .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-EfsiFxMLXPUWVi5W .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-EfsiFxMLXPUWVi5W .marker{fill:#333333;stroke:#333333;}#mermaid-svg-EfsiFxMLXPUWVi5W .marker.cross{stroke:#333333;}#mermaid-svg-EfsiFxMLXPUWVi5W svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-EfsiFxMLXPUWVi5W p{margin:0;}#mermaid-svg-EfsiFxMLXPUWVi5W .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-EfsiFxMLXPUWVi5W .cluster-label text{fill:#333;}#mermaid-svg-EfsiFxMLXPUWVi5W .cluster-label span{color:#333;}#mermaid-svg-EfsiFxMLXPUWVi5W .cluster-label span p{background-color:transparent;}#mermaid-svg-EfsiFxMLXPUWVi5W .label text,#mermaid-svg-EfsiFxMLXPUWVi5W span{fill:#333;color:#333;}#mermaid-svg-EfsiFxMLXPUWVi5W .node rect,#mermaid-svg-EfsiFxMLXPUWVi5W .node circle,#mermaid-svg-EfsiFxMLXPUWVi5W .node ellipse,#mermaid-svg-EfsiFxMLXPUWVi5W .node polygon,#mermaid-svg-EfsiFxMLXPUWVi5W .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-EfsiFxMLXPUWVi5W .rough-node .label text,#mermaid-svg-EfsiFxMLXPUWVi5W .node .label text,#mermaid-svg-EfsiFxMLXPUWVi5W .image-shape .label,#mermaid-svg-EfsiFxMLXPUWVi5W .icon-shape .label{text-anchor:middle;}#mermaid-svg-EfsiFxMLXPUWVi5W .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-EfsiFxMLXPUWVi5W .rough-node .label,#mermaid-svg-EfsiFxMLXPUWVi5W .node .label,#mermaid-svg-EfsiFxMLXPUWVi5W .image-shape .label,#mermaid-svg-EfsiFxMLXPUWVi5W .icon-shape .label{text-align:center;}#mermaid-svg-EfsiFxMLXPUWVi5W .node.clickable{cursor:pointer;}#mermaid-svg-EfsiFxMLXPUWVi5W .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-EfsiFxMLXPUWVi5W .arrowheadPath{fill:#333333;}#mermaid-svg-EfsiFxMLXPUWVi5W .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-EfsiFxMLXPUWVi5W .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-EfsiFxMLXPUWVi5W .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EfsiFxMLXPUWVi5W .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-EfsiFxMLXPUWVi5W .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EfsiFxMLXPUWVi5W .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-EfsiFxMLXPUWVi5W .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-EfsiFxMLXPUWVi5W .cluster text{fill:#333;}#mermaid-svg-EfsiFxMLXPUWVi5W .cluster span{color:#333;}#mermaid-svg-EfsiFxMLXPUWVi5W div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-EfsiFxMLXPUWVi5W .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-EfsiFxMLXPUWVi5W rect.text{fill:none;stroke-width:0;}#mermaid-svg-EfsiFxMLXPUWVi5W .icon-shape,#mermaid-svg-EfsiFxMLXPUWVi5W .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EfsiFxMLXPUWVi5W .icon-shape p,#mermaid-svg-EfsiFxMLXPUWVi5W .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-EfsiFxMLXPUWVi5W .icon-shape .label rect,#mermaid-svg-EfsiFxMLXPUWVi5W .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EfsiFxMLXPUWVi5W .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-EfsiFxMLXPUWVi5W .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-EfsiFxMLXPUWVi5W :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} RK3568用户态程序准备图像
提交给UVC Gadget驱动
驱动把usb_request挂到IN端点
PC Host按周期发起IN事务
RK3568 USB控制器返回视频数据

1.3 IN/OUT方向定义

这里"IN/OUT"永远以Host为参照:

方向 数据流向 典型应用
IN Device → Host USB摄像头视频、USB麦克风音频
OUT Host → Device USB音箱播放数据、PC发送控制命令
EP0 双向(控制传输) PC发送控制命令、设备枚举

⚠️ 重要提示:这是非常容易混淆、面试也经常问的地方!


2. 🏗️ Host侧和Device侧架构

以RK3568连接Windows PC为例:

2.1 Windows PC(Host侧)

复制代码
Windows PC(Host)
├─ xHCI Host Controller
├─ USB Core
├─ Hub Driver
└─ UVC/UAC Class Driver
          ↕ USB线

2.2 RK3568(Device侧)

复制代码
RK3568(Device)
├─ DWC3 Device Controller
├─ UDC Driver
├─ Gadget Core
├─ Composite Framework
├─ UVC Function
└─ UAC2 Function

2.3 重要名词解释

名词 描述 位置
Host Controller PC侧的USB控制器,一般是xHCI Host侧
UDC USB Device Controller,设备侧的控制器抽象 Device侧
Gadget Linux把"本机模拟成USB外设"的框架 Device侧
Function 复合设备中的一项功能,例如UVC、UAC、ACM Device侧
Composite Device 一个物理USB设备包含多个Function Device侧

2.4 最终设备结构

我们的最终设备大致是:

复制代码
一个USB Device
└─ 一个Configuration
   ├─ UVC Function
   │  ├─ VideoControl Interface
   │  └─ VideoStreaming Interface
   └─ UAC2 Function
      ├─ AudioControl Interface
      └─ AudioStreaming Interface

3. 🔍 Device、Interface和Endpoint的区别

3.1 Device(设备)

表示整个物理设备,包含:

  • VID/PID(厂商ID/产品ID)
  • USB版本
  • 设备类别
  • 厂商、产品、序列号字符串
  • Configuration数量

3.2 Configuration(配置)

表示设备的一套运行配置。大部分设备只有一个Configuration。Host通过SET_CONFIGURATION选择它。

3.3 Interface(接口)

表示一种逻辑功能。UVC摄像头通常不止一个Interface:

Interface类型 功能
VideoControl Interface 控制摄像头参数(亮度、对比度等)
VideoStreaming Interface 传输视频数据

Interface还可以有多个Alternate Setting:

Alternate Setting 状态
Setting 0 不传视频,没有等时端点
Setting 1 启用视频端点
Setting 2 启用更大带宽的视频端点

3.4 Endpoint(端点)

Endpoint是Device内部的数据通道。

端点地址格式
复制代码
bit 7:方向(1=IN,0=OUT)
bit 3:0:端点编号
示例
端点地址 端点编号 方向 完整描述
0x81 1 IN Endpoint 1 IN
0x82 2 IN Endpoint 2 IN
0x02 2 OUT Endpoint 2 OUT
0x00 0 OUT EP0 OUT方向
0x80 0 IN EP0 IN方向

注意:端点号相同但方向不同,可以表示不同端点:

  • EP1 IN = 0x81
  • EP1 OUT = 0x01

4. ⭐ EP0为什么特殊

每个USB设备都必须有Endpoint 0

4.1 EP0的作用

EP0用于Control Transfer,承担:

  • 获取描述符
  • 设置设备地址
  • 选择Configuration
  • 发送标准请求
  • 发送Class请求
  • UVC/UAC参数协商

4.2 为什么必须有EP0?

设备刚插入时,Host还不知道它是什么设备,但一定知道它存在EP0,因此枚举才能从EP0开始。

4.3 控制传输三个阶段

控制传输通常分为三个阶段:

复制代码
SETUP阶段 → 可选DATA阶段 → STATUS阶段

例如Host读取Device Descriptor:

  1. SETUP:Host说明"我要读取Device Descriptor"
  2. DATA:Device返回描述符
  3. STATUS:Host确认传输完成

4.4 SETUP包结构

SETUP包固定为8字节:

c 复制代码
struct usb_ctrlrequest {
    uint8_t  bRequestType;
    uint8_t  bRequest;
    uint16_t wValue;
    uint16_t wIndex;
    uint16_t wLength;
};

后面分析UVC请求时会反复遇到这个结构体。


5. 🔄 设备插入后的枚举过程

5.1 三个关键状态

先记住三个状态:

复制代码
Default → Addressed → Configured

5.2 典型枚举过程

#mermaid-svg-n969rTPSwqgxAQRA{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-n969rTPSwqgxAQRA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-n969rTPSwqgxAQRA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-n969rTPSwqgxAQRA .error-icon{fill:#552222;}#mermaid-svg-n969rTPSwqgxAQRA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-n969rTPSwqgxAQRA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-n969rTPSwqgxAQRA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-n969rTPSwqgxAQRA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-n969rTPSwqgxAQRA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-n969rTPSwqgxAQRA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-n969rTPSwqgxAQRA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-n969rTPSwqgxAQRA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-n969rTPSwqgxAQRA .marker.cross{stroke:#333333;}#mermaid-svg-n969rTPSwqgxAQRA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-n969rTPSwqgxAQRA p{margin:0;}#mermaid-svg-n969rTPSwqgxAQRA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-n969rTPSwqgxAQRA .cluster-label text{fill:#333;}#mermaid-svg-n969rTPSwqgxAQRA .cluster-label span{color:#333;}#mermaid-svg-n969rTPSwqgxAQRA .cluster-label span p{background-color:transparent;}#mermaid-svg-n969rTPSwqgxAQRA .label text,#mermaid-svg-n969rTPSwqgxAQRA span{fill:#333;color:#333;}#mermaid-svg-n969rTPSwqgxAQRA .node rect,#mermaid-svg-n969rTPSwqgxAQRA .node circle,#mermaid-svg-n969rTPSwqgxAQRA .node ellipse,#mermaid-svg-n969rTPSwqgxAQRA .node polygon,#mermaid-svg-n969rTPSwqgxAQRA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-n969rTPSwqgxAQRA .rough-node .label text,#mermaid-svg-n969rTPSwqgxAQRA .node .label text,#mermaid-svg-n969rTPSwqgxAQRA .image-shape .label,#mermaid-svg-n969rTPSwqgxAQRA .icon-shape .label{text-anchor:middle;}#mermaid-svg-n969rTPSwqgxAQRA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-n969rTPSwqgxAQRA .rough-node .label,#mermaid-svg-n969rTPSwqgxAQRA .node .label,#mermaid-svg-n969rTPSwqgxAQRA .image-shape .label,#mermaid-svg-n969rTPSwqgxAQRA .icon-shape .label{text-align:center;}#mermaid-svg-n969rTPSwqgxAQRA .node.clickable{cursor:pointer;}#mermaid-svg-n969rTPSwqgxAQRA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-n969rTPSwqgxAQRA .arrowheadPath{fill:#333333;}#mermaid-svg-n969rTPSwqgxAQRA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-n969rTPSwqgxAQRA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-n969rTPSwqgxAQRA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-n969rTPSwqgxAQRA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-n969rTPSwqgxAQRA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-n969rTPSwqgxAQRA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-n969rTPSwqgxAQRA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-n969rTPSwqgxAQRA .cluster text{fill:#333;}#mermaid-svg-n969rTPSwqgxAQRA .cluster span{color:#333;}#mermaid-svg-n969rTPSwqgxAQRA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-n969rTPSwqgxAQRA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-n969rTPSwqgxAQRA rect.text{fill:none;stroke-width:0;}#mermaid-svg-n969rTPSwqgxAQRA .icon-shape,#mermaid-svg-n969rTPSwqgxAQRA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-n969rTPSwqgxAQRA .icon-shape p,#mermaid-svg-n969rTPSwqgxAQRA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-n969rTPSwqgxAQRA .icon-shape .label rect,#mermaid-svg-n969rTPSwqgxAQRA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-n969rTPSwqgxAQRA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-n969rTPSwqgxAQRA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-n969rTPSwqgxAQRA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 设备接入
Host检测到连接
Host对端口复位
Device进入Default状态

地址为0
Host通过EP0读取

Device Descriptor
Host发送SET_ADDRESS
Device进入Addressed状态
Host读取完整描述符
Host根据Class/Subclass/Protocol

选择驱动
Host发送SET_CONFIGURATION
Device进入Configured状态
Class Driver开始发送

UVC/UAC专用请求

5.3 描述符读取顺序

复制代码
├─ Device Descriptor
├─ Configuration Descriptor
├─ Interface Descriptor
├─ Endpoint Descriptor
└─ String Descriptor

5.4 关键理解

一个关键点是:Host不是看到设备外观后认出摄像头,而是根据描述符识别它

如果描述符声明:

  • Video Class
  • VideoControl Interface
  • VideoStreaming Interface
  • MJPEG Format
  • 1280×720 @ 30fps
  • Isochronous IN Endpoint

Windows才会把它当作UVC摄像头,并加载系统内置的类驱动。

所谓"免驱",不是设备不需要驱动,而是设备遵守标准Class规范,Host使用系统已有的Class Driver。


6. 📦 Packet、Transaction、Transfer

这三个概念不能混用。

6.1 Packet(包)

USB总线上最基础的数据单元,例如:

  • Token Packet
  • Data Packet
  • Handshake Packet

6.2 Transaction(事务)

由若干Packet组成的一次总线事务。

例如普通IN事务:

复制代码
IN Token → DATA Packet → ACK

6.3 Transfer(传输)

面向软件的一次完整数据传输,可以由多个Transaction组成。

6.4 四种USB传输类型

类型 可靠性 带宽 特点 常见用途
Control 有校验和重试保证 基本访问 用于枚举和控制 EP0、枚举、控制
Bulk 有校验和重试 使用剩余带宽 可靠的大数据传输 U盘、打印机
Interrupt 有校验和重试 周期性调度 保证最大延迟 键盘、鼠标
Isochronous 通常不重传 保留周期带宽 保证带宽,不保证可靠 摄像头、麦克风

等时传输不重传的原因:实时音视频更在意"及时到达",过期的视频帧或音频样本即使重传,通常也没有播放价值。


7. ⚡ USB速度和时间单位

7.1 USB 2.0常见速度

速度等级 速率 典型应用
Low Speed 1.5 Mbps 键盘、鼠标
Full Speed 12 Mbps 音频设备、老式摄像头
High Speed 480 Mbps 高速存储、高清摄像头

7.2 调度单位

速度等级 调度单位 时长
Full Speed 1帧 1 ms
High Speed 1个Microframe 125 μs

注意:每秒有8000个High-Speed Microframe。

7.3 带宽注意事项

480 Mbps只是线路速率,不等于应用可以获得60 MB/s。协议开销、总线调度和端点类型都会减少实际可用带宽。


8. 📝 今日练习

练习1:解释方向

请判断下面每条数据流是IN还是OUT:

  1. RK3568摄像头向PC发送一帧图像。
  2. PC向RK3568发送"调整亮度"请求的数据阶段。
  3. PC向RK3568模拟的USB音箱发送PCM音频。
  4. RK3568模拟麦克风向PC发送PCM音频。

练习2:解析Endpoint Descriptor

给定原始字节:

复制代码
07 05 81 01 00 04 01

字段布局:

  • bLength:1字节
  • bDescriptorType:1字节
  • bEndpointAddress:1字节
  • bmAttributes:1字节
  • wMaxPacketSize:2字节,小端序
  • bInterval:1字节

请回答:

  1. 端点编号是多少?
  2. 是IN还是OUT?
  3. bmAttributes & 0x03等于1,是什么传输类型?
  4. wMaxPacketSize是多少?
  5. bInterval是多少?

练习3:理解枚举

用自己的话回答:

  1. 为什么USB设备必须有EP0?
  2. 为什么"免驱设备"仍然需要Host驱动?
  3. Host在什么时候知道设备是摄像头?
  4. SET_ADDRESSSET_CONFIGURATION分别改变什么?
  5. 摄像头有新画面时,为什么不能直接向USB总线发送?

9. 📚 总结

本文系统性地讲解了USB通信的核心原理:

  1. Host主导原则是USB架构的基石
  2. 设备架构分为Host侧和Device侧
  3. Device/Interface/Endpoint构成USB设备的层次结构
  4. EP0作为控制端点,负责设备枚举和配置
  5. 枚举过程是设备被Host识别和配置的关键流程
  6. Packet/Transaction/Transfer是USB数据传输的三个层次
  7. 传输类型决定了数据的可靠性和实时性

理解这些概念对于开发USB设备、调试USB问题以及深入理解现代计算机外设系统都至关重要。

💡 提示:建议结合实际的USB协议分析工具(如Wireshark的USB捕获功能)来加深理解,观察真实的枚举过程和数据传输。

相关推荐
不会代码的小猴2 小时前
7. JSON
开发语言·c++·笔记·qt·算法·json
沫璃染墨2 小时前
《Qt从零入门系列(六):信号与槽进阶——从多种连接方式到Lambda表达式》
开发语言·c++·qt·代码规范·设计规范·qt5
Hello_Damon_Nikola2 小时前
INMP441从入门到精通
单片机·嵌入式硬件·物联网
ye150127774553 小时前
12V转3V-5V2A电位器无极调光调速WT7027
stm32·单片机·嵌入式硬件
小小龙学IT3 小时前
ZeroMQ(libzmq)开源消息库深度解析:brokerless 时代的轻量消息内核
c++·开源
Benny_Tang4 小时前
题解:P10230 [COCI 2023/2024 #4] Lepeze
c++·算法
无损检测小白白4 小时前
STM32F407 串口3 DMA收发-标准库
stm32·单片机·嵌入式硬件
我变成萤火虫4 小时前
反悔贪心(经典题目讲解)
c++·算法·贪心算法·stl·排序算法·反悔贪心
greatriver0074 小时前
e2studio R7FA6M5 卡死 rtc 需要如何配置时钟
单片机·瑞萨单片机