ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

STM32虚拟串口重命名实战:USB描述符与Zadig驱动缓存完全解析

STM32虚拟串口重命名实战:USB描述符与Zadig驱动缓存完全解析 前阵子调试一板子手边插了三块STM32开发板打开设备管理器一看好家伙清一色的“STM32 Virtual COM Port (COM3/COM5/COM8)”。哪块是主控哪块是调试从机只能挨个拔插试浪费时间不说还容易把固件下错板子。后来我花了一个晚上把STM32CubeMX生成工程里的USB描述符改了改再配合Zadig重新刷了一遍驱动设备管理器里终于变成了“Motor Debug Kit (COM5)”、“Battery Monitor (COM4)”这种一眼就能认出来的名字。这篇文章就是把这套流程完整拆开告诉你虚拟串口名称是怎么来的、固件里怎么改、Zadig又在里面起了什么作用以及怎么才能让Windows老老实实在COM口旁边挂上你自己起的名字。这套方法适合谁凡是做STM32开发、经常在电脑上同时插多个USB转虚拟串口设备的人不管是自己玩还是做产品调试都能直接用。你不需要对USB协议有多深的理解只要会点STM32CubeMX基础操作、能编译烧录固件再照着Zadig的界面点几下就能告别设备管理器里那堆同名串口。1. 设备管理器里的“同名串口”到底是谁取的名字1.1 一次USB枚举决定Windows看到的一切先把基础原理说清楚。STM32作为USB设备插进电脑后不是上来就能变成串口的它要先经历一次USB枚举。在这个过程中Windows会向设备发一串标准请求设备则把自己USB描述符里的信息告诉系统包括设备描述符里的VIDVendor ID、PIDProduct ID字符串描述符里的制造商、产品名、序列号接口描述符里的CDC类信息这些信息中最影响你“视觉体验”的就是产品字符串iProduct。STM32CubeMX生成的USB CDC工程默认把这个字符串写死为“STM32 Virtual COM Port”。Windows加载驱动后设备管理器里显示的友好名称很大程度上就是根据这个字符串来的。所以你会发现三块板子用的是同一份CubeMX默认代码插上去自然是同一个名字。系统为了让它们能区分只能在后面追加COM号于是就成了“STM32 Virtual COM Port (COM3)”、“STM32 Virtual COM Port (COM5)”这样一排看着一模一样的设备。不过要注意一点设备管理器里的“显示名称”并不100%等于USB描述符里的产品字符串。Windows还会看驱动INF文件里的DeviceName定义。比如ST官方串口驱动它的INF里把设备名写成了“STMicroelectronics Virtual COM Port”那么哪怕你把固件里的Product字符串改成“MyBoard”用ST驱动时设备管理器也可能是旧名字。这就是为什么很多人改了固件描述符重启电脑一看名字还是没变。1.2 改完描述符名字为什么还是显示旧名字这个问题我在第一次尝试时候也踩了坑。固件里明明把USBD_PRODUCT_STRING从“STM32 Virtual COM Port”改成了“My Debug Board”烧录后重新插拔设备管理器里还是“STM32 Virtual COM Port”。原因主要有两个。第一个原因是Windows设备驱动缓存在作祟。Windows第一次安装某个VID/PID的设备时会把匹配的驱动INF、设备友好名称、设备安装状态写进注册表和C:\Windows\INF\INFCACHE.1这类缓存里。后面再插入同一VID/PID的设备系统优先从缓存里读取信息而不是重新从头解析一遍设备描述符。如果你只改了Product字符串VID/PID没动系统会觉得“这设备我见过”直接沿用旧信息。第二个原因是USB驱动栈不同。如果一个设备被识别成COM口加载的是usbser.sys这类系统串口驱动它的设备名称由usbser.inf定义通常就是“USB Serial Device (COMx)”和你的USB产品字符串没关系。这种情况下你改Product字符串设备管理器不会显示新名字只有在设备属性的“详细信息”里才能看到。所以必须有一个外部工具来强制Windows“忘掉”旧缓存或者装一个能被你自定义名字控制的驱动。Zadig就是干这个的。2. 从CubeMX下手改出固件里的专属设备名2.1 新建一个USB CDC虚拟串口工程这几个参数别配错在动Zadig之前先得让STM32固件能输出一个正常的USB虚拟串口。用STM32CubeMX配置其实很快步骤就那几步。第一步打开CubeMX新建工程选好你的MCU型号。以最常见的STM32F103C8T6或者F407为例都能做。第二步在Pinout Configuration界面左侧找到Connectivity打开USB_OTG_FSF407或USBF103把“Activate Full-Speed Device”勾上。接着找到Middleware and Software Packs下的USB_DEVICE把Class for FS IP改成“Communication Device Class (Virtual Port Com)”。这一步完成后CubeMX会自动把USB的D/D-引脚、中断和中间件代码拉起来。第三步也是最容易出问题的时钟树。USB Full-Speed设备必须工作在48MHz。F103的典型配置是HSE 8MHzPLL×9得到72MHz系统时钟然后USB时钟选择PLLCLK并经过分频得到48MHz。F407一般是HSE 8MHz、系统时钟168MHz、PLLQ输出48MHz给USB_OTG_FS。很多人改完描述符后设备插电脑没反应十有八九是USB时钟不是48MHz。第四步点击生成代码选好IDE工具链MDK-ARM或STM32CubeIDE都行编译烧录。如果一切正常Windows里应该能识别出一个虚拟串口。如果插上后设备管理器显示“Unknown Device”或者“无法识别的USB设备”先回去检查时钟树。2.2 在usbd_conf.c里重写产品字符串、VID和PIDCubeMX生成的代码结构里和USB描述符最相关的主要有两个文件USB_DEVICE/Target/usbd_conf.cUSB_DEVICE/App/usbd_desc.c不同CubeMX版本可能略有差异但大差不差。你需要打开usbd_conf.c会看到类似这样的宏定义#define USBD_VID 0x1155 #define USBD_PID 0x0001 #define USBD_LANGID_STRING 0x409 #define USBD_MANUFACTURER_STRING STMicroelectronics #define USBD_PRODUCT_STRING STM32 Virtual COM Port #define USBD_SERIALNUMBER_STRING 00000000001A #define USBD_CONFIGURATION_STRING CDC Config #define USBD_INTERFACE_STRING CDC Interface改起来很直白。把USBD_PRODUCT_STRING改成你想要的名字比如#define USBD_PRODUCT_STRING Motor Debug Kit同时建议把VID和PID也改一改。VID是厂商ID如果你只是自己调试用不用真的去USB-IF申请随便填一个合法的16进制值就行但最好避开已经被大厂占用的。比如用0x1155是STMicroelectronics的默认值大家一起用它很容易撞车。PID更是可以每个板子不一样给电机控制板用0xA001电池监测板用0xA002这样Windows在系统层面就会把它们当成不同的设备处理。改完宏定义后usbd_desc.c里的USBD_GetProductString函数会自动读取USBD_PRODUCT_STRING不用手动改。有一点要注意usbd_desc.c里还有一个USBD_GetDeviceDescriptor函数里面定义了bcdDevice字段。这个字段是设备版本号默认可能是0x0100或0x0200。如果你在同一个PID下想让Windows重新识别也可以把bcdDevice改高一个版本比如从0x0100改成0x0101这也会影响Windows的驱动匹配逻辑。2.3 字符串长度、编码和bcdDevice的隐藏影响改Product字符串的时候我强烈建议只用英文字母、数字、短横线和下划线不要直接用中文字符。USB字符串描述符本身是UTF-16LE编码理论上支持中文但在Windows加载串口驱动、INF解析时经常会出现乱码设备管理器里可能显示成“鍩庢帶...”这种鬼东西还不如不改。另一个限制是字符串长度。USB字符串描述符的第一个字节是bLength最大255但真正用来存放UTF-16字符时去掉字符串描述符头部的4字节剩下251字节也就是最多125个字符左右。实际使用中不要挑战极限我建议控制在32字符以内因为部分第三方串口驱动或INF的“友好名称”字段也有长度限制太长会被截断。还有一点别看漏了USBD_SERIALNUMBER_STRING序列号。如果你同时插入多块同型号、同PID、同Product的板子Windows可以通过序列号区分设备实例但设备管理器不一定会显示序列号。所以想靠名称区分重点还是改Product字符串和PID。3. Zadig在这里不是改装驱动而是帮Windows“忘掉旧账”3.1 为什么非要Zadig不可驱动缓存的逻辑前面说Windows有驱动缓存同一个VID/PID第一次装好驱动后后面再插就不太愿意“重新认识”。这时你可以用设备管理器卸载设备再重新扫描硬件改动有时候能解决。但要是有多个设备、多个COM口来回卸载扫描很麻烦而且不一定能刷新INF里写死的友好名称。Zadig这工具很多玩嵌入式的人应该见过它原本最常用于给USB设备安装WinUSB、libusb-win32、libusbK这类驱动比如把某个USB设备替换成自定义驱动供上位机直接通信。但在我们这个场景里它发挥的作用是“强制驱动更新”它把当前设备选出来不看Windows旧缓存直接给这个USB设备实例重新装一个驱动。Zadig在它自己的列表里会实时读取设备的描述符信息所以只要你固件里改好了Product字符串Zadig下拉框里显示的设备名就是新名字。你选中它、安装驱动Windows就会卸载旧的驱动关系重新安装新驱动。这个过程会触发设备重新枚举把设备描述符里的新名称和硬件ID重新注册一遍设备管理器里的显示自然就更新了。3.2 两条路线保COM口还是直接变WinUSB使用Zadig时有两条路线取决于你是想继续用COM口还是可以接受纯USB设备通信。路线A保留COM口。在Zadig的驱动下拉框里选择“USB Serial (CDC)”不同版本可能显示为“USB Serial Device”。安装后设备管理器里面仍然会出现COM口还能像以前一样用串口助手打开。但注意设备管理器显示的友好名称大概率是“USB 串行设备 (COMx)”而不是你的自定义Product字符串。这是因为驱动INF里的名字优先。路线B直接换WinUSB驱动。在Zadig里选择“WinUSB Driver”。安装后这个设备不再映射成COM口而是出现在“通用串行总线设备”分类下。这时设备管理器里通常显示的就是USB描述符里的Product字符串也就是你在固件里改好的“Motor Debug Kit”。这种方式适合不用传统串口调试、直接用WinUSB API做高速通信的场景。如果你只是想“让设备管理器里不再一排同名串口”并且上位机是自己写的路线B很香。但如果你还是要用实时串口工具、或者用XCOM这些调试助手就必须走路线A。而路线A下还想要专属名称就需要我下一大节讲的INF方案。3.3 Zadig完整操作替换驱动、卸载残留、验证结果具体操作步骤我贴一下都是经过反复验证的。下载Zadig去官方zadig.akeo.ie下载最新版即可不用安装直接运行exe。把烧录好新固件的STM32板子用USB线连到电脑上。打开Zadig在菜单栏勾选Options → List All Devices这样它才会列出所有USB设备而不是只看默认输入设备。在下拉框里找到你的STM32设备确认右侧USB ID显示的VID/PID和你固件里设置的一致。比如你改成了1155和a001这里就该显示1155:A001。设置驱动要保留COM口在驱动下拉框选“USB Serial (CDC)”。要换成WinUSB选“WinUSB (v6.x.x.x)”。点击右边的“Replace Driver”或“Install Driver”按钮。如果显示“Replace Driver”说明原来已经有驱动如果显示“Install Driver”说明还是无驱动状态。等进度条走完打开设备管理器应该能看到设备被重新枚举。如果驱动变化成功设备管理器的分类和名称都会发生变化。遇到安装失败怎么办最常见的情况是原来驱动被占用或者Zadig识别到了一个复合设备节点。先拔掉其它无关USB设备然后在Zadig的菜单Driver → Uninstall driver把这个设备原来的驱动卸载掉拔掉设备重插重新打开Zadig再装一次。装WinUSB时Windows 10/11对微软签名的WinUSB驱动一般是直接放行的如果提示签名问题去“恢复设置”里启用“禁用驱动程序强制签名”模式再试。4. 想要“COM5”旁边显示专属名称自己做一个INF才彻底4.1 拉出Zadig的驱动包当模板既然usbser驱动的默认INF把串口名字写死成“USB 串行设备”想改名字只有改INF这条路。你不必从零开始写INF可以让Zadig先把驱动包导出来当模板。步骤很简单在Zadig里选中设备驱动选WinUSB或者USB Serial都行不要点Install而是点下面的“Save driver files to folder”指定一个输出目录。Zadig会把这套驱动需要的INF、SYS、CAT、还有安装脚本都放到目录里。这个INF就是你的基础模板。它里面的整体结构可以直接用你要做的只是两个改动一是把硬件ID换成你自己板子的VID/PID二是把字符串里的设备名改成你想要的名字。如果你不想用Zadig导出从Windows系统的C:\Windows\INF\usbser.inf或ST官方驱动的INF里复制出对应节也可以。不过Zadig导出的INF更干净没有多余分支适合新手改。4.2 改INF里的DeviceName把“USB 串行设备”换成你的名字以Zadig导出的INF为例关键在文件的中后段通常有一个[Strings]段内容类似[Strings] ProviderName MyCompany DeviceName My Debug Board设备管理器的显示名就看DeviceName这个变量在哪被引用。再往上翻你会看到类似[DeviceList.NTamd64] %DeviceName% USB_Install, USB\VID_1155PID_A001这句话的意思是凡是通过USB\VID_1155PID_A001匹配到的设备都加载USB_Install这个安装节并且在设备管理器里使用%DeviceName%这个字符串作为名称。你把DeviceName改成“Motor Debug Board COM”这类名字把硬件ID改成自己的VID/PID保存。然后右键这个INF文件选择“安装”。安装完成后拔掉设备重新插或者设备管理器里“扫描检测硬件改动”正常情况下就会出现一个带有自定义名称的串口。因为我自己调试还需要区分不同工程我习惯在名字后面加上功能用途比如“Motor Debug Board (CAN)”这种光看名字就能知道这块板子跑的是哪个固件。4.3 驱动签名与安装不上的应对自己做的INF因为没有经过WHQL签名在64位Windows上安装时大概率会撞上签名校验。这很正常不是你的INF写错了。最简单的做法是临时禁用驱动程序强制签名。Windows 10/11中按住Shift点“重启”进入高级启动菜单依次选择“疑难解答 → 高级选项 → 启动设置 → 重启”然后在启动设置界面按数字键7或F7选择“禁用驱动程序强制签名”。系统正常进入桌面后再右键INF安装。这个方法只管当次开机有效下次重启又会恢复强制签名但足够你完成调试。如果长期要用可以给机器开启测试签名模式但那会带来安全风险不推荐日常开启。另外每次重新编译烧录后如果PID没变Windows可能会认为设备没变继续加载旧驱动。但如果PID变了旧驱动没有覆盖到新PID就需要重新用设备管理器或Zadig给新PID装一次。5. 实测经验多板共存的命名规范和避坑清单5.1 最容易翻车的三个环节第一覆盖旧驱动缓存。不要只改Product字符串而不改PID。当初我第一块板子只改了Product结果Zadig里看到的设备名还是老的“STM32 Virtual COM Port”因为Windows从缓存加载了旧描述符。后来把PID从0x0001改到0xA001再配合Zadig重装一下就生效了。第二Zadig安装时选错目标。Zadig会列出所有USB设备如果电脑上有鼠标、键盘这种Hid设备千万不要随手选那个看起来像“USB Composite Device”的。每个选项右侧都有USB ID对照固件里的VID/PID就不会错。第三INF安装后串口工作不正常。如果你用自建INF强行加载usbser但INF里漏了接口协议相关的字段系统可能显示端口但打开失败。我为了一劳永逸通常直接把Zadig导出的模板整个复制一份只改名称和硬件ID其他字段不动很少出问题。5.2 命名规范怎么定设备管理器才真正不乱多板子同时调试时一定要有一套自己的命名规则。不然今天改个“Board1”明天改个“Test002”后面自己都分不清。我现在的个人规范是“项目代号-板卡功能-接口类型”比如板卡用途PIDProduct字符串INF中的DeviceName主控调试A001Motor Debug KitMotor Debug Board电池监测A002Battery MonitorBattery Monitor COM网关升级A003Gateway UPGRADEGateway Upgrade Port这样设备管理器里的名称、固件里的PID、还有项目的实际硬件三者的对应关系一目了然。就算过了三个月再对着设备管理器我依然能立刻知道哪块板子在跑什么。如果你的项目里同一块板子有不同的变体建议在Product字符串中加入硬件版本比如“Motor Debug Kit V2.1”。这样调试时也能快速确认固件是不是匹配最新硬件板。5.3 从“改名字”到“程序自动识别设备”的进阶思路设备管理器里能看到自定义名字只是第一步。你写上位机软件时程序不能去解析设备管理器显示名字那不是稳定的接口。更可靠的方式是通过VID/PID来识别设备这样即使名字被改了或中文乱码程序也能准确找到对应的串口。Windows下可以调用SetupAPI枚举所有COM口读取每个设备实例的硬件ID匹配VID_1155PID_A001然后拿到对应的COM号。这样就可以做到插上板子自动选择串口不会因为COM口漂移而把数据发到别的设备上。个人体会是把“改名称”和“按VID/PID匹配”一起做才是最终方案。名称是给工程师看的VID/PID是给代码和驱动用的两者配合好设备管理器不仅外观清爽调试效率也能明显提升。最后再分享一个细节改完所有配置后最好用Windows设备管理器里的“查看 → 按连接排序”看看设备挂在哪个USB控制器下面。多个设备同时连接时这个视角能帮你确认每个设备实际插在哪个端口配合自定义名称基本就不会再出现拔错线的问题了。
返回列表