Linux 串口终端完全指南:从基础到实战
串口(Serial Port)作为一种古老而可靠的通信接口,至今仍在嵌入式系统、物联网设备、工业控制等领域发挥着不可替代的作用。在 Linux 系统中,串口不仅是硬件调试的“瑞士军刀”(如通过串口调试树莓派、路由器),也是设备间数据交换的重要桥梁(如 Arduino 与上位机通信、Modem 模块 AT 指令交互)。
本文将从串口基础讲起,详细介绍 Linux 系统下串口的设备表示、参数配置、终端工具使用、编程访问方法,并结合实战案例与故障排查技巧,帮助读者全面掌握 Linux 串口终端的应用。无论你是嵌入式开发者、Linux 系统管理员,还是物联网爱好者,本文都能为你提供清晰的操作指南和深度的技术解析。
目录#
- 简介
- 串口基础与 Linux 设备表示
- 2.1 什么是串口?
- 2.2 Linux 中的串口设备文件
- 硬件连接与设备识别
- 3.1 常见串口硬件
- 3.2 识别系统中的串口设备
- 3.3 权限配置
- 串口参数配置详解
- 4.1 核心通信参数
- 4.2 使用
stty命令临时配置
- 终端工具实操指南
- 5.1
screen:轻量级终端模拟器 - 5.2
minicom:功能丰富的经典工具 - 5.3
picocom:极简主义的选择 - 5.4
cutecom:图形化界面工具
- 5.1
- 编程访问串口:从 C 到 Python
- 6.1 C 语言与
termios库 - 6.2 Python 与
pySerial库
- 6.1 C 语言与
- 常见问题与故障排查
- 7.1 权限拒绝(Permission Denied)
- 7.2 通信参数不匹配
- 7.3 硬件连接与数据丢失
- 最佳实践
- 8.1 持久化设备命名(udev 规则)
- 8.2 代码层面的规范
- 8.3 测试与验证技巧
- 实战案例:与 Arduino 串口通信
- 总结
- 参考资料
1. 简介#
串口(Serial Port)作为一种古老而可靠的通信接口,至今仍在嵌入式系统、物联网设备、工业控制等领域发挥着不可替代的作用。在 Linux 系统中,串口不仅是硬件调试的“瑞士军刀”(如通过串口调试树莓派、路由器),也是设备间数据交换的重要桥梁(如 Arduino 与上位机通信、Modem 模块 AT 指令交互)。
本文将从串口基础讲起,详细介绍 Linux 系统下串口的设备表示、参数配置、终端工具使用、编程访问方法,并结合实战案例与故障排查技巧,帮助读者全面掌握 Linux 串口终端的应用。无论你是嵌入式开发者、Linux 系统管理员,还是物联网爱好者,本文都能为你提供清晰的操作指南和深度的技术解析。
2. 串口基础与 Linux 设备表示#
2.1 什么是串口?#
串口(串行接口)是一种通过逐位传输数据的通信方式,与并行接口(多线同时传输)相比,具有布线简单、成本低的特点,适用于中低速、远距离通信。常见的串口标准包括:
- RS-232:传统 DB9 接口,支持全双工通信,常见于工业设备。
- UART(通用异步收发传输器):嵌入式系统中最常用的串口类型(如树莓派的 GPIO 串口)。
- USB-to-Serial:通过 USB 接口模拟串口(如 CH340、PL2303 芯片的 USB 转串口模块),现代设备的主流选择。
串口通信依赖异步协议,双方需约定相同的通信参数(波特率、数据位等)才能正常交互。
2.2 Linux 中的串口设备文件#
Linux 系统将所有硬件抽象为文件,串口设备也不例外。串口对应的设备文件位于 /dev 目录下,命名规则如下:
| 设备文件 | 描述 | 典型场景 |
|---|---|---|
/dev/ttyS* | 传统硬件 UART 串口(如 PC 主板串口) | 老式工业设备、服务器调试口 |
/dev/ttyUSB* | USB 转串口设备(如 CH340、PL2303 芯片) | Arduino、传感器模块 |
/dev/ttyACM* | USB 复合设备(如 CDC-ACM 协议的 Arduino) | 带 USB 虚拟串口的嵌入式设备 |
/dev/ttyAMA* | 树莓派等 ARM 板载硬件串口 | 树莓派 GPIO 串口(UART0) |
例如,插入一个 USB 转串口模块后,系统通常会创建 /dev/ttyUSB0 设备文件,后续所有对该串口的操作都通过此文件进行。
3. 硬件连接与设备识别#
3.1 常见串口硬件#
- USB 转串口模块:如 CH340G、PL2303HX,一端接 USB 口,另一端引出 TX(发送)、RX(接收)、GND(地)引脚,用于连接嵌入式设备的 UART 接口。
- DB9 串口线:传统 RS-232 接口,需注意引脚定义(2-TX、3-RX、5-GND)。
- 嵌入式开发板:如 Arduino、树莓派(通过 GPIO 引出 UART 引脚)。
3.2 识别系统中的串口设备#
插入串口设备后,可通过以下命令确认其是否被系统识别:
方法 1:查看 /dev 目录#
ls /dev/tty{USB,S,ACM}* # 列出常见串口设备
# 输出示例:/dev/ttyUSB0 /dev/ttyS0方法 2:查看内核日志(dmesg)#
内核会记录设备插入事件,包括驱动加载和设备文件分配:
dmesg | grep -i tty # 过滤包含 "tty" 的日志
# 输出示例:
# usb 1-1: ch341-uart converter now attached to ttyUSB0上述日志表明,CH340 芯片的 USB 转串口设备已被识别,并分配到 /dev/ttyUSB0。
方法 3:查看设备详细信息(udevadm)#
udevadm info -q all -n /dev/ttyUSB0 # 查看 ttyUSB0 的详细属性
# 可获取厂商 ID(idVendor)、产品 ID(idProduct)等,用于后续 udev 规则配置3.3 权限配置#
Linux 默认对串口设备文件设置了严格的权限,普通用户直接访问可能报 Permission denied。解决方法:
临时方案(当前会话有效)#
sudo chmod 666 /dev/ttyUSB0 # 授予所有用户读写权限(不推荐长期使用)永久方案(添加用户到 dialout 组)#
串口设备通常属于 dialout 用户组,将当前用户加入该组即可:
sudo usermod -aG dialout $USER # 添加当前用户到 dialout 组注意:需注销并重新登录,权限方可生效。
4. 串口参数配置详解#
串口通信的核心是双方参数一致,否则会出现乱码或无法通信。以下是必须匹配的参数:
4.1 核心参数#
| 参数 | 说明 | 常见取值 |
|---|---|---|
| 波特率 | 每秒传输的比特数(bit/s),决定通信速度 | 9600, 19200, 115200(最常用) |
| 数据位 | 每帧数据中有效数据的位数 | 5, 6, 7, 8(8 位最常用) |
| 校验位 | 用于错误检测的额外位 | N(无校验), O(奇校验), E(偶校验) |
| 停止位 | 标识一帧数据结束的位数 | 1, 1.5, 2(1 位最常用) |
| 流控 | 防止数据溢出的机制 | 无(None), RTS/CTS(硬件流控), XON/XOFF(软件流控) |
最经典配置:8N1(8 数据位、无校验、1 停止位),配合 115200 波特率。
4.2 使用 stty 命令临时配置#
stty 命令可查看或修改串口参数(临时生效,设备关闭后失效):
stty -F /dev/ttyUSB0 # 查看当前参数
stty -F /dev/ttyUSB0 115200 cs8 -parenb -cstopb # 配置 115200 8N1
# 解释:
# 115200:波特率
# cs8:8 数据位
# -parenb:无校验(- 表示禁用)
# -cstopb:1 停止位(默认,若为 2 则用 cstopb)5. 终端工具实操指南#
Linux 提供多种终端工具用于直接与串口设备交互,适用于调试和手动测试。
5.1 screen:轻量级终端模拟器#
screen 是一款多功能终端复用工具,也可直接连接串口:
安装#
sudo apt install screen # Debian/Ubuntu
sudo yum install screen # CentOS/RHEL使用#
screen /dev/ttyUSB0 115200 # 连接串口,波特率 115200
# 退出方法:按 Ctrl+A,再按 K,输入 y 确认优势:无需复杂配置,适合快速测试;支持后台运行(Ctrl+A, D detach,screen -r 重新连接)。
5.2 minicom:功能丰富的经典工具#
minicom 是串口调试的老牌工具,支持参数保存、文件传输等功能。
安装#
sudo apt install minicom配置与使用#
- 启动配置界面:
sudo minicom -s # 需 sudo 权限以保存配置- 选择
Serial port setup,配置:A - Serial Device:输入/dev/ttyUSB0E - Bps/Par/Bits:输入9600 8N1(按 Enter 选择对应参数)F - Hardware Flow Control:设为No(多数场景无需硬件流控)
- 选择
Save setup as dfl保存为默认配置,退出配置界面进入终端。
常用操作:
- 发送文件:Ctrl+A → S,选择协议(如 XMODEM)
- 清屏:Ctrl+A → Z → C
- 退出:Ctrl+A → Q
5.3 picocom:极简主义的选择#
picocom 设计理念是“简单够用”,无菜单,纯命令行操作,适合脚本集成。
安装#
sudo apt install picocom使用#
picocom /dev/ttyUSB0 -b 115200 -e n # -b 波特率,-e n 禁用回显
# 退出:按 Ctrl+A,再按 Ctrl+X优势:启动速度快,参数通过命令行直接指定,适合自动化脚本。
5.4 cutecom:图形化界面工具#
若偏好 GUI,cutecom 提供直观的界面,适合新手:
安装与启动#
sudo apt install cutecom
cutecom # 启动图形界面在界面中选择设备文件、配置波特率,点击“Open”即可通信,支持十六进制发送/接收。
6. 编程访问串口:从 C 到 Python#
除了终端工具,还可通过编程直接控制串口,实现自动化通信。
6.1 C 语言与 termios 库#
Linux 中通过 termios 库(POSIX 标准)实现串口的底层控制,需手动配置参数、读写数据。
核心步骤#
- 打开串口设备文件(
open)。 - 获取当前配置(
tcgetattr)。 - 修改配置(波特率、数据位等)。
- 应用配置(
tcsetattr)。 - 读写数据(
read/write)。 - 关闭串口(
close)。
示例代码:串口发送字符串#
#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
int main() {
int fd;
struct termios tty;
// 1. 打开串口(O_RDWR:读写,O_NOCTTY:不将串口作为控制终端)
fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY);
if (fd < 0) {
perror("无法打开串口");
return -1;
}
// 2. 获取当前配置
if (tcgetattr(fd, &tty) != 0) {
perror("tcgetattr 失败");
close(fd);
return -1;
}
// 3. 配置波特率(115200)
cfsetospeed(&tty, B115200); // 输出波特率
cfsetispeed(&tty, B115200); // 输入波特率
// 4. 配置数据位(8 位)、无校验、1 停止位
tty.c_cflag &= ~PARENB; // 禁用校验位
tty.c_cflag &= ~CSTOPB; // 1 停止位(默认)
tty.c_cflag &= ~CSIZE; // 清除数据位设置
tty.c_cflag |= CS8; // 8 数据位
// 5. 禁用硬件流控
tty.c_cflag &= ~CRTSCTS;
// 6. 应用配置(TCSANOW:立即生效)
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
perror("tcsetattr 失败");
close(fd);
return -1;
}
// 7. 发送数据
const char *data = "Hello, Serial Port!\n";
write(fd, data, strlen(data));
// 8. 关闭串口
close(fd);
return 0;
}编译运行:
gcc serial_example.c -o serial_example
./serial_example # 需确保 /dev/ttyUSB0 权限正确6.2 Python 与 pySerial 库#
Python 通过 pySerial 库简化串口操作,适合快速开发。
安装#
pip install pyserial示例代码:读写串口数据#
import serial
import time
try:
# 打开串口(设备名、波特率、超时时间)
ser = serial.Serial(
port='/dev/ttyUSB0',
baudrate=115200,
bytesize=serial.EIGHTBITS, # 8 数据位
parity=serial.PARITY_NONE, # 无校验
stopbits=serial.STOPBITS_ONE, # 1 停止位
timeout=1 # 读超时(秒)
)
if not ser.is_open:
ser.open()
# 发送数据( bytes 类型)
ser.write(b"AT\r\n") # 发送 AT 指令(Modem 常用)
time.sleep(0.1) # 等待响应
# 读取数据
response = ser.read_all() # 读取所有缓存数据
print(f"收到响应:{response.decode('utf-8')}")
except serial.SerialException as e:
print(f"串口错误:{e}")
finally:
if 'ser' in locals() and ser.is_open:
ser.close() # 确保关闭串口关键 API:
serial.Serial():创建串口对象write(data):发送 bytes 数据read(size)/readline()/read_all():读取数据close():关闭串口
7. 常见问题与故障排查#
7.1 权限拒绝(Permission Denied)#
现象:open: Permission denied 或无法打开设备。
原因:用户无串口设备读写权限。
解决:
sudo usermod -aG dialout $USER # 添加用户到 dialout 组
# 注销后重新登录生效7.2 通信参数不匹配#
现象:接收到乱码或无响应。
排查:
- 确认双方波特率一致(最常见问题)。
- 检查数据位、校验位、停止位(如设备要求 7E1 而非 8N1)。
- 使用
stty或终端工具重新配置参数。
7.3 硬件连接与数据丢失#
现象:发送数据后无接收,或接收数据不完整。
排查:
- 接线错误:确认 TX(发送)接对方 RX(接收),GND 共地(必须连接 GND!)。
- 流控问题:若启用硬件流控(RTS/CTS),需确保对应引脚连接;多数场景建议禁用流控。
- 环路测试:将模块的 TX 与 RX 引脚短接(自环),发送数据后若能收到,说明硬件正常。
8. 最佳实践#
8.1 持久化设备命名(udev 规则)#
USB 串口设备拔插后可能导致 /dev/ttyUSB* 编号变化(如从 ttyUSB0 变为 ttyUSB1)。通过 udev 规则可将设备绑定到固定名称(如 /dev/arduino)。
步骤:#
- 获取设备唯一属性(厂商 ID 和产品 ID):
udevadm info -q all -n /dev/ttyUSB0 | grep -E "ID_VENDOR_ID|ID_MODEL_ID"
# 输出示例:
# E: ID_VENDOR_ID=1a86 # 厂商 ID(如 CH340 为 1a86)
# E: ID_MODEL_ID=7523 # 产品 ID- 创建 udev 规则文件:
sudo nano /etc/udev/rules.d/99-usb-serial.rules添加以下内容(替换为实际的 ID):
SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="arduino"- 重载 udev 规则:
sudo udevadm control --reload-rules && sudo udevadm trigger之后,该设备会被固定链接到 /dev/arduino,无需关心原始 ttyUSB* 编号。
8.2 代码层面的规范#
- 避免硬编码设备路径:使用配置文件或环境变量指定串口路径(如
/dev/arduino)。 - 错误处理:捕获串口打开失败、读写超时等异常(如 Python 中的
serial.SerialException)。 - 资源释放:确保程序退出前关闭串口(尤其在异常情况下)。
- 缓冲区处理:读取数据前清空输入缓冲区(
ser.flushInput()或tcflush)。
8.3 测试与验证技巧#
- 先用终端工具验证:在编写代码前,用
screen/picocom确认设备可正常通信(避免代码逻辑掩盖硬件问题)。 - 日志记录:记录串口收发数据(如打印发送/接收的十六进制值),便于调试。
- 压力测试:长时间发送数据,检查是否有丢包或缓冲区溢出(调整超时时间或缓冲区大小)。
9. 实战案例:与 Arduino 串口通信#
场景:通过 Linux 串口控制 Arduino LED#
硬件准备:#
- Arduino UNO(带 USB 转串口功能)
- 连接 Arduino 到 Linux 主机 USB 口
Arduino 代码(接收指令控制 LED):#
void setup() {
Serial.begin(115200); // 初始化串口,波特率 115200
pinMode(13, OUTPUT); // LED 接引脚 13(板载 LED)
}
void loop() {
if (Serial.available() > 0) {
String cmd = Serial.readStringUntil('\n'); // 读取指令(以换行结束)
cmd.trim(); // 去除空格和换行符
if (cmd == "ON") {
digitalWrite(13, HIGH);
Serial.println("LED 已开启");
} else if (cmd == "OFF") {
digitalWrite(13, LOW);
Serial.println("LED 已关闭");
} else {
Serial.println("未知指令,请发送 ON/OFF");
}
}
}Linux 端操作:#
- 上传 Arduino 代码后,通过
dmesg确认设备文件(如/dev/ttyACM0)。 - 使用
picocom测试:
picocom /dev/ttyACM0 -b 115200
# 输入 ON 并回车,观察 Arduino 板载 LED 点亮,终端显示 "LED 已开启"
# 输入 OFF 并回车,LED 熄灭- Python 自动化控制:
import serial
import time
ser = serial.Serial('/dev/ttyACM0', 115200, timeout=1)
time.sleep(2) # 等待 Arduino 重启(USB 连接后 Arduino 会复位)
ser.write(b"ON\n")
print(ser.readline().decode('utf-8').strip()) # 输出:LED 已开启
time.sleep(3)
ser.write(b"OFF\n")
print(ser.readline().decode('utf-8').strip()) # 输出:LED 已关闭
ser.close()10. 总结#
Linux 串口终端是连接物理世界与数字系统的重要接口,从嵌入式调试到工业控制均有广泛应用。本文从基础概念出发,覆盖了设备识别、参数配置、终端工具、编程访问、故障排查等核心内容,并通过实战案例展示了具体应用。
掌握 Linux 串口操作,不仅能提升硬件调试效率,更能为物联网、嵌入式开发打下坚实基础。建议读者结合实际硬件动手实践,深入理解串口通信的细节与原理。