Linux 串口终端完全指南:从基础到实战

串口(Serial Port)作为一种古老而可靠的通信接口,至今仍在嵌入式系统、物联网设备、工业控制等领域发挥着不可替代的作用。在 Linux 系统中,串口不仅是硬件调试的“瑞士军刀”(如通过串口调试树莓派、路由器),也是设备间数据交换的重要桥梁(如 Arduino 与上位机通信、Modem 模块 AT 指令交互)。

本文将从串口基础讲起,详细介绍 Linux 系统下串口的设备表示、参数配置、终端工具使用、编程访问方法,并结合实战案例与故障排查技巧,帮助读者全面掌握 Linux 串口终端的应用。无论你是嵌入式开发者、Linux 系统管理员,还是物联网爱好者,本文都能为你提供清晰的操作指南和深度的技术解析。

目录#

  1. 简介
  2. 串口基础与 Linux 设备表示
    • 2.1 什么是串口?
    • 2.2 Linux 中的串口设备文件
  3. 硬件连接与设备识别
    • 3.1 常见串口硬件
    • 3.2 识别系统中的串口设备
    • 3.3 权限配置
  4. 串口参数配置详解
    • 4.1 核心通信参数
    • 4.2 使用 stty 命令临时配置
  5. 终端工具实操指南
    • 5.1 screen:轻量级终端模拟器
    • 5.2 minicom:功能丰富的经典工具
    • 5.3 picocom:极简主义的选择
    • 5.4 cutecom:图形化界面工具
  6. 编程访问串口:从 C 到 Python
    • 6.1 C 语言与 termios 库
    • 6.2 Python 与 pySerial 库
  7. 常见问题与故障排查
    • 7.1 权限拒绝(Permission Denied)
    • 7.2 通信参数不匹配
    • 7.3 硬件连接与数据丢失
  8. 最佳实践
    • 8.1 持久化设备命名(udev 规则)
    • 8.2 代码层面的规范
    • 8.3 测试与验证技巧
  9. 实战案例:与 Arduino 串口通信
  10. 总结
  11. 参考资料

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

配置与使用#

  1. 启动配置界面:
sudo minicom -s  # 需 sudo 权限以保存配置
  1. 选择 Serial port setup,配置:
    • A - Serial Device:输入 /dev/ttyUSB0
    • E - Bps/Par/Bits:输入 9600 8N1(按 Enter 选择对应参数)
    • F - Hardware Flow Control:设为 No(多数场景无需硬件流控)
  2. 选择 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 标准)实现串口的底层控制,需手动配置参数、读写数据。

核心步骤#

  1. 打开串口设备文件(open)。
  2. 获取当前配置(tcgetattr)。
  3. 修改配置(波特率、数据位等)。
  4. 应用配置(tcsetattr)。
  5. 读写数据(read/write)。
  6. 关闭串口(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 通信参数不匹配#

现象:接收到乱码或无响应。
排查:

  1. 确认双方波特率一致(最常见问题)。
  2. 检查数据位、校验位、停止位(如设备要求 7E1 而非 8N1)。
  3. 使用 stty 或终端工具重新配置参数。

7.3 硬件连接与数据丢失#

现象:发送数据后无接收,或接收数据不完整。
排查:

  1. 接线错误:确认 TX(发送)接对方 RX(接收),GND 共地(必须连接 GND!)。
  2. 流控问题:若启用硬件流控(RTS/CTS),需确保对应引脚连接;多数场景建议禁用流控。
  3. 环路测试:将模块的 TX 与 RX 引脚短接(自环),发送数据后若能收到,说明硬件正常。

8. 最佳实践#

8.1 持久化设备命名(udev 规则)#

USB 串口设备拔插后可能导致 /dev/ttyUSB* 编号变化(如从 ttyUSB0 变为 ttyUSB1)。通过 udev 规则可将设备绑定到固定名称(如 /dev/arduino)。

步骤:#

  1. 获取设备唯一属性(厂商 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
  1. 创建 udev 规则文件:
sudo nano /etc/udev/rules.d/99-usb-serial.rules

添加以下内容(替换为实际的 ID):

SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="arduino"
  1. 重载 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 端操作:#

  1. 上传 Arduino 代码后,通过 dmesg 确认设备文件(如 /dev/ttyACM0)。
  2. 使用 picocom 测试:
picocom /dev/ttyACM0 -b 115200
# 输入 ON 并回车,观察 Arduino 板载 LED 点亮,终端显示 "LED 已开启"
# 输入 OFF 并回车,LED 熄灭
  1. 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 串口操作,不仅能提升硬件调试效率,更能为物联网、嵌入式开发打下坚实基础。建议读者结合实际硬件动手实践,深入理解串口通信的细节与原理。

11. 参考资料#