1. 为什么 CH340 在 Ubuntu 22.04 上总让人头疼
手里拿着一块开发板、一个烧录器或者一台老式串口设备,插上 USB 转串口线,满心期待地打开串口终端,结果发现/dev/ttyUSB0压根不存在——这个场景我遇到过太多次了。CH340 这颗芯片几乎是市面上最普及的 USB 转串口方案之一,价格便宜、外围电路简单,大量开发板、单片机下载器、工业采集模块都在用它。但它在 Linux 桌面发行版上的体验,尤其是 Ubuntu 22.04 这个长期支持版本上,经常不那么顺滑:有时插上就能用,有时死活识别不出来,有时识别出来了却收不到数据,还有的时候权限不对导致普通用户打不开设备节点。
这篇内容就是围绕Ubuntu 22.04 下 CH340 串口驱动配置与故障排查展开的。我会从内核驱动模块的加载机制讲起,把识别、权限、波特率、数据收发这几个环节拆开,给出可以直接照着敲的命令和配置,再把我实际踩过的坑整理成一张速查表。适合刚接触嵌入式开发的新手,也适合已经用了一段时间但遇到问题只会重启的同行——很多时候问题不在硬件,而在几个容易被忽略的细节上。
需要先说明一点:CH340 在主流 Linux 内核里其实早就有原生驱动了,模块名叫ch341,它同时覆盖 CH340、CH341、CH345 这一系列芯片。所以绝大多数情况下你不需要去官网下载什么独立驱动包,也不需要编译内核模块。真正需要动手的地方,往往是模块没自动加载、设备节点权限不对、或者设备被别的驱动抢走了。理解这一点,后面的排查思路就清晰多了。
2. 驱动机制拆解:CH340 在 Linux 下到底是怎么工作的
2.1 内核原生驱动 ch341 的覆盖范围
很多人第一次接触 CH340 是在 Windows 上,需要装一个厂商提供的驱动安装包,于是下意识认为 Linux 上也要走同样的流程。实际上 Linux 内核社区早就把这一系列芯片的支持合并进主线了,对应的模块是ch341。这个模块负责的事情包括:识别 USB 设备描述符、把 USB 端点映射成标准的串口设备、处理波特率设置、数据收发和流控。
你可以用一条命令确认当前内核有没有这个模块:
modinfo ch341如果输出里有filename、license、alias这些字段,说明模块是存在的。特别注意alias那一行,通常会看到类似usb:v1A86p7523d*这样的条目,1A86是厂商 ID,7523是 CH340 的产品 ID。内核正是靠这个 alias 匹配表,在设备插入时自动加载对应模块的。这也解释了一个常见现象:有些 CH340 设备插上就自动工作了,因为它的 VID/PID 在匹配表里;而某些改版芯片或者复合设备,PID 不在表里,就不会自动触发加载。
2.2 设备插入后的完整链路
把 USB 线插上的那一刻,系统内部发生了一连串动作,理解这条链路对排查问题非常关键。USB 子系统先枚举设备,读取厂商 ID 和产品 ID,然后通过udev规则和内核模块的 alias 表去匹配驱动。匹配成功后ch341模块被加载,驱动在/dev下创建ttyUSB0这样的字符设备节点,同时brltty之类的辅助服务也可能对某些串口设备产生兴趣。
这条链路上任何一环出问题,表现都是"设备没反应"。所以排查时不要一上来就怀疑芯片坏了,而是按链路顺序逐段验证:设备有没有被 USB 子系统看到、驱动有没有绑定、设备节点有没有创建、权限对不对。这个顺序后面会展开成具体的命令。
2.3 为什么不用第三方驱动包
网上有些教程会让你去下载厂商的驱动源码编译安装,我的建议是除非你的内核版本特别老或者芯片是特殊型号,否则不要这么做。原因有三:第一,第三方驱动和内核版本强绑定,内核一升级就可能编译失败或者运行异常;第二,主线驱动经过大量测试,稳定性和兼容性更好;第三,自己编译的模块需要处理签名和安全启动的问题,徒增复杂度。主线ch341模块已经能覆盖绝大多数使用场景,把精力放在配置和排查上更划算。
3. 从零配置:识别、权限与工具链准备
3.1 确认设备是否被系统识别
插上设备后,第一件事不是看/dev,而是看 USB 层面有没有认到。用lsusb命令:
lsusb | grep -i "1a86"正常应该看到类似Bus 001 Device 005: ID 1a86:7523 QinHeng Electronics CH340 serial converter的输出。如果这里什么都没有,说明问题在更底层:可能是线材只供电不传数据、USB 口接触不良、或者设备本身没上电。换根线、换个口再试,这一步能排除掉相当一部分"假故障"。
确认 USB 认到之后,再看内核日志里驱动绑定的情况:
dmesg | tail -30插入设备后立刻执行,正常会看到ch341-uart converter now attached to ttyUSB0这样的信息。如果看到的是usb 1-1: device descriptor read/64, error -71之类的报错,那是 USB 通信层面的问题,跟串口驱动无关,重点查线材和供电。
3.2 设备节点与权限配置
设备被正确识别后,/dev/ttyUSB0应该会出现。用ls -l看一下它的属主和权限:
ls -l /dev/ttyUSB0典型输出是crw-rw---- 1 root dialout ...,也就是说只有 root 和dialout组的成员能访问。普通用户直接打开会报Permission denied。解决办法是把当前用户加入dialout组:
sudo usermod -aG dialout $USER这里有个必须强调的细节:加组之后必须重新登录才生效,注销重进或者重启都行,光执行命令不重新登录是没用的。我见过不少人加完组发现还是没权限,折腾半天以为是驱动问题,其实就是没重新登录。验证方法是用groups命令看输出里有没有dialout。
如果你不想改用户组,也可以临时用sudo运行串口工具,但这只适合调试,日常开发还是加组更省事。另外有些系统里组名可能是uucp而不是dialout,用ls -l看设备节点的实际属组为准。
3.3 串口工具的选型与安装
配置好权限后需要一个趁手的终端工具。常用的有几个:minicom功能全但界面偏老,picocom轻量简洁,screen随手可用,cutecom是图形界面适合不习惯命令行的。我个人的组合是日常用picocom,需要抓日志时用screen配合重定向。
安装很简单:
sudo apt update sudo apt install picocom minicom screen用picocom连接的基本命令是:
picocom -b 115200 /dev/ttyUSB0-b指定波特率,退出用Ctrl+A再按Ctrl+X。这里提醒一句,波特率必须和设备端完全一致,常见的有 9600、115200、921600,设错了表现就是收到一堆乱码或者完全没数据,很容易被误判成驱动故障。
4. 实操全流程:一次完整的串口连通验证
4.1 分步验证流程与现场记录
我把整个验证过程整理成一个固定流程,每次遇到新设备都按这个走,效率最高。第一步lsusb确认 USB 层识别,第二步dmesg确认驱动绑定,第三步ls /dev/ttyUSB*确认节点创建,第四步检查权限,第五步用工具连接并做回环或收发测试。这五步对应前面讲的链路,任何一步失败就停在那里深挖,不要跳步。
举个实际例子。某次接一块采集模块,lsusb能看到1a86:7523,但dmesg里没有attached to ttyUSB0,反而出现了ch341-uart: probe of ... failed with error -110。-110是超时错误,说明驱动尝试和芯片通信时没收到响应。这种情况多半是硬件层面:供电不足、USB 线质量差、或者芯片本身异常。换了个带独立供电的 USB 集线器后问题消失。这个案例说明,看到驱动报错不要急着改配置,先判断是软件还是硬件问题。
4.2 波特率与串口参数的设置逻辑
串口通信的参数不止波特率一个,还有数据位、停止位、校验位、流控。标准配置通常是 8 数据位、1 停止位、无校验、无流控,简称 8N1。绝大多数设备都用这个默认值,但工业设备里偶尔会遇到 7E1 或者带硬件流控的情况。参数不匹配的表现和波特率错误类似,都是乱码或无数据。
用stty可以查看和设置当前串口参数:
stty -F /dev/ttyUSB0 -a这条命令会打印出当前的波特率、字符大小、校验方式等。要手动设置成 115200 8N1,可以这样:
stty -F /dev/ttyUSB0 115200 cs8 -cstopb -parenb -crtscts参数含义:cs8是 8 数据位,-cstopb是 1 停止位,-parenb是无校验,-crtscts是关闭硬件流控。这些参数在打开串口工具时通常会被工具重新设置,所以一般不用手动敲,但排查问题时用stty看一眼当前状态很有用。
4.3 数据收发的验证方法
确认能打开设备后,怎么验证数据真的通了?最直接的办法是做回环测试:把 USB 转串口模块的 TX 和 RX 两个引脚用杜邦线短接,然后往设备写数据,看能不能原样读回来。用两条命令配合:
# 终端一:持续读取 cat /dev/ttyUSB0 # 终端二:写入数据 echo "hello" > /dev/ttyUSB0如果终端一能打印出hello,说明驱动、节点、收发链路全部正常。这个测试的价值在于把"设备端"这个变量排除掉了,纯粹验证主机侧。如果回环不通,问题一定在主机侧或者模块本身;如果回环通了但接上真实设备不通,那就要查设备端的接线、波特率和协议了。
注意:做回环测试前务必确认模块的 TX/RX 是 3.3V 还是 5V 电平,短接前看清楚引脚定义,接错电源引脚可能烧芯片。
5. 故障排查实录:那些年踩过的坑
5.1 设备节点不出现的三类原因
/dev/ttyUSB0不出现是最常见的求助场景,原因可以归成三类。第一类是 USB 层没识别,lsusb里看不到设备,问题在线材、接口或供电。第二类是 USB 识别了但驱动没绑定,dmesg里有报错或者干脆没动静,可能是 PID 不在匹配表里,也可能是被brltty这类服务抢占了。第三类是驱动绑定了但节点名不是ttyUSB0,比如系统里已经有其他串口设备,新设备可能变成ttyUSB1,用ls /dev/ttyUSB*通配符看全一点。
关于brltty抢占这个问题值得单独说。Ubuntu 默认装了盲文终端服务brltty,它会对某些 USB 串口设备产生兴趣并尝试接管,导致ch341驱动拿不到设备。判断方法是dmesg里看到ch341的 probe 失败,同时有brltty相关的日志。处理办法是卸载或者禁用它:
sudo apt remove brltty这个坑我在不止一台机器上遇到过,表现非常迷惑——同样的设备在别的电脑上好好的,就这台不行,查半天才发现是系统服务在捣乱。
5.2 能识别但收不到数据的排查顺序
设备节点有了、权限也对了,但打开后一片安静,这种情况按下面的顺序查。先确认波特率和串口参数是否和设备端一致,这是最高频的原因。再用回环测试排除主机侧问题。然后检查接线,TX 要接对方的 RX,RX 要接对方的 TX,交叉接线这个基础错误新手经常犯。最后考虑电平匹配,3.3V 的模块直连 5V 设备可能通信异常。
还有一种隐蔽情况是流控。某些设备默认开启了硬件流控,而你的工具没开,或者反过来,表现就是能发不能收或者完全卡住。用stty -a看crtscts的状态,必要时显式关闭。我遇到过一台设备必须关闭流控才能正常通信,文档里没写,纯靠试出来的。
5.3 常见问题速查表
| 现象 | 可能原因 | 排查命令 | 处理方式 |
|---|---|---|---|
lsusb无设备 | 线材/供电/接口问题 | lsusb、换线换口 | 更换数据线或供电方式 |
有设备无ttyUSB | 驱动未绑定或被抢占 | dmesg、lsmod | 卸载 brltty,手动modprobe ch341 |
| 节点存在但无权限 | 用户不在 dialout 组 | ls -l /dev/ttyUSB0、groups | 加组后重新登录 |
| 打开后乱码 | 波特率或参数不匹配 | stty -F /dev/ttyUSB0 -a | 统一两端参数为 8N1 |
| 能发不能收 | 接线错误或流控 | 检查 TX/RX、stty流控位 | 交叉接线,关闭流控 |
| probe 报 -110 | 硬件通信超时 | dmesg | 换线、加供电、换模块 |
5.4 几个容易被忽略的实操心得
第一个心得:dmesg的输出会滚动,插入设备后要立刻看,或者用dmesg -w持续监控,插拔时观察实时日志,比事后翻记录高效得多。第二个心得:如果系统里有多个串口设备,不要硬编码ttyUSB0,用ls -l /dev/serial/by-id/看稳定的设备路径,这个路径基于设备序列号,插拔顺序变化也不会变,写脚本时特别有用。第三个心得:遇到玄学问题先重启udev服务或者重新插拔,有时候只是状态没刷新,别急着怀疑硬件。
提示:
/dev/serial/by-id/下的软链接是排查多设备场景的利器,脚本里用它比用ttyUSB0可靠得多。
6. 稳定性优化与长期使用建议
6.1 udev 规则固化设备权限
每次手动加组虽然一劳永逸,但如果设备要在多台机器上使用,或者需要给特定设备固定一个别名,写一条 udev 规则会更优雅。在/etc/udev/rules.d/下建一个规则文件,比如99-ch340.rules,内容可以指定设备插入时自动设置权限或者创建固定软链接:
SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE="0666", GROUP="dialout", SYMLINK+="ch340"这样设备插入后会自动创建/dev/ch340这个固定名字的软链接,权限也一并设好。改完规则后执行sudo udevadm control --reload-rules和sudo udevadm trigger让它生效。用固定软链接的好处是脚本和配置文件里不用再关心ttyUSB后面的数字,设备插拔顺序变了也不受影响。
6.2 长时间通信的稳定性考量
如果串口要长时间连续通信,有几个点值得注意。一是避免用cat这种简单工具做长期采集,它没有错误处理,遇到异常数据可能卡住,用带超时和重连逻辑的脚本更稳。二是注意 USB 自动挂起可能影响通信,可以在内核参数里关闭对应设备的自动电源管理。三是长时间运行后如果出现丢数据,检查一下缓冲区设置和读取频率,读得太慢会导致内核缓冲区溢出。
对于需要开机自动连接串口的场景,建议用systemd服务来管理,把启动顺序、重启策略、日志输出都交给它处理,比写个裸脚本可靠。服务配置里注意加上After=dev-serial-by\x2did-...device这样的依赖,确保设备就绪后再启动程序。
6.3 内核升级后的回归验证
Ubuntu 22.04 会不定期推送内核更新,升级后建议重新验证一遍串口功能。虽然主线ch341驱动很稳定,但内核版本变化偶尔会带来行为差异。验证方法就是走一遍前面那套五步流程,花不了两分钟。如果升级后出问题,可以用apt回退到之前的内核版本,或者用dkms管理自己编译的模块(如果确实需要的话)。养成升级后回归验证的习惯,能避免在关键时刻被意外问题打个措手不及。
我个人在实际操作中的体会是,CH340 这类成熟芯片的问题,九成以上都不在驱动本身,而在权限、参数、接线、系统服务这些外围环节。把排查顺序固定下来,按链路逐段验证,比盲目搜索教程高效得多。最后再分享一个小技巧:准备一个记录本或者文档,把每台机器、每个设备的可用配置记下来,包括波特率、特殊参数、遇到的坑和解决办法,下次遇到同类问题直接查记录,能省下大量重复排查的时间。