
经常做嵌入式开发或者DIY电子制作的朋友应该都遇到过这种场景USB口插着一堆开发板和自制设备打开设备管理器一看满屏的“USB 串行设备(COM3)”“USB Serial Device(COM7)”你根本分不清哪个对应哪块板子。今天这篇文章我就借着一个真实需求完整演示怎么用STM32CubeMX配合Zadig给STM32的USB虚拟串口定制一个专属名称让设备管理器里一眼就能认出是谁。整个过程不绕弯子先把思路讲清楚再给出可以直接抄作业的配置和代码最后把我踩过的坑一并列出来。1. 先搞清楚设备管理器里的名称到底是谁在起作用1.1 从USB枚举到显示名称Windows做了哪些事很多教程一上来就让人改代码但改完发现设备管理器里还是老样子原因就是没想明白Windows的设备名称机制。USB设备插上电脑后会先被主机枚举设备本身会向主机上报一串描述符信息里面包含厂商ID(VID)、产品ID(PID)、产品字符串(iProduct)、厂商字符串(iManufacturer)等。这些信息相当于设备的“身份证”。但设备管理器里显示的名字却不一定是这个“身份证”上的名字。Windows在识别到一个USB设备后会通过VID/PID去匹配驱动真正决定设备管理器列表里显示什么名称的是驱动安装包里的INF文件里面写着类似FriendlyName STMicroelectronics Virtual COM Port这样的字段。换句话说设备自己说“我叫张三”没用系统配发的工牌上写“李四”那设备管理器里就显示“李四”。这是一个非常关键的认知想让设备管理器显示你想要的名称要么让系统加载一个自定义的INF驱动要么让设备描述符里的字符串恰好成为Windows最终采用的名称来源。对STM32虚拟串口来说默认加载的是Windows自带的usbser.sys驱动系统会统一显示为“USB 串行设备(COMx)”所以哪怕你在STM32工程里把产品字符串改出花来设备管理器该显示“USB 串行设备”还是显示“USB 串行设备”。这也是为什么纯改STM32代码往往无法直接解决问题的原因。1.2 Zadig在这个流程里到底是什么角色Zadig是一个开源驱动安装工具网上很多人叫它“USB驱动装换神器”。它本身不负责改名字它的核心作用是把一个USB设备从系统当前绑定的驱动强制切换到另一个驱动。比如把设备从系统自带的usbser.sys切到WinUSB或libusbK或者反过来。那Zadig和“定制专属虚拟串口名称”有什么关系关系在于Zadig能把设备在系统里的驱动绑定状态“洗”一遍。在我们想安装自定义INF的时候系统经常因为已经记住了“USB 串行设备”这个旧状态而拒绝换名字这时先通过Zadig把设备切到WinUSB再换回串口驱动并安装自定义INF成功率会高很多。这个技巧我后面会专门讲属于网上教程不太会写但在实际项目中非常救命的路子。另外Zadig在设备列表中会显示设备上报的产品字符串所以你在STM32CubeMX里改好USBD_PRODUCT_STRING后可以在Zadig界面里直接看到自己取的名字。这既方便确认设备枚举状态也是排查描述符是否修改成功的一种简单手段。2. CubeMX快速搭出一个USB虚拟串口工程2.1 配置STM32CubeMX生成工程时钟树是关键先说前提我这边用来演示的芯片是STM32F103C8T6也就是大家最常用的蓝药丸开发板。用其他型号比如F407、F429操作路径略有不同但思路完全一致。如果你还没装STM32CubeMX先去官网下载对应版本安装过程没什么坑汉化包也有这里不展开。新建工程后首先在SYS里把Debug选成Serial Wire不然烧录器连不上。然后配置时钟源RCC - HSE - Crystal/Ceramic Resonator再打开USB外设。F103的外设叫USB在Pinout页面找到USB把它的工作模式选成Device (FS)这时候右侧芯片引脚会自动分配PA11和PA12。如果你是F407等带OTG的芯片对应的是USB_OTG_FS同样选择Device (FS)。接下来是很多初学者第一次翻车的地方时钟树。USB外设对时钟的要求非常死必须工作在48MHz。以F103为例系统主频一般是72MHzUSB时钟来自PLL的1.5分频也就是 72/1.548MHz。在CubeMX的Clock Configuration页面里把PLL Source选择为HSE倍频到72MHz然后检查USB Clock那个位置是不是48MHz。如果不是调整预分频让USB Clock变成48.0MHz。这一步错了设备插上电脑后要么没有任何反应要么设备管理器里出现黄色的“未知设备(Code 10)”图标。时钟配置好之后中间件部分需要开启USB设备。在Middleware and Software Packs里找到USB_DEVICE勾选启用然后在Class for FS IP下拉框中选择Communication Device Class (Virtual Port COM)。这就是虚拟串口的核心它让STM32在USB协议层模拟一个标准CDC类串口设备Windows不需要装额外驱动就能识别出COM口。最后在Project Manager里设置好工程名、路径和IDE我一般用MDK-ARM代码生成器选项里建议勾选“生成独立的.c/.h文件”这样改起来更清晰。2.2 修改产品描述符让Zadig和系统看到你的自定义名字生成工程后打开usbd_desc.c这是USB设备描述符的核心文件。不同CubeMX版本生成的代码略有差别但关键宏基本都在文件头部。默认情况下你会看到类似这样的定义#define USBD_VID 0x0483 #define USBD_PID 0x5740 #define USBD_LANGID_STRING 0x409 #define USBD_MANUFACTURER_STRING STMicroelectronics #define USBD_PRODUCT_STRING STM32 Virtual COM Port如果想让设备在Zadig列表里显示成自己的名字就把厂商字符串和产品字符串都改掉序列号也可以顺手改成一个固定值。比如#define USBD_LANGID_STRING 0x409 #define USBD_MANUFACTURER_STRING MyLab #define USBD_PRODUCT_STRING My STM32 Virtual COM这里有一点需要说明USBD_PRODUCT_STRING有些版本叫USBD_PRODUCT_FS_STRING原因是一个工程里可能同时定义了FS和HS两套字符串。你只需要找到实际被调用的那个宏并修改即可。改完之后重新编译烧录然后插上板子打开Zadig勾选Options - List All Devices下拉框里就能看到My STM32 Virtual COM。这说明描述符已经生效了。但请注意到了这一步设备管理器里显示的还不一定是这个名字。Windows的usbser.sys驱动有自己的显示逻辑它会按照大类统称这些设备所以你在设备管理器里大概率还是看到“USB 串行设备(COMx)”。别着急这是正常现象接下来的驱动替换和INF安装才是真正把名字钉死在设备管理器上的关键操作。3. Zadig重装驱动的关键操作与驱动选择3.1 三种驱动类型选错了COM口会消失用Zadig给STM32虚拟串口换驱动时会遇到几种驱动类型usbser、WinUSB、libusbK、libusb0。它们各有各的适用场景必须先搞清楚再动手。usbser是Windows自带的串口驱动加载后设备管理器里会生成COM口可以随便用串口助手打开收发数据。我们的最终目标其实是“让设备管理器显示自定义名称同时保留COM口”所以最终要绑定的还是usbser。WinUSB是微软提供的通用USB驱动加载后设备管理器里显示为“WinUSB device”整个设备已经不再是一个串口而是变成一个通用USB设备系统不会分配COM口。如果你想用WinUSB API或者libusb自己写上位机来和STM32通信选这个没问题但普通串口助手是打不开的。libusbK和libusb0是开源USB库提供的驱动适合配合libusb库使用同样不会保留COM口。所以结论很明确如果你想保持“虚拟串口”的易用性不要长期把设备切到WinUSB否则COM口就没了。但这不等于Zadig没用后面会讲到如何利用Zadig把设备驱动状态重置一遍再装回usbser从而让自定义INF生效。先把Zadig的基本操作流程走一遍。3.2 Zadig实操如何替换驱动以及如何恢复打开Zadig界面非常简洁。第一次使用的人经常遇到一个问题设备列表里找不到自己的STM32设备。这是因为Zadig默认不显示当前已有标准驱动的设备你需要点击菜单栏的Options勾选List All Devices。这时下拉框里就会列出所有USB设备包括被Windows当成未知设备的那部分。找到我们在CubeMX里设置的My STM32 Virtual COM确认右边显示的VID和PID是0483:5740如果你改过VID/PID就显示你自己的值。接下来在目标驱动那一栏选择你想切换的驱动。这里刻意不用“正确”或“错误”来形容因为要看你的目标如果你要为后续自定义INF做准备可以先选WinUSB然后点击Replace Driver。Zadig会提示即将替换驱动确认后等待完成。整个过程大概几秒钟。替换完成后打开设备管理器你会发现原来的COM口不见了取而代之的是一个名为“WinUSB device”的条目。这是正常的。如果后面想恢复成串口操作也很简单再次打开Zadig选中该设备在目标驱动下拉里选择usbser再点Replace Driver设备就会重新变成COM口。这一步在实际项目里很常用相当于一个“驱动状态重置开关”。有一点要提醒Zadig操作过程中必须用管理员权限运行否则会提示驱动安装失败。另外如果你电脑装了很多USB设备替换驱动前一定要确认选中的设备确实是自己的STM32不要顺手把鼠标键盘的驱动给换了虽然可以换回来但过程中鼠标可能短暂失灵挺闹心的。4. 定制专属设备管理器名称最稳的INF方案4.1 INF文件在Windows驱动体系中的角色Windows给USB设备分配驱动、显示名称的依据是INF文件。INF是一个文本文件里面描述了设备的VID/PID、要加载的驱动文件、设备类别、以及最重要的人类可读名称。你可以把它理解成一张“派工单”系统看到一个USB设备就去INF里查这个VID/PID应该怎么处理、显示什么名字。对CDC虚拟串口来说最稳妥的改名方案不是从零写一个驱动而是写一个“引用现有串口驱动、只改显示名称”的INF。这样做的好处是底层仍然使用微软签名的usbser.sys能保留COM口同时系统在设备管理器里显示的DeviceName是我们在INF里自己定义的文字。很多厂商的驱动比如ST官方驱动本质上就是这个思路。4.2 手写一个虚拟串口改名INF并安装下面给出一个可以直接套用的INF模板假设你的设备VID是0483PID是5740你想让设备管理器显示成“My STM32 Virtual COM”。[Version] Signature $WINDOWS NT$ Class Ports ClassGUID {4D36E978-E325-11CE-BFC1-08002BE10318} Provider %MfgName% DriverVer 06/26/2024,1.0.0.0 [Manufacturer] %MfgName%DeviceList,NTamd64 [DeviceList.NTamd64] %DeviceName%USB_Install, USB\VID_0483PID_5740 [USB_Install] Include usbser.inf Needs USBSER_Install [USB_Install.Services] Include usbser.inf Needs USBSER_Install.Services [Strings] MfgName MyLab DeviceName My STM32 Virtual COM这个INF文件的关键点是Class必须设为Ports这样设备管理器里会归类到“端口(COM和LPT)”下USB_Install段通过Include和Needs引用了系统自带的usbser.inf中的安装流程这样不需要自己拷贝任何驱动文件系统会加载标准的串口驱动而设备管理器右侧显示的设备名称则由[Strings]段里的DeviceName决定。安装这个INF有两种方式。第一种是在INF文件上右键选择“安装”但这种方式往往只在设备处于“未安装驱动”状态时有效如果设备已经被系统识别成“USB 串行设备”直接右键安装很可能会提示“指定位置不包含有关硬件的信息”。第二种方式是我强烈推荐的先用Zadig把设备切到WinUSB然后再打开设备管理器找到那个变名后的设备右键选择“更新驱动程序”接着选择“浏览我的电脑以查找驱动程序”再点“从磁盘安装”选中你写的INF文件。这时Windows会读取INF里的VID/PID匹配信息加载串口驱动设备管理器里的名称就会变成INF里指定的“My STM32 Virtual COM”并且后面还会带上系统分配的COM号。关于数字签名问题这里多说一句。因为INF里引用的是系统自带的usbser.inf驱动本体是微软签名的所以Windows 10/11通常不会报签名错误。但如果你改了驱动本体或者用了未签名文件就可能遇到“第三方INF不包含数字签名信息”的提示。个人实验时可以重启进入“禁用驱动程序强制签名”模式后安装但正式给客户批量用建议还是走签名流程或者沿用系统自带驱动。4.3 用Zadig“绕一圈”安装法的原理与实测效果实际操作中我发现一个现象如果设备当前已经绑定了usbser.sys你打开设备管理器想手动更新驱动到自定义INF很多情况下会失败系统会提示“已安装最适合该设备的驱动程序”压根不给你换。这时候Zadig的价值就体现出来了。我的常规套路是先用Zadig把设备替换成WinUSB驱动这一步能强制清掉Windows对“USB 串行设备”这个名称的驱动缓存。然后不需要急着用INF而是再次打开Zadig把目标驱动选回usbser同时把INF文件准备好。注意不要直接在Zadig里切回因为Zadig切回usbser时用的是系统默认的INF设备管理器还是会显示“USB 串行设备”。正确做法是Zadig切到WinUSB之后去设备管理器手动安装我们的自定义INFWindows在更新驱动的过程中会识别到新的INF并按照这个INF重新加载usbser.sys。这一步我多次在不同电脑上实测成功率非常高。原因推测是Windows在加载WinUSB后原来的设备实例被删掉重建系统回不到“已经选择过默认驱动”的状态只能老老实实按照用户指定的INF重新匹配。类似的思路也适用于CH340、CP2102等USB转串口芯片的改名只不过那些芯片的INF结构不同需要单独适配。5. 实战排查设备管理器名称不生效的常见坑5.1 常见问题速查表在实际操作中最让人头疼的不是操作步骤看不懂而是做完之后设备管理器里还是老样子。为了节省大家时间我把过去踩过的、以及帮朋友排查过的典型问题整理成了表格。现象可能原因解决办法插上板子后设备管理器出现“未知设备”或Code 10USB时钟不是48MHzPA11/PA12引脚配置冲突晶振没起振检查CubeMX时钟树确保USB Clock为48MHz检查整体工程引脚配置用示波器或逻辑分析仪确认晶振工作Zadig下拉框里找不到STM32设备设备没有被Windows枚举到Zadig没勾选“List All Devices”USB口供电不足勾选Options - List All Devices换个后端USB口直插重新插拔设备改了USBD_PRODUCT_STRINGZadig里还是旧名字设备管理器/系统缓存了旧描述符固件没烧录成功重新编译烧录拔掉USB线重新插设备管理器卸载设备后重新扫描在Zadig里刷新设备列表安装自定义INF提示“指定位置不包含有关硬件的信息”设备已经被系统用默认驱动绑定系统不认新INFVID/PID与INF不匹配先卸载设备并勾选“删除此设备的驱动程序软件”检查INF里的VID/PID是否正确用Zadig切换驱动后再装INF设备管理器名称没变还是“USB 串行设备”安装INF时系统仍沿用旧驱动缓存INF没安装成功按4.3节的“Zadig绕一圈”套路操作确认INF文件在64位系统的[DeviceList.NTamd64]段下有对应条目换完WinUSB后COM口不见了WinUSB不是串口驱动系统不会创建COM口如果想用串口收发数据用Zadig切回usbser或继续用自定义INF重装驱动多个同型号STM32板子插入设备管理器还是分不清产品字符串、序列号都相同Windows无法区分每块板子在usbd_desc.c里设置不同的USBD_SERIALNUMBER_STRING或不同的产品字符串然后再用INF分别为不同VID/PID或序列号定义不同名称5.2 几个容易被忽视的细节除了表格里的常见问题还有几个细节值得单独拿出来讲。第一个是关于设备描述符缓存的。USB设备描述符不是每次插上都会重新完整读取的Windows会对相同的VID/PID组合做缓存。如果之前这块板子插入过电脑你修改了产品字符串后再插上系统可能还是显示旧名字。解决办法是在设备管理器里找到对应的设备右键卸载并且在卸载对话框中勾选“删除此设备的驱动程序软件”然后重新插拔这样才能强制系统重新枚举并读取新的描述符信息。第二个是关于usbd_cdc_desc.c里的接口描述符。有些CubeMX版本生成的代码中USBD_PRODUCT_STRING虽然改了但设备管理器端口页里还是显示通用名这可能是INF文件需要同时匹配CDC的通信接口MI_00。如果你在设备管理器里看到设备被拆成了两个条目比如一个是“USB 串行设备(COMx)”另一个是“USB 输入设备”那就要考虑对INF进行更精细的接口匹配比如把设备路径写成USB\VID_xxxxPID_xxxxMI_00。不过对于大多数F103 CubeMX生成的CDC单接口设备前面给出的完整INF模板已经够用。第三个是COM号乱跳的问题。就算名称显示对了如果系统把COM号从COM5一会儿跳到COM10照样心烦。这里可以用一个小技巧设备管理器里选中设备右键进入“属性 - 端口设置 - 高级”然后指定一个固定的COM端口号。这个操作不需要改注册表也不用写脚本Windows会记住设备实例和COM号的绑定关系。如果你的设备被识别成未知设备无法进入端口设置页面那就要先解决驱动安装问题再回来固定COM号。6. 一点实操心得和进阶技巧按我自己的开发习惯现在只要是自研USB板子都不会让设备管理器里出现一堆“USB 串行设备”。一套顺手的工作流CubeMX里把VID/PID改成自己专门申请或内部统一的编号同时修改产品字符串和序列号工程代码里预留好版本号字段烧录后用Zadig配合一个写好的INF模板完成驱动替换和名称定制。整个过程在工程配置好的前提下换一块新板子只需要两三分钟。如果要给客户交付我会把自定义INF文件连同烧录器固件一起打包客户插上设备后只需要手动更新驱动就能看到专属名称体验好很多。不过要注意改VID/PID这件事是有讲究的。如果产品要过USB-IF认证VID需要正式申请如果只是自己玩或者内部使用用默认的0483/5740倒也不影响操作。但一旦同一台电脑上插了多块同VID/PID的设备区分度就会变差所以序列号字符串最好每台都不同可以在固件里用芯片唯一ID比如F103的96位UID来生成序列号字符串这样Windows里就能精确区分每一台设备。最后分享一个注册表层面的进阶玩法适合想彻底统一设备名称和COM号的朋友。在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\VID_0483PID_5740\设备实例路径下可以找到FriendlyName和PortName等值。手动修改这些值后设备管理器里显示的名称和COM号会跟着变。这个方法比INF更“暴力”改之前一定要备份注册表而且设备更新驱动后可能被系统重置回去只能算临时方案。正常项目开发中用自定义INF一次配好才是长久之计。这篇内容写到这里核心的“STM32CubeMX配置虚拟串口 修改描述符 Zadig换驱动 自定义INF改名”四步流程已经完整走了一遍。从一个满屏“USB 串行设备”的状态到现在每块板子插上去都显示专属名字整个过程并不复杂关键是把每个工具背后的原理弄明白。按我这个流程操作你也能省掉在设备管理器里反复拔插USB线确认端口的痛苦。