尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Ubuntu下开发板串口设备找不到?从原理到排查全攻略

Ubuntu下开发板串口设备找不到?从原理到排查全攻略 把一块开发板的USB串口接到Ubuntu主机上习惯性地敲了句ls /dev/ttyUSB0结果终端直接给你看了一脸“No such file or directory”。这个场景做嵌入式开发的人应该都不陌生尤其是刚从Windows切到Ubuntu环境的那段时间几乎隔几天就有人问一次。开发板、串口、Ubuntu这三样东西凑在一起最磨人的反而不是业务逻辑而是连设备文件都找不到钱花了、板子也上电了愣是没法开始调试。这篇文章就把这个问题从头到尾讲透。我会从设备文件的产生原理讲起然后给出按顺序执行的排查命令再针对CH340、FTDI这类最常见的USB转串口芯片把驱动加载、模块编译、udev规则这些实操步骤完整走一遍。里面还包含了我实际调试中踩过的坑以及虚拟机、容器、劣质数据线这些容易让人误判的隐藏场景。适合刚入门嵌入式或者第一次在Ubuntu下调试开发板的工程师参考照着我这个排查顺序走一遍大部分问题十分钟内能定位。1. 为什么开发板插上Ubuntu后没有设备文件1.1 一串设备文件的诞生过程先明确一个最基本的认知/dev/ttyUSB0这类设备文件不是插上开发板就自动出现的它是“一连串软件协作之后的结果”。开发板上通常有一颗USB转串口芯片比如CH340、CP2102、FTDI FT232它把板子的UART信号转换成USB信号插进电脑的USB口之后对Ubuntu来说相当于插入了一个USB设备。接下来内核要完成这件事USB核心识别到这个设备读取它的VID厂商ID和PID产品ID。内核根据VID/PID找到对应的驱动程序。CH340对应的是ch341模块FTDI对应的是ftdi_sio模块CP2102对应的是cp210x模块。驱动加载成功后会在USB转串口驱动框架usbserial下注册一个tty设备。内核生成设备节点udev再根据规则在/dev目录下创建ttyUSB0之类的文件。这四步里任何一步断了你从用户态就什么都看不到。所以排查的思路其实就是一级一级地确认电脑认没认到USB设备内核有没有加载对应驱动驱动有没有成功注册ttyudev有没有生成设备节点把这个链路想通之后你就会发现“找不到设备文件”根本不是单一故障而是一类故障的统称。这也是为什么网上搜解决方案有人说装驱动就好有人说改权限就好有人说要换线——因为大家遇到的断点根本不在一层。1.2 把问题拆成三层物理层、内核层、用户态层为了不让自己像个无头苍蝇一样乱试我一般会把这个问题拆成三层来判断物理层开发板有没有上电USB线是不是只支持充电接口有没有插错宿主机或虚拟机有没有把这个USB设备接管内核层Ubuntu有没有识别到USB设备内核有没有加载对应的串口驱动模块驱动有没有报错用户态层设备节点存不存在当前用户有没有访问权限用的终端工具是否配置正确这三层的优先级是严格的物理层没通过后面都不用看。内核层没过设备节点就不会出现。用户态层的问题通常表现为“设备存在但打不开”或者“minicom没反应”。很多新手容易犯的错是在内核层还没确认时就先去网上找一个驱动源码来编译结果折腾半天发现自己的芯片其实已经被内核支持了只是看一眼lsmod就能解决。反过来还有一种情况驱动源码编译了一下午最后发现是虚拟机没有把USB设备映射进去纯属白忙活。所以先按层定位再动手这个顺序本身比任何命令都值钱。2. 先别急着装驱动三分钟定位问题在哪一层2.1 插拔一瞬间的dmesg信息就是破案关键最快的定位方法不是打开什么图形工具而是盯着内核日志看。先把开发板的USB线拔掉然后在终端执行sudo dmesg -c-c参数会清空当前内核日志缓冲区这样后面输出里只有你插拔一瞬间的新日志不会被开机以来的一大堆信息淹没。接下来把USB线插上等两三秒再执行sudo dmesg | tail -n 30观察输出。我这里用CH340芯片举一个“正常识别”的例子日志大概长这样usb 1-1: new full-speed USB device number 5 using xhci_hcd usb 1-1: New USB device found, idVendor1a86, idProduct7523, bcdDevice2.64 usb 1-1: New USB device strings: Mfr0, Product2, SerialNumber0 usb 1-1: Product: USB Serial ch341-uart converter now attached to ttyUSB0最后一行是关键ch341-uart converter now attached to ttyUSB0说明内核已经识别并注册了串口设备。只要看到这行/dev/ttyUSB0大概率就存在了。如果日志只到New USB device found为止没有最后那行ch341-uart converter基本可以断定是驱动模块没有加载成功后面第3章会专门讲怎么处理。如果连New USB device found都没有说明USB枚举这步就没过问题在物理层或者虚拟机没做USB直通先别折腾驱动去检查线材和接口。有一种情况比较特殊插上去之后一点反应都没有dmesg完全没输出。这时候不要急着下结论先换个USB口或者把开发板断电重新上电再执行一次dmesg | tail -n 30。USB接口接触不良、供电不足都会导致设备直接不枚举日志干干净净但这不代表硬件坏了。2.2 lsusb确认芯片是否被识别dmesg能告诉你内核视角发生了什么lsusb则能从更底层确认USB控制器是否枚举到了这个设备。命令很简单lsusb输出是一堆USB设备列表。重点找几行常见USB转串口芯片的VID/PID对照如下芯片型号厂商ID (VID)产品ID (PID)常见设备名CH340/CH3411a867523ttyUSB0CP2102/CP210x10c4ea60ttyUSB0FTDI FT23204036001ttyUSB0PL2303067b2303ttyUSB0原生USB CDCSTM32/ESP32-S3等各类各类ttyACM0比如你是CH340就会看到一行Bus 001 Device 005: ID 1a86:7523 QinHeng Electronics CH340 serial converter。只要这一行出现说明USB枚举成功了剩下的问题基本在内核驱动和用户态。如果lsusb里压根看不到这个设备那就是物理层或者虚拟机的USB映射问题软件层面排查得再多也没用。这里还要提醒一下有些开发板用的是芯片自带的USB接口不走外置转串口芯片。例如STM32F407VE这类板子如果直接通过USB口连接电脑枚举出来很可能是ttyACM0而不是ttyUSB0这是两种完全不同的设备框架。很多人在/dev下翻半天找不到ttyUSB0结果设备文件其实叫ttyACM0只是名字不一样而已。所以执行ls /dev/tty*的时候把它俩都看一下。2.3 设备节点存在但打不开权限组问题设备文件找到了但minicom、串口助手这类工具打不开报Permission denied这是另一个高频问题本质上是当前用户不在dialout组里。看一下设备节点的权限ls -l /dev/ttyUSB0输出一般是crw-rw---- 1 root dialout 188, 0 Jan 20 10:23 /dev/ttyUSB0注意这行的权限位crw-rw----主是root属组是dialout权限是“root可读写dialout组成员可读写其他用户没有任何权限”。而你的登录用户通常不在dialout组里自然打不开。解决办法是把用户加到dialout组sudo usermod -aG dialout $USER执行完这个命令之后必须重新登录一次或者注销再登录让用户组变更生效。如果不想重新登录也可以直接用newgrp dialout切一下当前会话的组身份。这个方法适用于绝大多数发行版包括Ubuntu 22.04、24.04这些常见版本。加组之后再去打开串口权限问题就消失了。如果你用的是虚拟机里新装的Ubuntu也可能遇到sudo权限本身没配好的情况但那个问题症状不同通常是你连sudo dmesg都会报错这里就不展开了。3. CH340/FTDI驱动缺失时的处理方案3.1 先检查内核模块加载情况前面说了dmesg能看到USB设备枚举但看不到ch341-uart converter now attached最可能的原因就是驱动模块没有加载。先别急着去编译驱动用这几条命令确认一下内核模块的状态lsmod | grep ch341 lsmod | grep ftdi lsmod | grep cp210x有输出说明模块已经加载了。没输出就手动加载一下sudo modprobe ch341加载完立刻再看一眼dmesg这会提示“ch341-uart converter now attached to ttyUSB0”。但如果modprobe报错比如modprobe: FATAL: Module ch341 not found in directory /lib/modules/...说明你的内核里根本没编译这个驱动模块。这时候才需要往下走去手动编译。先确认一下内核头文件是否齐全这一步很关键uname -r sudo apt install linux-headers-$(uname -r)如果提示linux-headers-xxx已经是最新版本那就可以编译了。很多时候手动编译驱动失败不是因为代码有问题而是内核头文件没装好make的时候根本找不到内核源码。3.2 老芯片需要手动编译内核模块的完整流程如果你用的内核比较老或者定制过内核确实可能出现系统内置驱动缺失的情况。以CH340的官方源码编译为例把完整流程走一遍。官方驱动包一般叫CH341SER_LINUX.ZIP下载解压后目录里会有一个ch34x.c、一个Makefile。进入目录执行make正常情况下会生成ch34x.ko文件。然后先卸载系统里可能已经加载的旧模块sudo rmmod ch341再加载刚编译的sudo insmod ch34x.ko用dmesg确认一下是否出现ch341-uart converter now attached to ttyUSB0出现即成功。如果要让系统开机自动加载需要把这个模块复制到内核模块目录并执行depmodsudo cp ch34x.ko /lib/modules/$(uname -r)/kernel/drivers/usb/serial/ sudo depmod sudo modprobe ch34x这么做有个好处以后插上板子系统就会自动加载这个模块不用每次插线都手动insmod。编译过程中最常见的错误分两种。一种是fatal error: linux/compiler.h: No such file or directory这说明内核头文件没装回去补linux-headers。另一种是error: unknown type name wait_queue_t这类报错是源码过于老旧、跟新内核API不兼容导致的。遇到这种问题我的建议是优先用系统自带的ch341模块而不是死磕旧源码。新内核5.x之后的ch341驱动已经非常完善了覆盖了绝大多数CH340场景源码编译基本只适用于特殊内核或者老芯片的兼容问题。FTDI芯片的处理思路完全一样只是模块名换成ftdi_sio一般也不会缺缺了就用modprobe ftdi_sio加载。3.3 用udev规则固定设备名和权限驱动搞定之后还有一个值得做的事写udev规则。开发板插在不同的USB口上设备节点可能在ttyUSB0和ttyUSB1之间跳来跳去。对于经常同时接好几块板子或者多个串口设备的人来说设备名乱跳非常难受。创建一个规则文件sudo vi /etc/udev/rules.d/99-usb-serial.rules内容如下SUBSYSTEMtty, ATTRS{idVendor}1a86, ATTRS{idProduct}7523, MODE0666, SYMLINKttyCH340这段规则的含义是只要VID是1a86、PID是7523的USB设备注册为tty就把权限设为0666同时创建一个名为ttyCH340的软链接。之后无论插在哪个USB口都能通过/dev/ttyCH340访问不用再猜是ttyUSB0还是ttyUSB1。保存后让规则生效sudo udevadm control --reload-rules sudo udevadm trigger然后重新插拔开发板用ls -l /dev/ttyCH340确认。这里提个建议MODE0666会让所有用户都能读写这个串口在个人开发机上图省事没问题但如果电脑有其他用户最好改成MODE0660, GROUPdialout把权限收回到dialout组加上用户组成员控制更稳妥一些。4. 虚拟机与容器环境下最常见的漏网之鱼4.1 VMware/VirtualBox的USB直通配置如果你是在虚拟机里装的Ubuntu系统来调试开发板那“找不到设备文件”这个问题还有一层很容易被忽略的坑虚拟机根本就没把USB设备映射进去。在VMware里插入开发板后需要手动把USB设备从宿主机“移交”到虚拟机。操作路径是菜单栏的“虚拟机” - “可移动设备” - 找到你的USB转串口设备比如“USB Serial”点击“连接”。连接成功后lsusb里才会出现这个设备。VMware的USB控制器设置也值得检查一下。编辑虚拟机设置在“USB控制器”里把兼容性设置为“USB 2.0”或“USB 3.1”。有些老虚拟机配置默认的USB 1.1控制器速度极慢部分芯片会直接枚举失败也不稳定。VirtualBox的情况类似但前提条件更多。首先要在宿主机安装Oracle VM VirtualBox Extension Pack然后在虚拟机设置 - USB设备里添加一条空过滤器允许所有USB设备接入虚拟机或者专门针对VID/PID添加过滤器。分配完成之后启动虚拟机里才会出现设备。判断自己是不是栽在这个问题上最直接的方法在虚拟机里执行lsusb看有没有CH340/FTDI那行。如果虚拟机里看不到但宿主机上看得到99%是USB直通没配好。这个问题我在实际工作中遇到过不止一次每次帮同事排查第一个命令一定是lsusb。看到设备列表里没有那行就直奔虚拟机的USB设置去十分钟就能解决。4.2 容器内访问串口设备用Docker容器做嵌入式编译环境的人越来越多但容器默认是看不到宿主机的/dev/ttyUSB0的因为容器有自己的设备命名空间。启动容器时需要显式把串口设备映射进去docker run -it --device/dev/ttyUSB0 ubuntu:22.04 bash如果设备名不稳定建议同时映射宿主机派生的软链接目录。我自己的习惯是先把udev规则配置好固定设备名之后再在容器启动参数里加上--device/dev/ttyCH340配合-v /dev:/dev一起使用。不过直接用-v /dev:/dev虽然简单粗暴但会把宿主机的所有设备节点带进去安全性差点生产环境不建议这么干。容器里要用的串口工具也得单独装我用的是picocom或者minicomDebian系镜像里直接apt install就行体积不大调试够用了。5. 栽在硬件上的那些“找不到设备”假象5.1 数据线不等于充电线先换根线试试排查到这一步软件层面基本都清理干净了如果你还是看不到设备文件请认真怀疑一下手里的USB线。现在的MicroUSB和Type-C线有很大一部分只接入了电源线没有数据线芯。用这种线给开发板供电没问题板子上的灯也亮电脑也充着电但数据脚根本没通USB枚举自然失败dmesg干干净净lsusb里什么都没有。判断方法很简单换一根明确支持数据传输的线。如果手头有多根线就一根一根试。另外有些开发板的USB口有“供电专用”和“USB转串口”两个口插错了也不会枚举。比如某些带有自恢复保险丝电路设计的板子USB口旁边会有丝印标注插之前先看一眼。这种硬件问题最坑的地方在于它会让你误以为是软件配置有误从而在驱动、udev规则上浪费大量时间。我自己就经历过一次一个上午都在编译CH340驱动源码各种报错和排查最后发现是同事那根线不支持数据气得不行。所以如果你在物理层这关卡住了第一反应不应该是“我的环境有问题”而是“先换根线再说”。5.2 板载串口芯片损坏与ttyACM0的识别问题开发板上的USB转串口芯片本身也可能坏。比如CH340芯片的晶振虚焊、芯片引脚损坏都会导致USB无法正常枚举。判断方法不难如果lsusb里能看到一个“unknown device”或者“QinHeng Electronics”的条目但dmesg一直报device descriptor read/64, error -71之类的内容基本就是硬件层面的问题。可以尝试用万用表量一下开发板USB口的供电和地线确认电压正常。如果芯片附近有明显发烫或者你闻到焦糊味那就别折腾了板载芯片大概率已经烧了这种情况我遇到过三次每次都是换一片CH340模块外接到UART引脚上解决。还有一个容易忽略的点前面提过的ttyACM0。如果你用的是自带USB功能的开发板比如ESP32-S3它的USB口本身就不是通过CH340桥接的而是芯片原生USB枚举出来是/dev/ttyACM0。很多人习惯性地只搜ttyUSB0看到/dev/ttyACM0也不认识就会陷入“找不到设备文件”的困惑。解决办法就是在终端执行ls /dev/tty*把ttyUSB和ttyACM都看一下再通过udevadm info确认具体是什么设备避免草木皆兵。5.3 Ubuntu下常用的串口终端工具设备文件已经有了权限也OK了接下来就是选一个顺手的串口工具在Ubuntu下和开发板通信。Windows下大家习惯用各种串口调试助手Ubuntu下我常用的三款是minicom、picocom和screen。minicom功能最全但配置稍显繁琐。安装之后先执行sudo minicom -s进入配置界面选择“Serial port setup”把串口设备改成/dev/ttyUSB0或/dev/ttyACM0波特率设为115200按开发板实际配置来保存退出即可。之后启动minicom就能看到开发板的串口输出。picocom更轻量我日常用得最多一条命令就能连上sudo apt install picocom picocom -b 115200 /dev/ttyUSB0-b指定波特率。退出方式需要记住先按CtrlA再按CtrlX。第一次用的时候狂按CtrlC退不出去还以为卡死了实际上它就是这么设计的。screen是系统自带的工具用法是sudo screen /dev/ttyUSB0 115200退出时按CtrlA然后按K再按Y确认。适合临时快速看一眼串口输出没有额外依赖。结尾聊聊我自己的排查惯性在串口调试这件事上我吃过不少亏最后形成的个人排查习惯很简单插上开发板先不看/dev而是先敲dmesg | tail再敲lsusb两个命令就能确定问题在软件还是硬件。绝大多数“找不到设备文件”的问题最后都落在三个点上虚拟机没接USB、线不支持数据、用户不在dialout组。真正需要编译驱动的场景反而少之又少。再分享一个小技巧如果你经常需要在多块开发板之间切换调试强烈建议给每块板子写一条独立udev规则根据芯片的序列号区分设备给每块板子固定一个独立软链接比如/dev/board-stm32、/dev/board-rk3588。省去每次插线后猜设备名的痛苦也避免误操作烧到错误的板子。这一步配置好之后配合picocom -b 115200 /dev/board-stm32一句命令连板子效率能提升不少。
返回列表