资讯动态

Keil MDK中虚拟串口调试实战:从原理到场景全解析

发布时间:2026/9/29 7:07:28 来源:尧图企业网站定制
做嵌入式开发这些年串口一直是我调试路上最常用的“眼睛”。早期调STM32的时候手头板子没焊好、USB转TTL线只剩一根、上位机又催着联调那段时间我几乎天天跟Keil MDK和串口调试较劲。后来把虚拟串口这套玩法摸熟了才发现很多串口调试工作根本不需要等硬件齐全用Keil MDK配合虚拟串口完全可以把问题提前暴露在电脑上。这篇文章就把我的完整思路和实操记录整理出来覆盖虚拟串口的本质、Keil MDK工程的串口驱动准备、几种典型调试场景的完整配置以及我踩过的坑。不管你是刚入门串口通信的新手还是被printf没输出折腾过的老手应该都能找到可以直接照抄的套路。1. 先搞明白虚拟串口到底在虚拟什么1.1 串口调试的三个老大难问题串口调试最基础的流程大家都懂MCU的TX/RX引脚对外发数据通过USB转TTL芯片连到电脑电脑上开一个串口助手比如SSCOM、XCOM就能看到打印信息。这个流程看起来简单实际项目里却有非常多的约束。第一个问题是硬件资源不齐。我遇到过好几次板子只焊了MCU和电源部分串口芯片还没贴这时候USB转TTL插上去根本没法通信。第二个问题是上位机没就绪。很多时候嵌入式端和上位机是并行开发的嵌入式端想测串口发送但上位机连界面都没写出来。第三个问题是调试观察不透明。就算串口通了printf里只能看到“我打印出来的东西”但MCU内部某个变量在中断里被改成了多少、接收缓冲区的状态对不对光靠串口助手看不出来还得靠Keil MDK的调试器去看内存和寄存器。虚拟串口这招本质上是解决“数据通路不完整”或“数据通路不可观察”这两个矛盾。它在你现有条件的基础上用软件模拟出一条或者几条串口通道让你把串口调试工作拆开来做协议逻辑可以先验发送逻辑可以提前测接收逻辑可以在调试器里看状态。1.2 虚拟串口的几种常见形态我接触下来大家口中说的“虚拟串口”其实有好几种完全不同的形态用之前一定要分清楚。第一种是纯软件虚拟串口对代表工具有VSPD、com0com这类。它们会在电脑里创建一对互通的虚拟COM口比如COM3和COM4往COM3发数据COM4立刻就能收到。这对虚拟串口完全没有物理硬件参与数据在驱动层内部直接转发对应用程序来说和真实串口一模一样。这种形态最适合做PC端协议验证或者在没有串口硬件的情况下给上位机软件提供测试输入。第二种是调试器自带的虚拟COM口。比如ST-Link VCP、J-Link的Virtual COM功能、ULINKpro的虚拟串口它们的本质是调试器硬件里集成了USB转串口芯片目标板的UART通过调试器的USB口桥接到电脑上。这种虚拟COM口“虚拟”的只是物理位置数据是实打实从MCU的串口引脚出来的只是经过调试器转了一道USB。第三种是MCU自己通过USB枚举出来的虚拟串口也就是STM32的USB CDC类设备。PC端看到的COM口底层其实是USB包MCU端需要跑CDC协议栈。这种虚拟串口的“虚拟”程度最高低层通道完全不是UART所以你在Keil里不能再盯USART寄存器得去看USB接收缓冲区和CDC的状态。三种形态各有各的用途后面我会按实际调试场景展开说。先记住一点纯软件虚拟串口对适合在没有硬件时验证逻辑调试器虚拟COM口和USB CDC适合真实硬件调试只是走线不同。这篇文章说的“Keil MDK中使用虚拟串口调试串口”核心是第一种纯软件虚拟串口对和调试过程中的配合玩法。1.3 为什么在Keil MDK开发里虚拟串口特别好用我的体会是Keil MDK的开发流程本身就非常适合配合虚拟串口。因为MDK提供了完整的在线调试能力你可以随时打断点看寄存器而虚拟串口可以把串口数据引到一个可控的通道里两边一配合调试效率非常高。举个例子你在Keil里打开工程编译下载到板子板子的串口通过USB转TTL接电脑COM5。此时你想验证自己的自定义协议帧格式是否有问题但上位机还没写好。如果直接用串口助手手动发数据拼帧效率极低。这时候我用虚拟串口对在电脑里临时搭一个“模拟上位机”把测试数据按协议拼好通过虚拟串口发出去再用Keil的Watch窗口看MCU接收缓冲区的状态。整个链路非常透明。另外Keil MDK配合软件调试器比如ST-Link在线调试时调试器本身就占用了SWD接口但它不占用COM口资源所以串口和调试器可以同时工作。这一点很关键你既能通过串口收数据又能通过调试器看MCU内部的实时变量两者互不干扰。2. 方案选型不同调试场景配不同虚拟串口玩法2.1 场景一PC端纯协议验证用虚拟串口对这个场景我用的最多。嵌入式端和上位机端约定好一套协议比如帧头、命令字、长度、数据域、校验和。在上位机还没写好的时候我可以用两个串口助手分别打开虚拟串口对的两个端口在一边发送构造好的帧另一边接收验证。这样既能验证协议字段定义是否合理又能提前把校验代码的边界条件测出来。搭配Keil MDK的好处在于虚拟串口对的两端可以一端开串口助手、另一端用自己写的Python脚本自动化收发或者接一个真实串口设备的调试工具。这样PC端的协议栈逻辑可以在没有硬件的情况下先跑通等MCU端程序写完直接对接。具体软件上我推荐用VSPDEltima Virtual Serial Port Driver或者开源的com0com。VSPD界面比较直观点击Add pair就能创建一对COM口而且支持将真实串口Split成多个副本。com0com则是绿色免费配置稍微麻烦一点点。我自己的习惯是需要快速验证用VSPD需要跑自动化测试脚本时用com0com因为它在驱动层更稳定不容易被系统更新冲掉。2.2 场景二MCU代码还没完全就绪用ITM/SWO输出代替串口很多人在调Keil MDK工程时串口程序本身还没写好就想先用printf看某个变量。这时候其实不需要虚拟串口Keil MDK自带的ITM/SWO机制反而更方便。STM32的SWO引脚也就是SWD接口里的SWO信号可以把MCU内部的数据实时输出到调试器再通过Keil的Debug (printf) Viewer窗口显示出来。你只需要在代码里用ITM_SendChar()或者重定向fputc到ITM通道然后打开Keil的View - Serial Windows - Debug (printf) Viewer再去调试设置里把Trace的时钟源、SWO频率配置好就能在不占用任何串口引脚的情况下看到printf输出。这个机制和虚拟串口是互补的。它的优势是不需要串口硬件、不占UART引脚缺点是没办法通过串口往MCU发数据SWO是单向的而且对调试器的Trace能力有要求便宜的ST-Link V2不少阉割了SWO功能J-Link和ST-Link V3.0以上支持比较好。我一般在前期逻辑调试用ITM中后期联调用真实串口加虚拟串口对。2.3 场景三多个工具要同时读写同一个串口用虚拟串口分线器项目后期常常会遇到这种情况开发板串口接在电脑COM5上串口助手里要开着COM5看日志但我又想同时用另一个工具写一个自动化脚本往里发指令或者想让同事的网络调试工具也连上来。真实串口的布局是“一对一”的一个COM口同一时间只能被一个应用程序打开。这时候就用到了虚拟串口的分线功能。VSPD之类的高级版支持把物理串口Split成多个虚拟COM口比如把COM5拆出COM6、COM7应用程序分别打开COM6和COM7看到的都是COM5同一路数据。这样就实现了“一进多出”类似一个串口集线器。用这个方案串口助手的日志窗口、自动测试脚本、甚至远程调试工具可以各开各的互不占用、互不干扰。前提是物理串口和虚拟串口发的数据方向要对Split出去的口默认是双向转发。2.4 场景四STM32 USB虚拟串口调试如果你的目标MCU自带USB比如STM32F103C8T6还可以直接把USB配置成CDC虚拟串口。PC端装好ST官方VCP驱动后识别成一个COM口数据从MCU的USB D/D-引脚进出。这种方式的“虚拟”程度很高USB CDC协议栈里有TX缓冲区、RX缓冲区还要处理USB的枚举和端点传输。在Keil MDK里调试这类工程时我提醒大家别再盯着USART寄存器了要看USB_CDC_RxBuffer这类协议栈变量。我见过不少人在调试自制的USB虚拟串口时代码里写的是HAL_UART_Transmit实际上MCU的USB虚拟串口根本不走UART外设数据链路完全不对。这种场景下虚拟串口调试的核心是PC端的COM口收发是否正常、MCU端CDC的回显缓冲是否溢出两块分开排查。3. Keil MDK工程串口驱动怎么写才能方便调试3.1 USART外设初始化要点不管后面用不用虚拟串口MCU端的串口驱动本身必须写对。以STM32F1系列为例用标准外设库初始化一个USART1通常包含这几部分开启GPIO和USART时钟配置PA9为复用推挽输出TXPA10为浮空输入RX然后设置USART的波特率、数据位8位、停止位1位、无校验位、使能发送和接收、使能接收中断。下面是标准外设库的初始化代码我每次新建工程都会先写好这一个模板void UART1_Init(uint32_t baudrate) { GPIO_InitTypeDef gpio; USART_InitTypeDef usart; NVIC_InitTypeDef nvic; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE); GPIO_StructInit(gpio); gpio.GPIO_Pin GPIO_Pin_9; gpio.GPIO_Mode GPIO_Mode_AF_PP; gpio.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, gpio); gpio.GPIO_Pin GPIO_Pin_10; gpio.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, gpio); USART_StructInit(usart); usart.USART_BaudRate baudrate; usart.USART_WordLength USART_WordLength_8b; usart.USART_StopBits USART_StopBits_1; usart.USART_Parity USART_Parity_No; usart.USART_Mode USART_Mode_RX | USART_Mode_TX; usart.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_Init(USART1, usart); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); nvic.NVIC_IRQChannel USART1_IRQn; nvic.NVIC_IRQChannelPreemptionPriority 1; nvic.NVIC_IRQChannelSubPriority 0; nvic.NVIC_IRQChannelCmd ENABLE; NVIC_Init(nvic); USART_Cmd(USART1, ENABLE); }这段代码有几个容易被坑的地方。第一GPIO模式必须分清TX引脚是复用推挽输出不是普通推挽输出写错的话数据发不出去或者波形不对。第二RX引脚通常配置成浮空输入但如果硬件上有外部上下拉电阻必须结合原理图改成上拉或下拉输入否则会出现接收数据字节错位甚至乱码。第三中断优先级不能遮遮掩掩如果项目里同时用SysTick做延时要保证USART中断优先级小于主循环里的临界区保护逻辑不然会出现数据丢失。3.2 printf重定向虚拟串口调试的前置条件用虚拟串口调试本质上还是看串口收发数据所以printf重定向是绕不开的。很多人卡在这里明明串口通了但串口助手收不到任何东西。大多数情况是printf没有被正确重定向到串口发送函数。在Keil MDK中做printf重定向有两个必要条件。第一是勾选MicroLIB路径在Options for Target - Target - Code Generation - Use MicroLIB这个选项会启用一个精简版的C库它不需要实现完整的fputs、fwrite只要实现fputc就行。第二是在工程里写一个fputc函数把标准输出重定向到USARTint fputc(int ch, FILE *f) { while ((USART1-SR USART_SR_TXE) 0); USART1-DR (uint8_t)ch; return ch; }注意这个函数里的等待循环。USART_SR_TXE位表示发送数据寄存器为空但发送数据寄存器为空不代表数据已经全部移出移位寄存器。如果下一步马上切换GPIO模式或者进入低功耗模式最后一字节可能没发完。在简单测试中影响不大但在做精度要求高的调试时我习惯把等待条件改成USART_SR_TC发送完成位确保整个帧彻底发完。如果用的HAL库写法类似只需要调用HAL_UART_Transmitint fputc(int ch, FILE *f) { HAL_UART_Transmit(huart1, (uint8_t *)ch, 1, 0xFFFF); return ch; }这里注意第二个参数的指针类型HAL_UART_Transmit接收的是uint8_t*直接取ch地址会报警告我一般先强转。另外超时时间不要设0否则在串口繁忙时可能立即返回导致丢字符。3.3 给调试预留一个“万能打印通道”实际项目中调试打印不应该直接到处写printf否则后期去掉调试信息是个大工程。我的习惯是在工程里封装一个调试输出模块用宏来控制#define DEBUG_UART_ENABLE 1 #if DEBUG_UART_ENABLE #define DBG_PRINT(fmt, ...) printf([DBG] fmt \r\n, ##__VA_ARGS__) #else #define DBG_PRINT(fmt, ...) #endif这样在代码里用DBG_PRINT(state%d, len%d, state, len)输出正式版直接把DEBUG_UART_ENABLE置0所有打印自动消失不用一行一行删。配合虚拟串口调试时DBG_PRINT输出的每一行最好带时间戳或模块名这样在串口助手里看日志能快速定位是哪个模块打出来的。串口接收这边也一样我建议不要在主循环里用阻塞轮询方式读串口而是加一个简单的环形缓冲区。中断里只负责把数据放进去主循环或者协议解析任务再取出数据这样调试时不容易丢数据也方便在虚拟串口调试时观察缓冲区的使用情况。4. 实战流程从虚拟串口对到完整串口调试4.1 步骤一创建虚拟串口对先验证PC端收发假设我现在要验证一个自定义通信协议帧头0xA5、1字节命令字、2字节长度、数据域、1字节累加校验和。上位机还没写好我先把PC端的协议解析逻辑用Python脚本跑通。首先安装VSPD打开后点Add pair创建一个COM3和COM4的虚拟串口对。VSPD的原理是在Windows驱动层模拟两个串口的物理连接COM3发数据COM4收到反过来也一样。创建完成后我的电脑上就多出了两个COM口虽然它们背后没有真实硬件。接着用Python脚本验证协议代码大概是这样import serial ser serial.Serial(COM3, baudrate115200, timeout0.5) def build_frame(cmd, data): payload bytes([0xA5, cmd, len(data) 0xFF, (len(data) 8) 0xFF]) data checksum sum(payload) 0xFF return payload bytes([checksum]) send build_frame(0x01, bytes([0x10, 0x20, 0x30])) ser.write(send) resp ser.read(64) print(recv:, resp.hex())对应地在另一个工具比如串口助手打开COM4就能看到COM3发来的数据帧。这时候不需要任何硬件PC端的协议构造和解析逻辑已经被我验证了一遍。这个步骤为后面MCU联调省了大量时间因为协议本身的bug已经排掉了。4.2 步骤二在Keil MDK里编译烧录把MCU串口接进电脑PC端验证完成接下来才是Keil MDK登场的时候。我在Keil里打开串口工程确认代码无误后点击编译用ST-Link下载器烧录到STM32板子里。目标板的USART1通过USB转TTL线接入电脑假设设备管理器里看到的是COM5。这时候的调试结构是MCU的TX/RX - USB转TTL - 电脑COM5 - 串口助手显示。打开串口助手选择COM5波特率设为115200数据位8、停止位1、无校验打开端口。串口助手必须设置成和MCU代码里的USART配置一致否则看到的就是乱码。如果你手头只有一个USB转TTL但又想同时用串口助手和自动化脚本去操作COM5这时候就要用到前面说的虚拟串口分线功能。VSPD里选择COM5的Split克隆出COM6、COM7这样COM6开串口助手收日志COM7跑自动化脚本发指令两个工具同时对COM5进行操作也不会冲突。4.3 步骤三用Keil在线调试观察串口内部状态串口助手能看到数据只是说明数据通道通了。真正要排查问题时得进入Keil的在线调试模式。我一般这么做点击Debug按钮进入调试然后在USART1_IRQHandler中断服务函数里打断点或者直接在主循环里协议处理函数处打断点。当串口收到数据时程序会在断点处停下这时候我打开View - Watch窗口添加uart_rx_buf、uart_rx_head、uart_rx_tail这些变量实时观察缓冲区状态。配合Debug (printf) Viewer窗口甚至可以在线查看某个局部数组的内存内容。这一步是真实硬件调试的利器也是Keil MDK相比其他IDE最大的优势之一。需要注意进入调试模式后勾选了Reset and Run的话程序会自动跑起来否则点一次运行。有些新手会发现进调试模式后串口助手收不到数据其实是代码停在某处断点没运行不是串口的问题先全速运行看看。4.4 步骤四构建一个带虚拟串口的完整联调环境项目后期上位机也写好了嵌入式端也稳定了这时候我习惯搭一个更完整的联调环境把虚拟串口对嵌进链路里做“中间人”。具体做法是用VSPD创建COM10/COM11虚拟串口对再让串口助手的接收端打开COM10而另一个程序比如自己写的串口转发脚本打开物理COM5和COM11把COM5收到的数据转发到COM11再进入虚拟串口对被COM10接收。这样串口助手看到的数据其实是物理串口经过转发后的数据中间可以插入过滤、加时间戳、甚至模拟丢帧等操作。这种玩法的价值在于你能在PC端注入一些MCU端不方便模拟的异常情况比如随机的坏帧、超长帧、满缓冲区的情况用来测试上位机的健壮性。在Keil MDK工程不变的情况下把通信链路的“故障注入点”放到了电脑里。我经常用这个思路做回归测试比每次改MCU代码再去烧录高效得多。5. 常见问题与排查技巧5.1 printf没输出先从这几个地方查printf没有输出是串口调试里最经典的问题。我总结的排查顺序是先看工程有没有勾选MicroLIB没勾的话fputc可能不被调用再看代码里有没有重定义fputc很多人的fputc和标准库的底层函数冲突编译报错然后看串口初始化是否在printf之前完成如果main里先printf后初始化串口输出自然丢了。另一个容易忽略的是缓冲区问题。printf默认是行缓冲或全缓冲串口助手那边可能没看到数据但程序已经跑过去了。用MicroLIB后printf一般没有缓冲但如果用的是标准库可以在重定向代码里加上setvbuf(stdout, NULL, _IONBF, 0)关闭缓冲让每个字符立即发出。实测下来加上这行比不加更稳。5.2 乱码问题八成是波特率或时钟配置出问题串口助手收到乱码先别急着怀疑虚拟串口软件按下面的顺序排查。第一波特率是否一致MCU代码里的USART_BaudRate和串口助手设置的是否一样。第二数据位、停止位、校验位是否一致常见的是两边都为115200 8N1但有一边设成了9位数据乱码就出现。第三MCU的时钟频率是否和初始化代码里的配置匹配比如STM32F103C8T6板载8MHz晶振但没有做倍频到72MHz串口初始化时按72MHz计算波特率就会产生偏差可能显示出来是乱码。用USB转TTL芯片时还要注意CH340之类的驱动版本。Windows更新后驱动被替换成系统自带的旧版偶尔会出现丢字符或乱码直接在设备管理器里更新驱动为CP210x或CH340官方版本即可。虚拟串口对之间的乱码一般是波特率参数不匹配大多数虚拟驱动不检查波特率但有的版本会做校验两边必须配置一致才给发数据。5.3 COM口冲突物理串口和虚拟串口打架Keil MDK在线调试时有时候会提示无法连接ST-Link排查半天发现目标板的COM口号和设备管理器的驱动被占用。原因是有些调试器在固件升级模式下会虚拟一个COM口Keil误把这个COM口当作串口工具使用了。我遇到过一次ST-Link插上后出现在设备管理器里的COM12同时VSPD里我也创建了一个COM12结果是两个驱动抢同一个端口号导致串口助手打开COM12时一直失败。解决办法很简单在VSPD里把虚拟串口的编号改成COM12以上的空闲号比如COM35并确保设备管理器里没有重名端口。养成一个好习惯创建虚拟串口对时端口号从COM20以后开始用避免和USB转TTL的自动编号冲突。5.4 虚拟串口对创建成功但收发不到数据VSPD或者com0com创建好虚拟串口对后两边都打开了但A端发数据B端收不到。这种问题最常见的原因是驱动安装权限不足软件提示创建成功实际上驱动没有加载。解决办法是以管理员身份运行VSPD重启一次系统让驱动服务真正启动。另一个原因是串口助手缓存导致的数据显示延迟。有些串口助手要手动暂停或清空显示数据其实已经收到了只是界面没刷新。遇到这种情况先看串口助手的“接收计数”有没有增加如果计数在涨但界面不显示换个串口助手比如XCOM就好。com0com在Win10/11的某些版本上也有兼容问题表现为创建的COM口在设备管理器里是感叹号需要去com0com的安装目录里运行setup_c.exe重新设置端口号或者直接换成VSPD。5.5 Keil调试器连接失败先看调试器和串口的关系用Keil MDK在线调试时ST-Link虽然不直接占用物理串口但如果项目里开启了RTE的Event Recorder功能调试器可能会和串口有冲突。Event Recorder需要调试器的ITM通道而ITM的SWO引脚在不同板子上可能和某个UART引脚复用这时候串口调试和调试器会互相干扰。我的建议是前期跑通串口通信时不用勾选Event Recorder只用DAP或ST-Link的基础SWD调试功能。等到需要Event Recorder分析RTOS调度时再把串口调试暂时关闭两边分开调试避免抢占SWO引脚。遇到连接失败时先检查Keil的Debug设置里Port选的是SW还是JTAGST-Link V2大多数只支持SW模式如果选错了也会连接失败。6. 进阶玩法与使用心得6.1 把虚拟串口和自动化脚本结合起来做回归测试我的调试工作流后期基本是这样的每次改完协议解析代码先编译下载到板子然后跑一段自动化Python脚本通过物理串口发送预置的测试帧组再把MCU的响应收回来和期望值对比。这个流程在PC端用虚拟串口分线功能作为中转能同时记录日志和运行断言跑完直接给出结果。举个例子我需要对一个Modbus协议的从机程序做回归测试写一个Python脚本循环发送10种不同功能码的请求帧每帧之间间隔50ms然后把响应帧解析出来检查错误码是否合理。脚本跑一次大概几秒钟比手动在串口助手点发几千次靠谱得多。虚拟串口对在这里的作用是提供一个“可编程的串口链路”脚本写在COM11端物理串口COM5端接到MCU利用虚拟串口把协议数据流汇聚和分发。实际测试中我遇到过脚本发送过快导致MCU接收缓冲溢出丢帧的情况。这时候把脚本的发送间隔从10ms调大到200ms问题就消失了。由此我也悟出一个经验自动化测试的发送速率必须放在真实链路下验证虚拟串口的仿真环境无法完全模拟硬件的实时性。6.2 几个让我效率翻倍的虚拟串口调试小习惯第一串口助手的显示格式统一设置为“十六进制”看数据帧文本格式方便看printf日志。两个用途分开不要混在一个窗口里不然日志和数据帧搅在一起很难看。第二每次创建虚拟串口对之后顺手在VSPD里加备注说明这组端口是给哪个项目用的不然项目一多COM号根本对不上。第三USB转TTL线的型号尽量固定我用CP2102和CH340的线各一根但绝不混用因为两家的驱动在Windows下的行为有细微差别混用时会莫名出现串口打不开。还有一个值得说的小技巧如果你在Keil MDK的调试脚本里会用到串口输出可以在MDK的Command窗口里输入SWO相关命令查看Trace状态或者在Debug (printf) Viewer窗口右键选择“Show Timestamps”给每条打印信息加上时间戳。我后来排查一个时序问题时就是靠这个时间戳功能定位到两个模块之间相差了300多毫秒比用逻辑分析仪还直观。6.3 虚拟串口调试解决不了的还是得靠真实硬件说了这么多虚拟串口的优势最后我还是想泼一点冷水虚拟串口能帮你验证协议逻辑、能让你在没有硬件时提前开发、能让你在调试时多开几个观察窗口但它无法替代真实物理链路的时序验证。波特率的微小偏差、串口线路上的信号反射、USB转TTL芯片驱动对高波特率的支持能力、MCU在低功耗模式下串口唤醒的时序这些问题只有在真实硬件上才能暴露。所以我的使用原则是前期逻辑开发和协议调试大胆用虚拟串口中后期硬件联调和可靠性测试回归真实硬件。两者之间的关系不是替代而是互补。理解这一点键盘上的每一行代码和调试器里的每一个观察窗口才能真正帮你把串口这个老牌外设吃透。最后分享一个小经验每次调试结束后我会把虚拟串口对删除掉VSPD里Remove pair保持电脑的串口环境干净。因为虚拟串口驱动在系统里会常驻服务占用资源不说还可能与下次插入的新硬件串口号冲突。这个习惯帮我避免过好几次“串口明明没被占用却打不开”的诡异问题。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑