1. 什么是USB字符串描述符?
如果你曾经在设备管理器中看到过"USB Composite Device"这样的模糊名称,或者插入USB设备后只显示"Unknown Device",那么很可能是因为缺少了正确的字符串描述符。字符串描述符就像是USB设备的"身份证"和"名片",它让设备能够用人类可读的文字来介绍自己。
简单来说,字符串描述符就是USB设备用来存储各种文本信息的特殊数据结构。这些信息包括厂商名称、产品名称、序列号、配置描述等。虽然从技术上讲,没有字符串描述符USB设备也能正常工作,但有了它,用户和操作系统就能更好地识别和管理设备。
我在实际开发中发现,很多USB设备无法被正确识别的问题,都是由于字符串描述符配置不当造成的。有一次我调试一个自定义USB设备,在Windows上总是显示为"Unknown Device",折腾了半天才发现是字符串描述符的索引设置错了。
2. 字符串描述符的标准格式
字符串描述符采用UTF-16LE编码,这是为了支持多语言环境。每个字符都用2个字节表示,即使是英文字符也是如此。这种编码方式确保了无论设备在哪个国家使用,都能正确显示本地语言的字符。
让我们来看一个具体的例子。假设我们要存储字符串"USB",其描述符的二进制格式如下:
08 03 55 00 53 00 42 00
这个8字节的数据结构可以这样解析:
08:描述符总长度(8字节)03:描述符类型(字符串描述符)55 00:字符'U'的UTF-16LE编码53 00:字符'S'的UTF-16LE编码42 00:字符'B'的UTF-16LE编码
在实际编程中,我们通常这样定义字符串描述符:
// 英文"USB"的字符串描述符
const uint8_t usb_string[] = {
0x08, // bLength: 8字节
0x03, // bDescriptorType: 字符串描述符
'U', 0x00, // "U"
'S', 0x00, // "S"
'B', 0x00 // "B"
};
需要注意的是,字符串描述符不以NULL字符结尾,其长度完全由bLength字段决定。每个字符串最多可以包含126个字符(254字节数据,加上2字节的头部信息)。
3. 语言ID描述符(String[0]的特殊作用)
字符串索引0有一个特殊的用途——它不存储实际的字符串内容,而是存储设备支持的语言ID列表。这是USB协议中实现多语言支持的关键机制。
当主机想要获取设备的字符串信息时,它首先会请求索引0的描述符,获取设备支持的语言列表,然后选择适当的语言ID来请求具体的字符串内容。
一个典型的语言ID描述符看起来像这样:
04 03 09 04
这个描述符表示:
04:描述符长度(4字节)03:描述符类型(字符串描述符)09 04:支持的语言ID(0x0409表示美式英语)
语言ID的格式遵循Microsoft的LCID标准,常见的值包括:
- 0x0409:英语(美国)
- 0x0404:中文(繁体)
- 0x0804:中文(简体)
- 0x0411:日语
- 0x0407:德语
在实际项目中,我曾经遇到一个有趣的问题:设备在英文系统上显示正常,但在中文系统上却显示乱码。经过排查发现,设备只支持英语(0x0409),当主机尝试用中文语言ID(0x0804)请求字符串时,设备无法提供对应语言的版本,导致显示异常。
4. 标准描述符中的字符串索引引用
USB设备的各种描述符(设备描述符、配置描述符、接口描述符)并不直接包含字符串内容,而是通过索引值来引用字符串描述符表中的对应条目。这种设计既节省了空间,又支持了多语言功能。
让我们看看各个标准描述符中如何使用字符串索引:
设备描述符中的字符串字段:

实战:从索引映射到多语言扩展&spm=1001.2101.3001.5002&articleId=155847895&d=1&t=3&u=de427ae6a37c4a61b961513700596628)
1464

被折叠的 条评论
为什么被折叠?



