2026/1/19 16:59:37
网站建设
项目流程
最大招聘网站,教学类网站怎么做,seo精华网站,自己建立公司网站手把手教你编译Linux下的CH340驱动#xff1a;从零开始#xff0c;不靠包管理器也能用串口你有没有遇到过这种情况#xff1a;手里的开发板插上电脑#xff0c;ls /dev/tty*死活看不到/dev/ttyUSB0#xff1f;dmesg 一查#xff0c;满屏都是unknown USB device或者no suc…手把手教你编译Linux下的CH340驱动从零开始不靠包管理器也能用串口你有没有遇到过这种情况手里的开发板插上电脑ls /dev/tty*死活看不到/dev/ttyUSB0dmesg 一查满屏都是unknown USB device或者no such device……而你用的不过是常见的 Arduino Nano CH340 版、ESP-12F 模块或者某宝十块钱包邮的 USB 转 TTL 线——核心芯片正是CH340。别急这多半不是硬件坏了而是你的 Linux 系统里缺了那个关键的小东西ch34x 驱动模块。更糟的是如果你用的是老旧发行版、定制嵌入式系统甚至没网的工控机想靠apt install或yum install安装驱动根本行不通。那怎么办总不能每次调试都换台电脑吧答案是自己动手编译一个.ko文件把驱动“种”进内核里。这篇文章不讲虚的也不复制粘贴手册。我会带你一步步从源码开始完成 CH340 驱动的获取、编译、安装和验证全过程。全程不需要联网下载额外包除了源码适合离线环境部署也帮你真正搞懂 Linux 内核模块是怎么跑起来的。为什么 CH340 在 Linux 上经常“失灵”我们先来理清楚一个问题为什么 FTDI 和 CP210x 几乎即插即用而 CH340 却常常要手动折腾简单说就一句话CH340 不是标准的 CDC ACM 设备。什么意思大多数现代 USB 转串芯片比如 FT232RL、CP2102遵循 USB 组织定义的CDC ACMCommunication Device Class - Abstract Control Model标准。这类设备一旦插入Linux 内核自带的cdc-acm驱动就会自动识别并绑定立刻生成/dev/ttyACM0或/dev/ttyUSB0。但 CH340 不走寻常路。它使用的是厂商自定义类bInterfaceClass 0xFF不属于任何标准类别。这就意味着必须有一个专门写给它的驱动程序才能工作。这个驱动就是ch34x.ko。好消息是从 Linux 内核4.10 开始官方已经将ch34x驱动合并进了主线代码树。所以如果你用的是较新的 Ubuntu、Debian、Fedora大概率插上去就能用。坏消息是- 很多国产开发板配套的镜像基于老内核如 3.18、4.4- 某些裁剪过的嵌入式系统为了精简体积直接去掉了ch34x模块- Secure Boot 启用后第三方模块加载受限这些情况都会导致你明明插了设备系统却“视而不见”。这时候你就得自己动手丰衣足食了。第一步确认问题出在驱动而不是别的地方在动手前先做一次快速诊断避免白忙一场。1. 插上设备看内核日志dmesg | tail -15如果看到类似输出usb 1-1: new full-speed USB device number 5 using xhci_hcd usb 1-1: New USB device found, idVendor1a86, idProduct7523 usb 1-1: Product: USB2.0-Serial usb 1-1: Manufacturer: wch.cn恭喜你USB 层已经识别成功VID 是1a86PID 是7523—— 这正是 CH340G 的标志性参数。但如果下面没有紧接着出现usbcore: registered new interface driver ch34x usbserial: USB Serial support registered for ch34x ch34x ttyUSB0: ch34x converter now attached那就说明驱动没加载。2. 检查是否已有 ch34x 模块运行lsmod | grep ch34x如果有输出说明模块已加载。如果没有再查一下系统有没有这个模块文件find /lib/modules/$(uname -r) -name ch34x.ko*如果找不到那就只能自己编译了。第二步准备编译环境要编译内核模块你需要三样东西当前运行内核的头文件headers构建工具链make, gcc驱动源码我们一个个来。1. 安装内核头文件最关键模块编译必须与当前运行的内核版本完全匹配。否则会出现Unknown symbol in module或Module version mismatch错误。查看当前内核版本uname -r # 输出示例5.4.0-42-generic根据你的发行版安装对应的头文件包发行版命令Ubuntu/Debiansudo apt install linux-headers-$(uname -r)CentOS/RHELsudo yum install kernel-devel-$(uname -r)Fedorasudo dnf install kernel-devel-$(uname -r)⚠️ 注意某些系统中uname -r返回的版本号可能无法直接用于包管理器例如带有本地修改的定制内核。此时需要手动查找匹配的 headers 包或从源码重建。2. 安装基本构建工具# Debian/Ubuntu sudo apt install build-essential # RHEL/CentOS/Fedora sudo yum groupinstall Development Tools3. 获取 CH340 驱动源码最稳妥的方式是从Linux 内核源码树中提取ch34x.c因为它保证与你当前使用的内核 API 兼容。但我们也可以直接从沁恒官网或 GitHub 上找开源版本。推荐使用社区维护良好的仓库git clone https://github.com/juliagoda/CH341SER.git cd CH341SER该仓库包含了适用于多种平台的ch34x.c和 Makefile并支持主流内核接口。结构大致如下CH341SER/ ├── ch34x.c ├── Makefile └── README.md第三步编写正确的 Makefile 来编译模块这是最容易出错的地方。很多人照搬网上老旧的 Makefile结果编译失败。我们要写一个符合kbuild 系统规范的双段式 Makefile。创建Makefile文件内容如下ifneq ($(KERNELRELEASE),) obj-m : ch34x.o else KDIR : /lib/modules/$(shell uname -r)/build PWD : $(shell pwd) default: $(MAKE) -C $(KDIR) M$(PWD) modules clean: rm -f *.o *.ko *.mod.* *.cmd *.markers *.order *.symvers endif关键点解释obj-m : ch34x.o表示我们要把ch34x.c编译为可加载模块注意是obj-m不是obj-y$(MAKE) -C $(KDIR)跳转到内核构建目录通常是/lib/modules/.../build它是指向真实内核源码的符号链接M$(PWD)告诉内核构建系统“回到当前目录继续编译模块”双段结构是为了兼容内核构建系统的递归调用机制保存后执行make如果一切顺利你会看到Building modules, stage 2. MODPOST 1 modules CC ch34x.mod.o LD [M] ch34x.ko并且生成了ch34x.ko文件。 成功一半了第四步加载模块并验证功能现在进入最后一步把.ko文件“注入”内核。1. 加载模块sudo insmod ch34x.ko不出意外的话你应该能在 dmesg 中看到ch34x: loading out-of-tree module taints kernel. USB Serial support registered for ch34x ch34x: ch34x converter detected usbcore: registered new interface driver ch34x ch34x ttyUSB0: ch34x converter now attached同时设备节点也生成了ls /dev/ttyUSB* # 应该输出 /dev/ttyUSB02. 测试通信可以用screen或minicom连接测试sudo screen /dev/ttyUSB0 115200如果你连接的是单片机并发送了日志这时应该能看到输出了按CtrlA→K→Y退出 screen。常见坑点与解决方法❌ 问题1insmod: error inserting ch34x.ko: -1 Invalid module format原因内核版本不匹配或者 headers 没装对。解决方案- 确认uname -r与安装的 headers 完全一致- 检查/lib/modules/$(uname -r)/build是否存在且能访问- 尝试重新安装 headers 包❌ 问题2Unknown symbol in module如 usb_serial_register这是典型的 API 变更问题。旧版驱动用了已被废弃的函数。解决方案- 使用更新的驱动源码优先选用 Linux 主线中的版本- 或打补丁修复符号引用建议参考 Linux 内核源码中的drivers/usb/serial/ch341.c注意名字是 ch341但它也支持 ch340❌ 问题3Secure Boot 阻止模块加载在启用了安全启动的系统上如 Ubuntu 20.04 默认开启加载第三方模块会报错The system is running in secure boot mode...解决方案有两个方法一禁用 Secure Boot临时方案进 BIOS 设置关闭 Secure Boot。方法二签名模块生产级做法生成密钥并对模块签名# 生成私钥和公钥 openssl req -new -x509 -newkey rsa:2048 -keyout MOK.priv -outform DER -out MOK.der -nodes -days 36500 -subj /CNCH34X Driver/ # 注册公钥到 MOKMachine Owner Key sudo mokutil --import MOK.der # 重启后按提示设置密码完成注册 # 签名模块 /usr/src/linux-headers-$(uname -r)/scripts/sign-file sha256 ./MOK.priv ./MOK.der ch34x.ko # 再加载 sudo insmod ch34x.ko这样就能通过 Secure Boot 验证了。如何让驱动开机自动加载每次重启都要手动insmod太麻烦。我们可以让它自动加载。方法1加入模块加载列表echo ch34x | sudo tee /etc/modules-load.d/ch34x.conf系统启动时会自动执行modprobe ch34x。方法2安装到系统模块路径sudo cp ch34x.ko /lib/modules/$(uname -r)/kernel/drivers/usb/serial/ sudo depmod -a然后就可以用modprobe ch34x替代insmod了。进阶技巧为 ARM 板交叉编译驱动如果你的目标平台是树莓派、全志H3/H5、RK3399 等 ARM 设备就不能在 x86 主机上直接编译。你需要做交叉编译。修改 Makefile 添加架构和工具链ARCH ? arm CROSS_COMPILE ? arm-linux-gnueabihf- KDIR : /path/to/target/kernel/build obj-m : ch34x.o all: $(MAKE) -C $(KDIR) ARCH$(ARCH) CROSS_COMPILE$(CROSS_COMPILE) M$(PWD) modules clean: rm -f *.o *.ko *.mod.* *.cmd *.markers *.order *.symvers然后在主机上运行make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- KDIR/home/user/rpi-kernel/build生成的.ko文件拷贝到开发板即可加载。总结一下我们到底学会了什么这不是一篇“复制命令就能跑”的快餐教程。我们真正掌握的是✅ 如何判断 CH340 设备是否被正确识别✅ 如何搭建独立的内核模块编译环境✅ 如何使用标准 kbuild 系统编译.ko文件✅ 如何手动加载模块并排查常见错误✅ 如何应对 Secure Boot 和交叉编译等现实挑战更重要的是你不再依赖别人打包好的.deb或.rpm文件。你可以面对任何一台没有网络、没有包管理器、甚至连驱动都没装的嵌入式设备自信地说一句“让我给你装个驱动。”而这正是嵌入式工程师的核心能力之一。最后一点建议虽然现在主流发行版基本都自带ch34x支持但在国产化替代浪潮下越来越多的设备采用 CH340/CH341 芯片。了解其驱动机制不仅能解决眼前问题还能帮助你在面试、项目评审、故障排查中脱颖而出。下次当你看到同事还在百度“Linux 插 CH340 没反应怎么办”你可以默默打开终端敲下make sudo insmod ch34x.ko然后看着/dev/ttyUSB0出现在屏幕上。那一刻你已经不是一个普通的使用者而是掌控系统的那个人。如果你觉得这篇实战指南有用欢迎收藏转发。也欢迎在评论区分享你在实际项目中遇到的奇葩驱动问题我们一起拆解解决。