干了这么多年Linux下的嵌入式开发和系统运维,串口始终是个绕不开的活儿。前两天帮同事排查一块开发板烧写失败的问题,折腾了半天,最后发现既不是波特率配错,也不是接线松动,而是系统压根没把USB转串口芯片识别出来。这种情况在Linux下太典型了:Windows下插上就能用的CH340,在Linux下经常要手动确认驱动、设备节点、权限、终端工具这些一层层的东西。
这篇东西就围绕“Linux下查看与设置串口信息和属性”这条主线,把我日常排查和配置串口(尤其是USB转串口和板载串口终端)的完整思路整理出来。内容包括怎么确认设备节点是否存在、驱动是否加载,怎么用stty查看和修改波特率/数据位/停止位/校验位,以及minicom、picocom、screen这些终端工具的选型和坑点。适合刚接触Linux串口调试的嵌入式开发新人,也适合偶尔要用串口连网络设备、交换机、路由器或单片机开发板的运维同学。
1. 先搞清楚串口设备在哪,驱动有没有起来
1.1 设备节点的基础认知
Linux下面一切都走文件系统这套逻辑,串口设备对应的就是 /dev 目录下的节点。传统板载串口通常叫 /dev/ttyS0、/dev/ttyS1,比如老式主板的COM1、COM2;USB转串口芯片则对应 /dev/ttyUSB0、/dev/ttyUSB1(FT232、CH340、CP2102这些常见芯片都是这个命名);还有一些PCIe或m.2扩展串口卡,可能是 /dev/ttyS4这种高位编号。
所以第一步永远是先确认节点在不在。插上设备后执行:
ls -l /dev/ttyUSB* ls -l /dev/ttyS*如果出现了 /dev/ttyUSB0,说明节点有了。如果什么都没输出,别急着怪硬件,先查系统认没认出芯片。
1.2 用 dmesg 和 lsusb 确认芯片型号
确认芯片是否被内核识别,最直接的办法是 dmesg 看内核日志。设备拔插后立刻执行:
dmesg | tail -20正常识别CH340时,日志里会出现类似 “usb 1-2: ch341-uart converter now attached to ttyUSB0” 或者 “cp210x converter now attached to ttyUSB0” 的字样。看到这句话,基本就是驱动没问题、节点也建好了。
再配合 lsusb 查看USB总线上挂着的设备:
lsusb输出里找厂家ID和产品ID。CH340通常是 “1a86:7523”,CP2102是 “10c4:ea60”,FT232是 “0403:6001”。这些信息在排查芯片型号和驱动问题时非常关键。
我遇到过一种情况:设备刚插上时能识别,过一会儿 ttyUSB0 就消失了。后来发现是USB口供电不稳,芯片反复掉线。这时候换一个供电更稳的USB口,或者用带屏蔽的USB线,问题就解决了。类似的坑还在后面,排查思路要按“节点->驱动->硬件供电”这个顺序来。
注意:如果内核没有对应驱动,内核日志里通常只有USB枚举信息,但不会出现挂载到ttyUSB0的记录。此时先确认你用的是不是常见芯片,CH340和CP210x在主流发行版里都自带驱动;少数小众芯片需要自己装驱动,这个后面单说。
1.3 板载串口与扩展串口卡的差异
处理板载串口时有个容易忽略的坑:Linux发行版为了降低启动等待时间,可能把某些ttyS端口屏蔽了,或者端口配置成非标准IO地址。这时候用 setserial 可以查看和设置串口的IO端口与IRQ信息:
setserial -g /dev/ttyS0如果输出提示 “Device or resource busy” 或者 “Permission denied”,说明端口可能被别的服务占用(比如getty、ModemManager),或者当前用户没有访问权限。板载串口的处理和老式ISA/PCI串口卡属性设置逻辑相近,核心就是确认IO地址、IRQ和UART类型这几项是否与硬件实际配置一致。
排查板载串口时还有一个思路值得尝试:设备节点不存在时,用 udevadm 重新触发硬件检测:
udevadm trigger udevadm settle然后再检查 /dev 目录。这一步在实际操作中解决过不少“明明硬件在,节点不创建”的怪问题,推荐优先尝试。
2. 串口工具怎么选:minicom、screen、picocom 横向对比
2.1 minicom:老牌工具,配置繁琐但功能最全
minicom 在Linux串口调试中的地位和 vim 在编辑器界的地位差不多,老、稳、功能全,但初次上手容易被配置界面劝退。第一次运行需要先配置:
sudo minicom -s进入配置菜单后选择 “Serial port setup”,把串口设备改成 /dev/ttyUSB0,波特率改成 115200 或其他你需要的值,数据位通常保持 8N1(8数据位、无校验、1停止位),然后 Save setup as dfl 保存为默认配置,以后直接输入 minicom 就能进入。
minicom 的退出方式很有年代感:先按 Ctrl+A,然后按 X,再回车确认。不熟悉的人第一次按下 Ctrl+A 后发现没反应,以为卡死了,其实是进入了快捷键模式。调出帮助菜单也是 Ctrl+A,然后按 Z。
minicom 的优势在于会话日志、收发文件(ZModem协议)这些功能齐全。比如你要用串口传一个固件包,在 minicom 里按 Ctrl+A,再按 S,选择 ZModem,就能直接发送文件到对端设备。这在嵌入式设备联网不方便、只能靠串口文件传输的场景下非常实用。
2.2 picocom:轻量准确的现代选择
如果只是连上设备看日志、敲命令,我更推荐 picocom。它没有菜单界面,参数全在命令行里指定,非常干净:
picocom -b 115200 -d 8 -p n -s 1 /dev/ttyUSB0-b 是波特率,-d 数据位,-p 校验位(n表示无校验),-s 停止位。退出方式是 Ctrl+A,Ctrl+X,比 minicom 简单多了。
picocom 还有一个很实用的功能:默认会把串口收到的内容实时打印到终端,同时可以通过 -l 参数开启日志记录,把所有收发内容写入文件。排查通信协议时特别香,回看数据不用靠肉眼盯屏幕。
日常调试我直接给 picocom 写了一个别名:
alias com='picocom -b 115200 -d 8 -p n -s 1 /dev/ttyUSB0'每次连接开发板就敲一个 com,效率比开工具软件快多了。
2.3 screen:万能终端还是串口终端?
screen 本来是终端复用工具,但用 screen 连接串口也是简化流程的好办法:
screen /dev/ttyUSB0 115200退出是 Ctrl+A,然后输入 :quit 回车。screen 的优点是系统自带率高,很多发行版默认就装了。缺点是出错提示不友好:设备没权限时会黑屏一闪而过,新手根本不知道发生了什么。所以用 screen 之前,一定要先确认设备节点存在且当前用户有权限。
另外 screen 连接串口时默认走的是原始模式,但某些终端控制字符还是会干扰显示,乱码的概率比 picocom 高一些。我的结论是:screen 适合临时救急,长期调试还是用 picocom 或 minicom。
2.4 工具选型总结
按场景给一个选择参考:
| 场景 | 推荐工具 | 理由 |
|---|---|---|
| 快速连接开发板终端 | picocom | 启动快,参数直观,日志方便 |
| 传输固件/文件 | minicom | ZModem集成好,操作成熟 |
| 系统没有额外工具可装 | screen | 大多数发行版自带,零安装成本 |
| 查看/修改串口属性 | stty | 纯命令行操作,脚本化方便,下面重点讲 |
3. stty:Linux下查看与设置串口属性的核心命令
3.1 用 stty 查看当前串口参数
stty 是Linux下最底层的串口属性查看与设置工具,它直接和终端驱动打交道,不依赖任何终端界面。查看串口当前参数用 -F 指定设备文件,-a 显示全部属性:
stty -F /dev/ttyUSB0 -a输出内容很多,重点关注这几个字段:
- speed 后面跟着的数字就是波特率,比如 115200
- cs8 表示数据位8位(cs5/cs6/cs7/cs8对应5/6/7/8位)
- -cstopb 表示1位停止位,cstopb 表示2位停止位
- -parenb 表示无校验位,parenb 表示启用校验(配合 parodd 是奇校验,-parodd 是偶校验)
这三个组合起来就是我们常说的 8N1、8E1、7E1 这类串口属性。
常见组合的对照关系列出来供参考:
| 参数组合 | 含义 |
|---|---|
| 115200 cs8 -cstopb -parenb | 115200波特率,8数据位,1停止位,无校验(8N1) |
| 9600 cs8 cstopb parenb parodd | 9600波特率,8数据位,2停止位,奇校验(8O2) |
| 19200 cs7 -cstopb parenb -parodd | 19200波特率,7数据位,1停止位,偶校验(7E1) |
3.2 用 stty 设置串口参数
设置参数同样用 -F 指定设备,后面直接跟要改的属性:
stty -F /dev/ttyUSB0 115200 cs8 -cstopb -parenb这条命令设置了常用的 115200 8N1。注意:stty 设置的是串口驱动层的属性,对端设备(比如单片机)如果你更改后出现乱码,优先确认对端设备的串口参数是不是和这里完全一致。
设置完成后可以再执行一次 -a 查看确认,这是我每次调试前的习惯动作。检查输出里的 speed、cs8、-cstopb、-parenb 是否都符合预期,再开始收发数据。
还有一个和实际场景强相关的操作:把串口设置为原始模式,避免终端驱动对数据进行额外处理(比如把回车转成换行、把特殊字符解释成控制键)。在做串口协议通信时,不设置 raw 模式是很容易踩的坑:
stty -F /dev/ttyUSB0 raw -echoraw 表示原始模式,-echo 表示不把收到的内容回显给发送端。调试单片机串口时,如果不加 raw,可能会出现你发 0x0A,对端收到的是 0x0D 0x0A 这种被系统改过的数据,排查半天都找不到原因。
3.3 脚本化设置串口的两种姿势
实际项目中经常需要把串口参数设置写进脚本或程序里。命令行层面可以直接在启动终端工具前用 stty 设置:
stty -F /dev/ttyUSB0 115200 cs8 -cstopb -parenb raw -echo picocom -b 115200 /dev/ttyUSB0这样能确保 picocom 连接前串口已经是我们要的状态。
在编程语言层面,Linux下最标准的方式是使用 termios 接口。C语言里要引入 <termios.h>,Python里用 pyserial 库,Go里用 github.com/tarm/serial,核心都是对这些属性的封装。以 Python pyserial 为例:
import serial ser = serial.Serial( port='/dev/ttyUSB0', baudrate=115200, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, timeout=1 ) ser.write(b'AT\r\n') data = ser.readline()这部分属于串口编程的范畴,这次不展开,但理解 stty 设置的底层参数后,再看任何语言的串口配置都会一通百通,因为它们映射的都是同一套 termios 数据结构。
3.4 硬件流控与软流控的判断
很多人在 Linux 下连串口时遇到数据收发异常,最后发现是流控设置不对。stty 输出里有两个关键字段:crtscts(硬件流控RTS/CTS)和 ixon/ixoff(软件流控XON/XOFF)。
默认情况下很多发行版会启用软件流控。ixoff 开启时,系统收到特定控制字符会自动暂停或恢复数据发送。但绝大多数嵌入式串口设备根本不用软件流控,这个特性反而会干扰数据内容。调试时如果发现数据莫名其妙地丢一段、停一下,检查一下:
stty -F /dev/ttyUSB0 -ixon -ixoff stty -F /dev/ttyUSB0 -crtscts-ixon关闭软件输出流控,-ixoff关闭软件输入流控,-crtscts关闭硬件流控。对大多数单片机、路由器、交换机的串口终端来说,关掉所有流控才是正确姿势。连接网络设备时例外,部分交换机要求启用硬件流控才能正常输出,所以设置之前最好先查一下对端设备的文档。
注意:stty 设置在重启或拔插设备后通常会失效,因为设备重新枚举时驱动会恢复默认参数。需要每次连接前重新设置,或者编写脚本统一完成“设置参数+连接终端”的整个流程。
4. 完整实操案例:连开发板、烧固件、查日志
4.1 场景一:连接嵌入式Linux开发板串口终端
嵌入式开发板的调试串口一般是 TTL 电平的,不能用普通RS232线直接连电脑,中间需要 USB转TTL 模块,也就是常说的 USB转串口 小板。接线虽然简单,但只有两条线要特别注意:TXD接对端RXD、RXD接对端TXD、GND接GND。如果接了地线还是没输出,多半是TXD和RXD接反了,开发板的丝印上通常会有标注。
接线完成后,步骤是这样:
- 插上USB转TTL模块,执行 dmesg | tail 看识别结果,确认 ttyUSB0 节点生成
- 用 stty 设置参数,开发板调试串口一般默认 115200 8N1:
stty -F /dev/ttyUSB0 115200 cs8 -cstopb -parenb raw -echo- 用 picocom 连接:
picocom -b 115200 /dev/ttyUSB0- 给开发板上电,终端窗口里应该能看到启动日志输出
启动日志能看到但不完整,经常是在 bootloader 阶段正常,进内核后卡住,这种情况后面讲排查思路。
4.2 场景二:串口烧写固件时的注意点
串口烧写失败是热搜词里出现频率很高的问题,实际项目中遇到的情况也相当多。常见表现是烧写工具卡在 “Connecting...”,或者烧写到一半报超时错误。
先排除最基础的设置问题:确认烧写工具里选择的串口号是 /dev/ttyUSB0 而不是 /dev/ttyS0,确认波特率与目标芯片的烧写协议匹配。很多单片机芯片烧写时的波特率不是默认的 115200,比如STM32的串口ISP默认可能是 115200 或 9600,ESP8266/ESP32 烧写时常用 460800 甚至更高,需要根据芯片手册设置。
接下来是硬件层面的几个坑:
- 开发板需要手动进入烧写模式(按住BOOT键再按复位,或者跳线帽短接),有些板子按住BOOT键的时间不够,系统直接进了正常启动流程
- 供电不稳会导致烧写中断,尤其是笔记本USB口同时挂着无线鼠标、USB Hub时更容易发生。换直接插主机后置USB口,或者给开发板单独供电
- 有的USB转TTL模块不支持高波特率,标称能到 2Mbps,实际在 921600 以上就丢数据。换一个主控芯片更好的模块(CP2102、FT232通常比某些杂牌CH340更稳)
Linux下的烧写操作还要注意权限问题,这类问题通常表现为:
open /dev/ttyUSB0: Permission denied解决思路是:不是用sudo绕过,而是把当前用户加入 dialout 组,因为串口设备默认属于 dialout 组:
sudo usermod -a -G dialout $USER注销重新登录后生效。组名在部分发行版中可能不同(比如 tty 组),可以用 ls -l /dev/ttyUSB0 查看设备所属组来确认。
4.3 场景三:查看串口设备更多底层信息
除了 stty,查看串口设备底层属性还有两个命令值得掌握。一个是前面提到的 setserial:
setserial -g /dev/ttyUSB0真正强大的是用 udevadm 查询设备的完整信息,包括驱动名称、设备路径、厂商ID、产品ID、序列号等,这对排查驱动匹配问题非常关键:
udevadm info -a -n /dev/ttyUSB0输出里能看到 ATTRS{idVendor}、ATTRS{idProduct} 这样的关键属性。当你需要根据特定厂商产品ID编写 udev 规则(比如给某个设备固定一个稳定的别名 /dev/ttyUSB_esp32)时,从上一步的输出中就能拿到确切参数。
做一个自定义串口别名的示例。新建 /etc/udev/rules.d/99-usb-serial.rules,内容大致是:
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", SYMLINK+="ttyUSB_mydevice"然后执行 udevadm control --reload-rules 并重新插拔设备。之后无论设备插入哪个USB口,都只有一个固定的 /dev/ttyUSB_mydevice 节点。在多设备调试场景中,这能省下大量找设备节点的时间。
5. 常见问题排查与避坑经验
5.1 权限问题:为什么提示 Permission denied
串口设备节点通常归属于 dialout 或 tty 组,普通用户没有访问权限。临时解决方案是 sudo 加在命令前面,长期解决方案是加入对应组。加入后需要注销重登,有些系统要求重启桌面会话才能生效。如果你不想注销,也可以使用 newgrp 命令临时切换组身份:
newgrp dialout另外注意:部分开发环境里使用了 systemd-logind 管理用户会话,组权限的重新加载会有延迟,验证是否生效可以通过 id 命令查看:
id输出里如果 gid 或者 groups 里包含 dialout,说明已生效。
5.2 设备节点不存在:可能的原因
dmesg 没有输出,说明内核根本没识别到USB芯片,优先检查硬件:换USB口、换线、确认模块供电。如果芯片识别但没生成 ttyUSB 节点,可能是驱动没加载。手动加载:
sudo modprobe ch341 sudo modprobe cp210x如果提示模块不存在,才需要编译安装第三方驱动。市面上绝大多数 USB转串口 芯片在内核主线里都有支持,连国产的 CH343、CH9102 等新型号在新版本内核里也原生支持,不用折腾编译。所以驱动不工作的情况真的不多,大部分“找不到设备”的问题根源是硬件接触不良或者线材质量问题。
5.3 乱码:先查波特率,再查电平
串口输出乱码的排查顺序:
- 波特率是否匹配。终端工具里设置115200,对端设备实际运行在9600,输出必然乱码
- 数据位、停止位、校验位是否匹配。很多定制协议不是标准的8N1,需要手动修改
- 电平是否一致。TTL电平的板子和RS232电平的串口直接连接,不仅乱码,严重时还会烧芯片。中间必须加RS232转TTL模块
- 检查是否启用了不该启用的流控,前面提到的 ixon/ixoff 也可能干扰数据
5.4 数据丢失:可能不是代码问题
串口丢数据经常被误判为程序bug,实际可能涉及几个层面:
- 操作系统层面:内核串口缓冲区不足,特别是高波特率大流量时。可以在代码里改用非阻塞读,或者减少读取间隔
- 终端工具层面:minicom 的显示跟不上,不代表数据真丢了,可以开日志文件确认
- 硬件层面:USB转TTL芯片质量差,高波特率下丢字节,典型的例子是杂牌CH340在 921600 波特率下频繁丢数据。解决办法是降低波特率,或换用CP2102/FT232这类更稳定的芯片
- 流控问题:前面特别提到的 ixoff 软件流控,对端设备可能发送了 XOFF 字符导致系统暂停接收,现象就是数据断断续续
排查数据丢失时,建议先用下面这个命令做一次纯数据回环测试:把USB转TTL模块的TXD和RXD短接,然后往串口发送数据,看是否能完整收回来。如果回环数据都丢,问题大概率是硬件或系统配置层面。
5.5 连接终端没有输出:常见于启动日志阶段
连接开发板后终端上没有任何输出,先按开发板复位键试一次。很多板子默认启动速度很快,你完成终端连接时U-Boot阶段已经过了,内核日志已经刷完,需要复位才能看到完整输出。如果复位后依然没有任何输出,检查一下:
- 接线顺序是否正确,TXD和RXD有没有反
- 模块的TXD/RXD引脚上是否有电平变化,用一个简单的LED电路或者万用表量一下
- 开发板的调试串口是否被 u-boot 环境变量禁用,比如有些板子默认 console 设置指向了其他串口
这张排查速查表是我每次解决串口问题时的快速索引,也分享给读者:
| 现象 | 优先排查项 | 次要排查项 |
|---|---|---|
| Permission denied | 用户是否加入 dialout 组 | 设备节点属组是否正常 |
| 找不到 ttyUSB0 | dmesg 是否有识别日志 | 换USB口、换线 |
| 输出乱码 | 波特率是否匹配 | 数据位/校验位、电平转换 |
| 数据断断续续 | 关闭 ixon/ixoff 流控 | 硬件质量、供电稳定性 |
| 烧写失败 | 是否进入烧写模式 | 高波特率改用稳定芯片、供电 |
| 连接后无输出 | 按复位键看启动日志 | 接线顺序、console 配置 |
6. 个人使用的日常调试流程
最后分享一下我自己在Linux下调试串口的固定流程,这个流程踩过不少坑后沉淀下来的,能最大限度减少掉坑概率:
第一步永远是用 stty -F /dev/ttyUSB0 -a 检查当前参数。不管昨天配置过什么,今天拔插一次设备后参数就可能变了。
第二步把流控全部关掉,设置 raw 模式。对绝大多数设备这是最保险的状态,避免系统层面的干扰。
第三步再连接终端工具。我主力用 picocom,只有传文件时才切到 minicom。
第四步是调试过程中出现任何异常,第一时间用 dmesg 看内核日志,很多串口问题其实在内核层就能看出端倪,而不是怀疑应用工具。
这套流程在处理 RTOS 单板、嵌入式Linux设备、路由器交换机调试时都适用。串口这个东西,说简单就是一根线发数据收数据,说复杂起来,驱动、设备节点、参数配置、用户权限、终端工具任何一个环节出问题,都能让调试卡住半天。把查看和设置串口信息这套基本功搞扎实了,后面不管是写串口程序还是做设备调试,都会顺手很多。