简介:面向在 Ubuntu 22.04 上使用 CH340 USB 转串口芯片的开发者与嵌入式学习者,这份驱动资料包针对 Linux 内核未默认集成 CH340 驱动、串口设备难以识别的问题,提供可参考的驱动源码、编译脚本与模块文件。压缩包共 16 个文件,约 291KB,主要包含 C 源码、Makefile 编译脚本、ko 内核模块、o 中间文件、cmd 构建命令记录及 txt 说明文档,覆盖从源码编译到模块生成的基本材料。已有 779 人学习下载,说明其在同类环境配置中具有一定参考价值。读者可借此了解 Linux 串口驱动模块的组织方式、编译产物构成与加载前准备,并结合说明文档排查设备识别、权限配置等常见问题,适合需要搭建 CH340 串口通信环境或对照编译过程查漏补缺的中初级用户。
1. 先别急着找驱动包:Ubuntu 22.04 识别 CH340 的真实路径
Ubuntu 22.04 安装 CH340 串口驱动,最容易翻车的地方不是“找不到驱动”,而是把它当成 Windows 那套思路:先到处找安装包,再双击下一步。CH340 在 Linux 下走的是内核ch341模块,Ubuntu 22.04 的 5.15 内核和后续 HWE 内核一般都带了这个模块。插上模块后,lsusb能看到1a86:7523,但/dev/ttyUSB0迟迟不出现,问题往往落在模块没加载、brltty抢占、ModemManager干扰或者当前用户不在dialout组。
这套环境在开发板调试、工控设备日志抓取、传感器串口读数里太常见了。装不好不会蓝屏,只会让你对着一个“有 USB 设备、没有串口节点”的黑匣子干瞪眼。下面按“先核对环境、再加载模块、然后配权限和 udev、最后验证收发”的顺序走,新手能照抄,熟手也能看到版本差异和参数取舍。
2. 装前把环境钉死:Ubuntu 22.04 内核、CH340 硬件 ID 与串口工具链
先把机器底细摸清,比一上来就modprobe更省时间。CH340 在 Ubuntu 22.04 上能不能出/dev/ttyUSB0,第一取决于内核里有没有ch341,第二取决于 USB 设备有没有被别的服务截胡,第三才轮到权限。环境核对这一步做细,后面排错就不靠猜。
2.1 核对内核与 ch341 模块:5.15 与 HWE 内核的差异
先看当前跑的内核:
uname -rUbuntu 22.04 初始版本常见的是 5.15 系列内核,后面启用 HWE 的机器会跑到 6.2、6.5 一类分支。版本号本身不决定 CH340 能不能用,关键是这个内核的模块包里有没有ch341.ko。我一般接着查模块信息:
modinfo ch341正常会看到filename指向/lib/modules/$(uname -r)/kernel/drivers/usb/serial/ch341.ko,还会带alias: usb:v1A86p7523d*这类别名。只要这个输出在,就说明内核侧已经具备识别 CH340 的能力,不需要去外面找所谓“CH340 Linux 驱动包”。如果报modprobe: FATAL: Module ch341 not found或者modinfo: ERROR: Module ch341 not found,先别怀疑芯片,先看模块包:
ls /lib/modules/$(uname -r)/kernel/drivers/usb/serial/ | grep ch341 grep CONFIG_USB_SERIAL_CH341 /boot/config-$(uname -r)grep的结果如果是CONFIG_USB_SERIAL_CH341=m,说明编成了模块;如果是=y,说明编进内核;如果是# CONFIG_USB_SERIAL_CH341 is not set,这个内核就没带,换官方内核比乱装第三方包靠谱。Ubuntu 上常见做法是补linux-modules-extra:
sudo apt update sudo apt install -y linux-modules-extra-$(uname -r)这个包补的是当前内核的额外模块,不是替换内核。装完再跑一次modinfo ch341。不同内核分支的包名会跟着版本走,$(uname -r)不要写死,否则换内核后对不上。下面这张表是我核对环境时常用的判断顺序:
| 检查项 | 命令 | 正常表现 | 异常时先看什么 |
|---|---|---|---|
| 当前内核 | uname -r | 5.15 或 HWE 分支 | 是否刚换过内核没重启 |
| 模块信息 | modinfo ch341 | 有 filename 和 alias | 模块包是否缺失 |
| 内核配置 | grep CONFIG_USB_SERIAL_CH341 /boot/config-$(uname -r) | =m或=y | 是否为not set |
| USB 枚举 | lsusb -d 1a86:7523 | 能看到设备 | 线缆、接口、供电 |
硬件 ID 也要以实际lsusb为准。CH340 常见的是1a86:7523,但不同封装、不同小板子未必完全一样。不要只记一个 PID 就到处套,插上设备跑:
lsusb lsusb -tlsusb -t能看出设备挂在哪条 USB 总线上、速率是 12M 还是 480M。CH340 是 USB 转串口,通常不会跑高速,看到它挂在总线下面就够了。若lsusb完全没动静,先换线、换口,不要继续折腾驱动。
2.2 安装 minicom、picocom 与内核头文件:依赖一次装齐
串口工具不用装一堆,但常用的几个装上后面省事。下面这条命令把 USB 查看、串口终端、编译依赖和当前内核头文件一起补齐:
sudo apt update sudo apt install -y usbutils picocom minicom screen \ build-essential linux-headers-$(uname -r) linux-modules-extra-$(uname -r)usbutils提供lsusb和usb-devices;picocom轻量,适合快速打开串口;minicom功能多,菜单和配置习惯看个人;screen在临时调试时也够用。build-essential和linux-headers-$(uname -r)不是 CH340 内置模块的硬依赖,但后面一旦要编译外部模块、DKMS 驱动或者排查内核头文件问题,没有它们会卡住。linux-modules-extra-$(uname -r)则是补当前内核的额外模块。
装完先确认工具在:
picocom --help | head lsusb -V如果linux-headers-$(uname -r)报找不到包,不要硬装一个版本号对不上的头文件。先查可用包:
apt-cache search linux-headers | grep "$(uname -r)"HWE 内核的 headers 包名可能和主内核不同,按uname -r的实际版本找。还有一点,Secure Boot 开启时,自己编译的外部模块会涉及签名;但 CH340 走的是内核自带ch341,通常不碰这一层。只有在模块确实缺失、需要自己编译时,才去处理 MOK 签名,不要一上来就把问题复杂化。
工具装好后,插上 CH340,马上看 USB 层:
lsusb -d 1a86:7523 sudo dmesg -T | tail -n 30dmesg里如果出现ch341-uart converter now attached to ttyUSB0,说明内核已经认了;如果只有 USB 枚举信息,没有 tty 绑定,就往第 3 章的模块加载和brltty方向查。这个顺序不要反,先看 USB,再看模块,最后看设备节点。
3. 从 lsusb 到 /dev/ttyUSB0:ch341 模块加载与设备节点确认
lsusb能看到设备,只代表 USB 层认出了这颗芯片,不代表串口驱动已经绑定。Linux 下 USB 转串口要经过“USB 枚举 -> 匹配ch341驱动 -> 注册 tty -> 生成/dev/ttyUSB0”这条链。中间任何一环被挡住,设备节点就不会出现。
3.1 手动加载 ch341:modprobe、dmesg 与 brltty 抢占
先手动加载一次,排除“模块没加载”这种低级问题:
sudo modprobe ch341 lsmod | grep ch341 sudo dmesg -T | tail -n 30modprobe会自动处理依赖模块,比insmod适合日常使用。lsmod里看到ch341一行,后面跟着usbserial之类的依赖,说明模块在。dmesg里重点看两类信息:一类是ch341-uart converter now attached to ttyUSB0,这是正常绑定;另一类是brltty字样,这通常意味着盲文终端服务把 CH340 当成了自己的设备。
brltty是 Ubuntu 桌面环境里可能预装的服务,它会扫描 USB 串口设备。CH340 被它抢走后,表现就是lsusb有设备、dmesg有 USB 枚举,但/dev/ttyUSB0不出现。先看服务状态:
systemctl status brltty-udev.service --no-pager systemctl status brltty.service --no-pager如果确认是它,先停掉再插拔:
sudo systemctl stop brltty-udev.service sudo systemctl stop brltty.service sudo systemctl mask brltty-udev.servicemask是防止它被别的依赖重新拉起来。注意,如果这台机器真的接盲文显示设备,不要直接卸载brltty,用stop和mask更可控,需要时再unmask。普通串口调试环境里,停掉它一般不影响别的功能。停完把 CH340 拔下再插上,重新看:
ls -l /dev/ttyUSB* sudo dmesg -T | tail -n 20如果日志里出现ch341-uart converter now attached to ttyUSB0,节点基本就出来了。若仍然没有,继续看dmesg里的错误关键词。下面这张表是我排查枚举问题时常用的对照:
| 日志关键词 | 可能原因 | 下一步 |
|---|---|---|
ch341-uart converter now attached | 绑定成功 | 看/dev/ttyUSB0权限 |
brltty | 盲文服务抢占 | 停brltty-udev.service后重插 |
device descriptor read/64, error -71 | 线缆、接口、供电 | 换线、直插主板 USB 口 |
unable to enumerate USB device | USB 枚举失败 | 去掉 Hub,检查供电 |
ch341但无 tty | 驱动绑定异常 | modprobe -r ch341后重载 |
重载模块可以这样:
sudo modprobe -r ch341 sudo modprobe ch341modprobe -r是卸载,执行前确认没有串口工具占着设备,否则会提示模块在使用。重载后再插拔一次设备,让 USB 重新枚举。这个动作比重启整台机器轻,适合反复试。
3.2 固定设备名:modules-load.d 与 by-id 路径
手动modprobe成功,不等于重启后还在。让ch341开机自动加载,写一个modules-load.d配置:
echo "ch341" | sudo tee /etc/modules-load.d/ch341.conf sudo systemctl restart systemd-modules-load.service这个文件里一行一个模块名,systemd-modules-load.service启动时会读取。写完后可以用systemctl status systemd-modules-load.service --no-pager看有没有报错。注意文件名不要和已有配置冲突,ch341.conf这种就够清楚。
设备节点名也要注意。/dev/ttyUSB0不是永久名字,拔插顺序、多个 USB 串口同时插,编号都可能变。看固定路径:
ls -l /dev/serial/by-id/ ls -l /dev/serial/by-path/ udevadm info -q symlink -n /dev/ttyUSB0by-id通常包含设备序列信息,重插后相对固定;by-path跟物理 USB 口走,换口会变。/dev/ttyUSB0适合临时调试,写脚本、做长期采集时我一般用by-id或者后面第 4 章加的 udev 别名。路径对比如下:
| 路径 | 特点 | 适用场景 |
|---|---|---|
/dev/ttyUSB0 | 编号会变 | 临时插拔调试 |
/dev/serial/by-id/... | 跟设备标识走 | 脚本长期使用 |
/dev/serial/by-path/... | 跟物理口走 | 固定插口的设备 |
/dev/ch340 | 自定义别名 | 单设备、规则简单 |
udevadm info -q symlink -n /dev/ttyUSB0能看到当前节点关联的符号链接。如果by-id目录不存在,先确认udev正常、设备确实是 tty 类。不要把ttyUSB0写死进生产脚本,换一台机器或者多插一个模块就会翻车。
4. 权限与 udev 规则:让普通用户直接打开 CH340 串口
设备节点出来以后,下一步不是马上sudo picocom,而是把权限模型理清。Ubuntu 默认的/dev/ttyUSB0一般是root:dialout,权限0660。普通用户不在dialout组,就会看到Permission denied。长期用sudo打开串口,日志、锁文件、配置文件的属主都会乱,后面更麻烦。
4.1 dialout 组与权限模型:为什么不要 chmod 666
先看当前用户和节点权限:
id ls -l /dev/ttyUSB0如果输出是crw-rw---- 1 root dialout ... /dev/ttyUSB0,说明组权限已经给到dialout。把当前用户加进去:
sudo usermod -aG dialout "$(id -un)"-aG是追加组,不要写成-G覆盖原有组。执行后当前 shell 不会立刻生效,可以重新登录,或者临时用:
newgrp dialout groupsnewgrp会开一个新 shell,退出后回到原环境。最省事的还是注销重登。确认:
id -nG输出里出现dialout就对了。不要用sudo chmod 666 /dev/ttyUSB0图省事,这个权限在拔插、重启后会丢,而且把串口设备开放给所有用户,不是合格做法。sudo打开串口虽然能通,但picocom、minicom生成的锁文件和日志容易变成 root 属主,下次普通用户再开就可能被锁文件挡住。
4.2 写 99-ch340.rules:VID/PID、SYMLINK 与 GROUP 的取舍
只靠dialout组能解决权限,但设备名还是会变。写一条 udev 规则,把 VID/PID 匹配、权限和别名一次定下来:
sudo tee /etc/udev/rules.d/99-ch340.rules >/dev/null <<'EOF' SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE="0660", GROUP="dialout", SYMLINK+="ch340" EOF sudo udevadm control --reload-rules sudo udevadm trigger --subsystem-match=tty这条规则里,SUBSYSTEM=="tty"限定只处理 tty 设备;ATTRS{idVendor}和ATTRS{idProduct}匹配父 USB 设备的厂商 ID 和产品 ID,CH340 常见是1a86:7523,以lsusb实际输出为准;MODE="0660"给属主和组读写;GROUP="dialout"把组设为dialout;SYMLINK+="ch340"创建/dev/ch340这个稳定别名。这里用ATTRS而不是ATTR,是因为idVendor、idProduct在父 USB 设备上,当前 tty 节点上未必直接有。
规则写完后,重新插拔设备,检查:
ls -l /dev/ch340 ls -l /dev/ttyUSB0如果/dev/ch340没出现,先看规则文件权限和换行:
sudo cat /etc/udev/rules.d/99-ch340.rules sudo udevadm test /sys/class/tty/ttyUSB0udevadm test是模拟执行,不会真正改设备,但能看到规则有没有命中。规则文件名用99-是为了排在后面,避免被更早的规则覆盖。多个 CH340 同时插时,SYMLINK+="ch340"会冲突,可以改成SYMLINK+="ch340-%k",或者干脆在脚本里用by-id。单设备调试用/dev/ch340最顺手,多设备就不要偷这个懒。
4.3 ModemManager 与串口独占:谁在抢 /dev/ttyUSB0
节点有了、权限对了,串口还是打不开,就要看谁占着设备。ModemManager是常见嫌疑,它会扫描串口设备,把一些 USB 串口当成调制解调器。查状态:
systemctl status ModemManager --no-pager sudo fuser -v /dev/ttyUSB0fuser会列出占用进程。如果是ModemManager,可以先停:
sudo systemctl stop ModemManager但不建议上来就mask。这台机器如果真用 4G/5G 模块联网,ModemManager还有用。更细的做法是在 udev 规则里让 ModemManager 忽略这个设备:
sudo tee /etc/udev/rules.d/99-ch340.rules >/dev/null <<'EOF' SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE="0660", GROUP="dialout", ENV{ID_MM_DEVICE_IGNORE}="1", SYMLINK+="ch340" EOF sudo udevadm control --reload-rules sudo udevadm trigger --subsystem-match=ttyENV{ID_MM_DEVICE_IGNORE}="1"是给 ModemManager 看的标记,让它跳过这个设备。改完重插,再用fuser确认。还有一类占用是串口工具自己没退干净,比如screen挂在后台、minicom异常退出留下锁文件。先ps看进程,再决定是杀进程还是清锁文件,不要一上来就拔线。
5. 避坑与排查:Ubuntu 22.04 下 CH340 最常见的五类翻车
CH340 的坑不复杂,但很分散:有的在 USB 层,有的在 tty 层,有的在权限层,还有的在接线层。下面五条是我在 Ubuntu 22.04 上反复遇到的翻车记录,按“现象 -> 原因 -> 解决”写,遇到问题可以直接对号。
5.1 枚举与节点类问题:lsusb 有、ttyUSB 没有
现象一:lsusb能看到1a86:7523,但/dev/ttyUSB0不存在,dmesg里出现brltty。
原因:brltty把 CH340 当成盲文终端抢占了,USB 设备虽然枚举,但 tty 没注册出来。解决:先停服务再重插,不要直接删包:
sudo systemctl stop brltty-udev.service sudo systemctl stop brltty.service sudo systemctl mask brltty-udev.service停完拔插设备,再看dmesg和ls /dev/ttyUSB*。如果这台机器确实用盲文设备,改成临时stop,不要mask。
现象二:sudo modprobe ch341报Module ch341 not found。
原因:当前内核的模块包没装全,或者这个内核根本没编CONFIG_USB_SERIAL_CH341。解决:先补linux-modules-extra-$(uname -r),再modinfo ch341。如果仍然没有,换 Ubuntu 官方内核,不要从不明来源下载所谓“CH340 Linux 驱动压缩包”。内置模块能解决的事,不要引入外部编译风险。
现象三:dmesg反复出现device descriptor read/64, error -71或unable to enumerate USB device。
原因:多半是线缆、USB Hub、供电或接口接触。CH340 小板子供电不足时,枚举会反复失败。解决:换一根能传数据的 USB 线,直插主板后置 USB 口,去掉 Hub,检查模块供电。不要在这个阶段继续改 udev 规则,先把 USB 层弄干净。
5.2 权限与通信类问题:能打开但收不到数据
现象四:picocom报Permission denied,但/dev/ttyUSB0明明存在。
原因:当前用户不在dialout组,或者 udev 规则把GROUP写错,或者ModemManager占着设备。解决:按顺序查:
id -nG ls -l /dev/ttyUSB0 sudo fuser -v /dev/ttyUSB0id -nG没有dialout就重新登录;ls -l的组不对就改 udev 规则;fuser有占用就先处理占用进程。不要用chmod 666掩盖问题。
现象五:串口能打开,但收不到数据,或者全是乱码。
原因:波特率不对、TX/RX 没交叉、GND 没共地、流控没关,或者目标板电平不匹配。解决:先确认串口参数是115200 8N1、无流控;再确认 CH340 的 TX 接目标板 RX、RX 接目标板 TX、GND 对接;最后做一次回环测试,短接 CH340 的 TX 和 RX,看输入字符能不能回显。回环能通,问题就在接线或目标板;回环不通,问题在串口工具或驱动。
这五条里,前三条偏枚举,后两条偏通信。排查时不要跳步:先lsusb,再dmesg,再ls -l /dev/ttyUSB*,最后才开串口工具。顺序乱了,很容易把权限问题当成驱动问题。
6. 装完怎么验证:用 picocom 回环测试确认 CH340 真能收发
验证不要只看/dev/ttyUSB0在不在,那只能说明节点出来了。我一般固定跑三步:先看别名和权限,再开串口,最后做回环。
ls -l /dev/ch340 picocom -b 115200 --flow n /dev/ch340ls -l /dev/ch340应该指向ttyUSB0,属组是dialout,权限是crw-rw----。picocom里-b 115200是波特率,--flow n关闭硬件流控。进去后按Ctrl-A再按Ctrl-X退出。如果打不开,先回到第 4 章看dialout和fuser,不要反复重装工具。
回环测试更直接:断电后把 CH340 模块的 TX 和 RX 短接,再上电打开picocom,输入任意字符,屏幕上应该回显。能回显说明 USB、驱动、tty、权限、串口工具这条链全通了。不能回显就查线序和模块供电。验证项可以按下面这张表过一遍:
| 检查项 | 命令 | 预期 |
|---|---|---|
| 设备别名 | ls -l /dev/ch340 | 指向 ttyUSB0,组为 dialout |
| 模块加载 | `lsmod | grep ch341` |
| 内核日志 | `sudo dmesg -T | tail -n 20` |
| 串口打开 | picocom -b 115200 --flow n /dev/ch340 | 不报 Permission denied |
| 回环收发 | 短接 TX/RX 后输入字符 | 字符回显 |
从那以后我每次把 CH340 插到新机器上,都先跑一遍lsusb、dmesg、ls -l /dev/ch340这三步,再开picocom。这套习惯不花时间,但能少走很多“以为驱动坏了、其实是权限或线序”的弯路。希望帮到你。
本文还有配套的精品资源,点击获取