十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

Ubuntu下USB转串口设备ttyUSB0缺失的排查指南

Ubuntu下USB转串口设备ttyUSB0缺失的排查指南 上周帮朋友调一块T113开发板他把USB转TTL模块插到Ubuntu主机上minicom打开ttyUSB0时直接报“No such file or directory”但同一块板子在Windows设备管理器里明明能看到COM3。这个现象在嵌入式开发里太常见了设备在Windows下有驱动到了Ubuntu下却没有生成对应的设备文件。其实大多数情况下并不是板子坏了也不是串口芯片挂了而是驱动、权限、USB枚举、设备命名这几个环节里有某一环出了问题。这篇文章我就把这个完整的排查链路拆开讲清楚。无论你用的是STM32F407VE、ESP32、正点原子RK3588、K230还是泰山派开发板只要是通过串口连Ubuntu排查思路完全一样。内容会覆盖USB枚举、内核驱动的加载与缺失处理、/dev目录下的设备命名规则、权限配置、TTL电平接线、回环测试以及最后如何用udev固定设备名一次性解决插拔后ttyUSB0漂移的问题。1. 插上USB却看不到设备先分清板子串口的两种引法1.1 USB串口和TTL排针串口的区别很多人一上来就执行ls /dev/ttyUSB*没输出就发帖问“是不是开发板有问题”。我建议先冷静下来看一眼你手上的板子到底属于哪种串口形态。第一种是板载USB转串口芯片。典型代表是ESP32 DevKitC板子上的CP2102或者STM32F407VE板上常见的CH340G。这类板子直接用USB线连电脑板上那颗USB转UART芯片会把串口信号转换成USB协议计算机侧枚举出一个串口设备。在Ubuntu上正常情况下内核会加载对应驱动并生成/dev/ttyUSB0或/dev/ttyACM0。第二种是TTL排针引出。很多核心板比如T113、RK3588底板、K230板上并没有USB转串口芯片只是用一个4pin或6pin排针把UART0的TX、RX、GND、VCC引出来。这时候你需要外接一个USB转TTL模块CH340G、CP2102、FT232都行用杜邦线把模块和板子连起来再把模块的USB端插到电脑上。这两种形态的排查方向差别很大。第一种的问题大概率出在USB枚举、驱动加载、权限配置第二种除了同样的软件链路还多了一个“杜邦线接对了没有”的硬件问题。我见过太多人拿着第二种板子以为USB线直接插开发板就能出ttyUSB0结果插的是板子的纯供电口当然什么都找不到。1.2 “找不到设备文件”不等于“设备没被识别”还有一个非常反直觉的点设备文件是内核驱动绑定成功之后才创建的不是USB设备一插上就自动出现。USB设备枚举成功后内核会根据VID/PID去匹配驱动驱动绑定成功、probe函数执行完毕才会调用tty_register_driver在 /dev 下创建设备节点。所以“/dev/ttyUSB0不存在”的本质是驱动没绑定成功或者绑定后没有成功注册tty设备而不是“这个USB设备不存在”。另外有经验的开发者都知道Linux下串口设备不一定叫ttyUSB0。有些芯片走的是CDC ACM协议比如部分STM32板载调试芯片、ESP32-C3/C6板载串口芯片它们注册出来的是/dev/ttyACM0。如果只用ls /dev/ttyUSB*去搜看到ttyACM0也可能被忽略误以为没有生成设备文件。2. 标准三步定位lsusb、dmesg、/dev目录对照着看2.1 先跑lsusb确认USB层有没有枚举到设备这是整个排查链路的第一步也是最快能缩小范围的一步。把USB转串口模块或开发板插上然后在终端里执行lsusb正常情况下你会看到类似这样的输出Bus 001 Device 004: ID 1a86:7523 QinHeng Electronics CH340 serial converter如果是FTDI芯片大概是Bus 001 Device 005: ID 0403:6001 Future Technology Devices International, Ltd FT232 Serial (UART) ICCP2102芯片则显示为10c4:ea60。如果lsusb里压根没有新设备问题基本可以锁定在物理层要么是USB线只供电不传数据要么是插的USB口根本没有连接芯片要么是虚拟机环境下没有把USB设备直通给Ubuntu。如果lsusb能看到设备但 /dev 下没有对应的tt文件那就是驱动或者内核配置的问题进入下一步。2.2 再看dmesg驱动加载过程一目了然lsusb只能说明USB设备被枚举了不能说明驱动有没有绑定成功。想看驱动层发生了什么用dmesgdmesg | grep -i tty dmesg | grep -i usb正常的加载过程会看到类似这样的日志usb 1-2: new full-speed USB device number 4 using xhci_hcd usb 1-2: New USB device found, idVendor1a86, idProduct7523 usb 1-2: New USB device strings: Mfr1, Product2, SerialNumber0 ch341-uart converter now attached to ttyUSB0最后一行ch341-uart converter now attached to ttyUSB0是关键信号。它表示驱动已经识别芯片并且成功注册了ttyUSB0这个设备节点。如果lsusb能看到设备但dmesg里只有USB枚举的信息没有出现“attached to ttyUSB0”这样的字段那就说明内核没有匹配到驱动。后面第4章会细说怎么处理。2.3 最后才看/dev设备名和符号链接要认全确认驱动加载成功后再看设备节点ls -l /dev/ttyUSB* /dev/ttyACM*输出类似crw-rw---- 1 root dialout 188, 0 1月 21 10:30 /dev/ttyUSB0注意这里的权限位是crw-rw----所属组是dialout。当前用户如果不在dialout组里即使设备文件存在open的时候也会报Permission denied。这是后面第3章的内容。另外有些发行版或者自定义桌面环境可能在 /dev/serial/by-id/ 下生成符号链接比如ls -l /dev/serial/by-id/如果你的板载USB转串口芯片有唯一的序列号这里会生成一个稳定路径这个特性在后面第6章固定设备名时会用到。3. 设备文件在却连不上权限问题常被忽略3.1 检查当前用户是否在dialout组里设备文件都已经存在了但minicom、screen、tio这些工具打开串口的时候仍然失败终端提示类似minicom: cannot open /dev/ttyUSB0: Permission denied这种情况九成是权限问题。查看一下设备文件的属组stat -c %G /dev/ttyUSB0标准Ubuntu系统里通常是dialout。再把当前用户加进去sudo usermod -aG dialout $USER需要注意usermod对已经登录的会话不会立即生效。你可以注销重新登录也可以在当前终端执行newgrp dialoutnewgrp会临时切换当前会话的组身份立即生效不用重启排查问题非常方便。3.2 用udev规则直接放开读写权限如果你觉得每次都要关注用户组太麻烦也可以写一条udev规则让系统在识别到串口设备时直接把权限改成666sudo nano /etc/udev/rules.d/99-usb-serial.rules写入KERNELttyUSB[0-9]*, MODE0666 KERNELttyACM[0-9]*, MODE0666保存后重载规则sudo udevadm control --reload-rules sudo udevadm trigger这一步做完不需要重启重新插拔一次USB转串口模块/dev/ttyUSB0的权限就会变成crw-rw-rw-任何本地用户都可以直接读写。有一点必须提醒MODE0666 意味着所有用户都能访问这个串口设备。在个人开发机上问题不大但如果是多人共用的服务器这样放开会存在安全隐患建议还是用dialout组管理不要图一时省事。4. CH340、CP210x、FTDI驱动缺失时的处理方案4.1 先对照芯片型号确认该由哪个内核模块接管USB转串口芯片型号非常多但Ubuntu下常见的就那几类对应的内核模块也基本固定。芯片型号USB VID:PID内核模块设备节点CH340 / CH3411a86:7523 / 1a86:5523ch341ttyUSB0CP2102 / CP210x10c4:ea60cp210xttyUSB0FTDI FT232R / FT22320403:6001 等ftdi_siottyUSB0PL2303067b:2303pl2303ttyUSB0CDC ACM类芯片各不相同cdc_acmttyACM0拿到开发板之后先用lsusb确认VID和PID然后对号入座。我之前遇到过有人拿一颗CH340芯片却一直在网上找cp210x的驱动折腾了半天其实内核日志早就告诉你1a86:7523是CH340了。4.2 模块没加载时先modprobe再考虑编译现代Ubuntu内核20.04以上默认已经把常见USB转串口驱动编译成模块了。模块没加载一般是因为系统启动时没有自动modprobe或者手动卸载过。先看看模块状态lsmod | grep ch341 modinfo ch341如果modinfo能打印出模块信息说明内核里自带这个驱动只是没加载直接sudo modprobe ch341加载完再dmesg确认。每次开机都要手动加载的话可以把模块写入/etc/modulesecho ch341 | sudo tee -a /etc/modules如果你的Ubuntu是精简安装或者自己编译过内核、把串口驱动裁剪掉了modinfo会提示找不到模块。这时候才需要从源码编译。编译前先装好内核头文件sudo apt install linux-headers-$(uname -r) build-essential然后从芯片厂商或开源仓库下载对应驱动源码比如CH340系列常见的是ch341开源驱动FTDI官方也提供Linux驱动源码。编译安装后用modprobe加载。但我个人建议不到万不得已不要走这一步。Ubuntu官方内核的驱动模块覆盖率其实非常高99%的情况modprobe就能解决手动编译反而容易遇到内核签名、头文件版本不一致这类新问题。4.3 虚拟机环境和“开发板挂载Ubuntu”的概念澄清用VMware或VirtualBox跑Ubuntu做开发的人经常遇到一个诡异情况Windows宿主机的设备管理器里能看到COM口但虚拟机里的lsusb什么都看不到。这通常不是驱动问题而是USB设备没有直通给虚拟机。VMware Workstation的操作右键虚拟机 → 设置 → 硬件 → USB控制器确认USB兼容性选的是USB 3.1或更高然后在“USB设备”里勾选“自动连接新USB设备”。插入USB转串口后如果右下角弹窗提示连接到虚拟机或宿主机一定要选虚拟机。VirtualBox则要先安装Extension Pack否则只支持USB 1.1设备大部分USB转串口芯片会枚举失败或工作不稳定。还有一个容易搞混的概念热词里常有人说“开发板挂载Ubuntu”指的是开发板自己跑Ubuntu系统用SD卡启动然后通过串口看启动日志。在这个场景下我们调试用的ttyUSB0是“宿主机这边”看到的设备节点开发板自己Linux系统里看到的是/dev/ttyS0、/dev/ttyS1或/dev/ttyAMA0。如果开发板系统里没有串口输出那是设备树中UART节点没使能或者uart时钟没配好的问题宿主机这边就算把lsusb和dmesg翻个底朝天也查不出原因。别把这两个层面混在一起。5. 硬件层面排雷接线、回环测试和线材的坑5.1 TTL串口接线的三个常见错误软件链路全部正常设备文件也有但串口终端就是没有任何输出这时候大概率是硬件接线出了问题。外接USB转TTL模块连接开发板排针标准接法是USB转TTL模块的TX → 开发板的RXUSB转TTL模块的RX → 开发板的TXGND → GND第一个常见错误是TX和RX接反。很多人下意识认为TX接TX、RX接RX实际上串口是交叉连接。接反了不会报错设备文件照常生成但就是收不到数据。这里有个快速判断方法用示波器或者万用表量一下TX引脚串口空闲状态应该是高电平如果有数据发送时会看到电平跳动。第二个错误是把VCC也接上去了。USB转TTL模块上的VCC引脚是用来给外部设备供电的有些模块默认跳线是5V而开发板主控IO可能是3.3V。一旦把5V接到开发板的3.3V供电网络轻则电平不匹配导致通信乱码重则直接烧掉板载LDO甚至主控芯片。接入之前一定要确认开发板使用的是3.3V还是5V逻辑。第三个坑是电平不匹配。USB转TTL模块多数支持3.3V和5V切换通常有一个跳线帽或者拨码开关。如果模块的跳线设置在5V而开发板是3.3V逻辑串口通信会不稳定甚至出现乱码。务必把模块跳到3.3V档位再接板子。5.2 回环测试三步法快速锁定故障在模块侧还是板子侧如果你不确定到底是模块坏了还是接线问题做一次回环测试五分钟就能分出责任方。第一步拔掉USB转TTL模块连接开发板的所有杜邦线用一根杜邦线把模块的TXD和RXD短接起来。第二步把模块插到Ubuntu主机确认ttyUSB0设备节点存在。第三步随便用一个串口工具比如minicomsudo apt install minicom sudo minicom -s选择串口设备为/dev/ttyUSB0波特率设个1152008N1然后打开串口。在终端里随便敲几个字符比如“hello”。因为TXD和RXD被短接了发送的数据会原路返回屏幕上会看到自己敲进去的字符回显。如果回环测试正常说明模块本身、驱动、USB链路都是好的问题出在模块和开发板之间的接线或者开发板串口硬件本身。如果没有回显那责任在模块、线材或者串口终端工具配置上。除了minicom也可以用更直接的方式测试echo test /dev/ttyUSB0然后再开一个终端cat /dev/ttyUSB0回环状态下cat终端会收到test字符串。5.3 USB线材和供电不稳导致的枚举失败硬件排查还有一个容易被忽略的点USB线看起来长得都一样但有些线只有电源线没有数据线。这种线插上去之后设备可能指示灯亮了lsusb里却完全没有新设备。判断方法很简单换一根确定支持数据传输的USB线再试。也可以看dmesg如果只有USB插入事件但没有ID信息大概率就是数据线不通。供电不足也会导致枚举失败尤其是笔记本电脑的USB口带大开发板的时候。dmesg里如果出现usb 1-2: device descriptor read/64, error -71这是典型的供电不足或者信号质量差导致的枚举错误。解决方法是把USB转串口模块插在有源USB HUB上或者给开发板用独立电源供电只和模块共享GND。6. 进阶多个串口设备时用udev固定设备名6.1 ttyUSB0为什么不稳定会在ttyUSB0和ttyUSB1之间跳当主机上同时插着多个USB转串口设备比如一个CH340的USB转TTL模块、一个CP2102的调试器还有一个FTDI的仿真器/dev/ttyUSB0到底是哪个设备完全由内核枚举顺序决定。如果你重启系统后发现之前写死的/dev/ttyUSB0现在变成了/dev/ttyUSB2或者在自动化脚本里总是打开错误的串口别奇怪这是Linux下多串口设备最常见的坑。USB设备是热插拔的内核对设备节点的编号是按照注册顺序动态分配的没有任何硬件层面的稳定性保证。6.2 用udev规则建一个固定符号链接一劳永逸解决思路不是去固定ttyUSB0本身而是通过udev规则根据USB设备的VID、PID、序列号或者物理端口位置创建一个固定的符号链接。先查看设备当前的udev属性udevadm info -a -n /dev/ttyUSB0输出里会有类似这样的信息ATTRS{idVendor}1a86 ATTRS{idProduct}7523 ATTRS{serial}0001然后新建一个udev规则文件sudo nano /etc/udev/rules.d/99-usb-serial.rules写入类似内容SUBSYSTEMtty, ATTRS{idVendor}1a86, ATTRS{idProduct}7523, ATTRS{serial}0001, SYMLINKttyBoardA重载规则并触发sudo udevadm control --reload-rules sudo udevadm trigger之后不管它被内核命名为ttyUSB0还是ttyUSB3/dev下面都会多出一个/dev/ttyBoardA符号链接指向真实设备节点。脚本和串口工具里直接写这个固定路径就行了。如果手头有两个一模一样的CH340模块VID和PID完全一致也没有唯一序列号这时候可以根据USB物理端口来区分。udevadm info里有一个KERNELS属性会显示类似KERNELS1-4.1这样的路径它表示设备插在哪个USB口上。只要每次都插同一个USB口这个路径基本保持不变可以拿它做规则。我自己工作台的走线习惯是专门用一根短线把CH340模块固定在正对机箱后置USB口的第二个口上规则里写死这个物理端口。这样无论是调试STM32还是RK3588只要模块不换口设备名永远不变省了很多重复配置的精力。这个内容后续还可以扩展一下如果你同时接好几块板子想在BeagleBone、树莓派、ESP32、STM32之间快速切换串口终端可以给每块板子建一个固定符号链接然后写一个简单的shell脚本传入板子名称就自动打开对应串口。实际用起来比每次去数ttyUSB编号舒服得多。
返回列表