【嵌入式】第2讲:USB CDC 从“插上电脑”到“出现 COM 口”,枚举过程到底发生了什么

好,进入第 2 讲。

第2讲:USB CDC 从"插上电脑"到"出现 COM 口",枚举过程到底发生了什么

后面调试时,最常见的问题不是"代码编译不过",而是:

  • 插上电脑没反应
  • 设备管理器里看不到东西
  • 有未知设备,但没 COM 口
  • 有设备名,但打不开
  • 有 COM 口,但发不回去

这些问题,本质上都和枚举过程有关。

所以这一讲要学会两件事:

  1. 电脑插上板子后,双方在干什么
  2. 调试时怎么根据现象判断卡在哪一步

一、先讲一句最核心的话

"出现 COM 口"不是 USB 一插上就天然有的,而是电脑先成功识别了你的设备是 CDC,然后操作系统才把它呈现成 COM 口。

也就是说:

text 复制代码
插上USB
-> 电脑检测到设备接入
-> 电脑开始枚举
-> 设备返回描述符
-> 电脑确认这是 CDC 设备
-> 系统加载对应驱动
-> 设备管理器里出现 COM 口

如果这条链中间任何一步出问题,COM 口都可能不会出现。


二、什么叫"枚举"

可以先把"枚举"理解成:

电脑在给新插入的 USB 设备做身份核验和能力确认。

电脑要确认这些问题:

  • 你是不是一个合法 USB 设备?
  • 你是什么设备?
  • 你支持什么功能?
  • 你有几个接口?
  • 你有哪些端点?
  • 该给你配什么驱动?

设备必须按 USB 规范回答。

如果回答对了,电脑就继续。

如果回答错了,电脑就会:

  • 识别失败
  • 变成 Unknown Device
  • 或者根本不出 COM 口

三、从物理插入开始,到 COM 口出现,大概经历哪些步骤

下面按顺序讲。


第 1 步:物理接入,主机检测到设备存在

把 USB 线插上后,主机侧首先会感知:

"有一个 USB 设备接进来了。"

为什么能感知?

因为 USB 设备端会在数据线上表现出"我在这"的电气特征。

在板子上,这和:

  • DP
  • DM
  • USB_SLAVE
  • 板上的相关上拉控制电路

有关。原理图能看到 USB_SLAVEDP 存在关联链路,这就是设备接入识别相关电路的一部分。

这一阶段如果有问题,常见现象是:

  • 插上电脑完全没反应
  • 设备管理器没有任何刷新
  • 甚至供电灯都不对

这通常先查:

  • USB 线
  • 供电
  • D+ / D- 硬件
  • 设备是否真的在跑程序

第 2 步:主机复位设备,准备开始问话

电脑发现设备后,不会立刻给你 COM 口。

它会先做一个"初始化动作",把设备拉到统一起点,然后开始问问题。

你可以把它想成:

"先让你站好,再开始查身份证。"

设备此时必须正确响应 USB 基本协议。

如果这一步都没过,后面描述符都轮不到。


第 3 步:主机读取 Device Descriptor(设备描述符)

这是第一份关键身份证。

它会告诉主机一些非常基础的信息,比如:

  • USB 版本
  • 厂商 ID(VID)
  • 产品 ID(PID)
  • 设备类别
  • 设备版本
  • 字符串索引等

现阶段不用背字段值,但要知道:

Device Descriptor 是主机认识你的第一步。

如果这一步有问题,常见现象:

  • 设备显示为 Unknown USB Device
  • 设备描述符请求失败
  • 根本继续不下去

第 4 步:主机给设备分配地址

刚插上时,USB 设备并不是正式"有身份"的。

主机读完第一轮基础信息后,会给它分一个 USB 地址。

这个地址就像"点名时给你编号"。

后面主机再和你通信,就按这个地址找你。

如果这一步出问题,也会导致枚举中断。


第 5 步:主机继续读取更完整的描述符

这里就进入关键阶段了。

主机会继续读:

  • Configuration Descriptor
  • Interface Descriptor
  • Endpoint Descriptor
  • String Descriptor

可以先这样理解它们:

1. Configuration Descriptor

告诉主机:

  • 我有一种怎样的工作配置
  • 里面总共有多少接口
  • 总长度是多少

2. Interface Descriptor

告诉主机:

  • 我有哪些功能接口
  • 每个接口属于什么类别

对于 CDC 来说,通常会涉及:

  • 通信控制接口
  • 数据接口

3. Endpoint Descriptor

告诉主机:

  • 我的数据通道怎么分配
  • 哪些端点用来收
  • 哪些端点用来发
  • 哪些端点是中断/批量等类型

4. String Descriptor

告诉主机:

  • 厂商名
  • 产品名
  • 序列号等字符串信息

四、为什么读完这些描述符后,电脑才可能出 COM 口

因为主机必须先搞清楚:

"是不是 CDC 设备?"

只有当主机从描述符中确认:

  • 这个设备的接口组织方式符合 CDC
  • 类别信息正确
  • 端点安排合理

操作系统才会说:

"哦,这是个虚拟串口设备,我给它挂成 COM 口。"

所以必须记住:

COM 口不是某个 GPIO 决定的,而是"USB 枚举 + CDC 描述符 + 驱动匹配"的结果。


五、为什么有的设备被识别了,但就是不出 COM 口

这是新手非常容易混淆的点。

"被电脑识别"不等于"一定有 COM 口"。

可能出现几种情况:


情况 1:设备被识别成别的 USB 类

例如:

  • HID
  • MSC
  • 自定义类

这种情况下,设备可能完全正常,但就是不会出 COM 口。

因为它不是 CDC。


情况 2:描述符不完整或不符合 CDC 规范

这时可能出现:

  • 设备能被看见
  • 但驱动不匹配
  • 或者只显示异常设备
  • 没有虚拟串口

情况 3:驱动问题

有些系统环境下,即便设备本身枚举得差不多,如果驱动没匹配好,也可能:

  • 没有 COM 口
  • 有感叹号
  • 无法打开

情况 4:枚举中途失败

前面几步走了一半,但后面某一步失败,也可能表现成:

  • 设备一闪而过
  • 反复重连
  • 设备管理器刷新但不稳定
  • 最终没有 COM 口

六、把整个枚举过程类比成"入职登记"

把 USB 设备想成"新员工",电脑想成"公司前台"。

第一步:你进门

前台看到"有人来了"。

第二步:让你站好

确认你是一个正常来访者。

第三步:看身份证

读取 Device Descriptor。

第四步:给你工号

给设备分配地址。

第五步:看你的岗位说明

读取 Configuration / Interface / Endpoint Descriptor。

第六步:安排你进哪个部门

如果看出来你是 CDC,就把你安排成"串口设备"这个角色。

第七步:系统里给你开账号

最终在 Windows 里变成一个 COMx

所以:

COM 口 = 电脑完成一整套识别流程后的"岗位分配结果"

不是一插上就天然存在。


七、结合目标,最应该关注哪几个"观察点"

后面调试时,不要一上来就盯代码。

先盯现象。


观察点 1:插上后,设备管理器有没有刷新

如果完全没刷新,先怀疑:

  • USB 线坏
  • 板子没供电
  • 板子程序没跑
  • USB 硬件链路问题
  • D+ / D- 没建立有效接入状态

观察点 2:有没有出现"未知设备"

如果出现 Unknown Device,说明:

  • 主机感知到了设备接入
  • 但枚举没成功

这时候重点查:

  • 描述符
  • 时钟
  • USB 初始化
  • 底层驱动

观察点 3:有没有出现某个 USB 设备,但不是 COM 口

这说明:

  • 设备可能部分枚举成功了
  • 但没被识别为 CDC

重点查:

  • CDC 类注册
  • CDC 描述符
  • 类/接口/端点配置
  • 驱动匹配

观察点 4:有没有出现 COM 口

如果已经出现 COM 口,说明前面最困难的那部分其实已经过了:

  • USB 设备存在
  • 枚举基本成功
  • CDC 类基本成立
  • 驱动基本匹配

八、为什么 USB 时钟错误会严重影响枚举

要提前建立意识。

USB 比 UART 更挑时钟。

因为 USB 设备和主机之间的数据时序要求更严格。

如果 USB 时钟不稳定或不正确,常见现象是:

  • 枚举失败
  • 描述符读不完整
  • 设备反复断开重连
  • 有时认得出,有时认不出
  • COM 口时有时无

所以以后遇到"奇怪的 USB 问题",时钟一定是重点怀疑对象之一。


九、要知道"端点"是什么

端点不是物理引脚。

可以先把它理解成:

USB 设备内部的数据通道编号。

对于 CDC 设备,通常会有:

  • 控制相关端点
  • 数据接收端点
  • 数据发送端点

主机之所以能和你的"虚拟串口"通信,不是靠 原理图上引脚,而是靠这些 USB 端点在工作。

你现在只要先知道"端点存在且很重要"即可。


十、未来会遇到的故障,按枚举阶段分类


阶段 A:物理接入失败

现象:

  • 插上没任何反应

查:

  • USB 线
  • 电源
  • 板子程序是否运行
  • D+/D- 硬件链路

阶段 B:早期枚举失败

现象:

  • 设备管理器有反应
  • 但显示未知设备或报错

查:

  • Device Descriptor
  • USB Core 初始化
  • 时钟
  • 中断

阶段 C:类识别失败

现象:

  • 设备被识别了
  • 但没有 COM 口

查:

  • CDC 类注册
  • Interface / Endpoint Descriptor
  • 驱动匹配

阶段 D:应用层失败

现象:

  • 有 COM 口
  • 串口助手能打开
  • 但发什么都没回

查:

  • CDC 接收回调
  • 缓冲区
  • 发送接口
  • 忙状态处理

十一、这一讲该记住的结论

是:

  1. COM 口不是插上就有,是枚举成功后的结果。
  2. 电脑先读描述符,再判断你是不是 CDC。
  3. 只有被识别成 CDC,Windows 才会给你 COM 口。
  4. "设备被识别"不等于"一定有 COM 口"。
  5. 调 USB 问题时,要先判断卡在枚举哪一层。

十二、当前阶段的理解题

自己在脑子里答一遍:

1. 为什么 USB 设备插上后不一定有 COM 口?

因为主机要先完成枚举,并确认它是 CDC 设备,才会表现成 COM 口。

2. 为什么描述符很关键?

因为主机靠它判断设备身份、功能接口和端点组织。

3. 如果设备管理器出现 Unknown Device,说明什么?

说明主机已经感知到设备,但枚举过程中某一步失败了。

4. 如果设备被识别了但没有 COM 口,优先怀疑什么?

优先怀疑 CDC 类配置、描述符、接口和端点组织、驱动匹配。


十三、下一讲该讲什么

第3讲:做 USB CDC 虚拟串口,最小工程到底要具备哪些条件

这一讲会讲:

  • 工程必须有哪些基础文件
  • 时钟要满足什么
  • 中断要满足什么
  • USB 初始化链最小应该有哪些步骤
  • 如何判断"现在这个工程具不具备出 COM 口的资格"
相关推荐
2301_805962932 小时前
树莓派学习1-I2C配置与设备状态检测
嵌入式硬件·学习
jwt7939279374 小时前
RabbitMQ HAProxy 负载均衡
rabbitmq·负载均衡·ruby
学嵌入式的小杨同学10 小时前
STM32 进阶封神之路(三十三):W25Q64 任意长度写入深度实战 —— 从页限制到工业级通用读写(附完整代码 + 避坑指南)
stm32·单片机·嵌入式硬件·架构·硬件架构·嵌入式·flash
孟章豪11 小时前
《SQL拼接 vs 参数化,为什么公司禁止拼接SQL?(附真实案例)》
服务器·数据库·sql
不怕犯错,就怕不做12 小时前
linux 如何查看自己的帐号密码及samba的帐号和密码
linux·运维·服务器
Hello_Embed12 小时前
嵌入式上位机开发入门(三):TCP 编程 —— Server 端实现
笔记·单片机·网络协议·tcp/ip·嵌入式
李彦亮老师(本人)13 小时前
Rocky Linux 9.x 新特性详解
linux·运维·服务器·centos·rocky linux
NiKick13 小时前
在Linux系统上使用nmcli命令配置各种网络(有线、无线、vlan、vxlan、路由、网桥等)
linux·服务器·网络
zt1985q14 小时前
本地部署开源元搜索引擎 SearXNG 并实现外部访问
服务器·网络协议·开源