Linux串口开发是嵌入式系统、工业控制、物联网设备通信等领域的基础技术,它通过串行端口实现设备间的数据交互,具有协议简单、成本低廉、抗干扰能力强等优点,本文将从Linux串口基础、环境搭建、核心操作、编程实践及常见问题等方面,系统介绍Linux串口开发的关键知识点。

Linux串口基础概念
在Linux系统中,串口设备被抽象为字符设备文件,通常位于/dev目录下,常见的设备名包括/dev/ttyS0(内置串口)、/dev/ttyUSB0(USB转串口设备)、/dev/ttyAMA0(树莓派等嵌入式板载串口)等,每个串口设备对应一个唯一的设备文件,应用程序通过读写该文件实现与串口外设的通信。
串口通信的核心参数包括波特率(Baud Rate)、数据位(Data Bits)、停止位(Stop Bits)、校验位(Parity Bit)和流控制(Flow Control),波特率表示每秒传输的比特数,常见的有9600、115200等;数据位通常为5-8位,默认8位;停止位为1、1.5或2位;校验位用于简单错误检测,可选None、Even、Odd、Mark、Space;流控制则通过硬件(RTS/CTS)或软件(XON/XOFF)避免数据溢出,这些参数必须在通信双方保持一致,否则会导致数据解析错误。
开发环境搭建
1 硬件环境准备
硬件方面,需要一台Linux主机(或虚拟机)、串口设备(如PC自带串口、USB转串口模块)以及连接线(交叉串口线或直通串口线,取决于设备类型),对于USB转串口模块(如CH340、FT232),Linux通常会自动识别并生成设备文件(如/dev/ttyUSB0),可通过ls /dev/tty*命令查看。
2 软件环境配置
开发Linux串口程序主要依赖C语言和系统调用,无需额外安装IDE,但需确保系统包含必要的开发工具包,以Ubuntu为例,可通过以下命令安装基础开发工具:
sudo apt update && sudo apt install build-essential
推荐使用串口调试工具(如minicom、screen、cutecom)测试串口通信,安装minicom:
sudo apt install minicom
配置minicom时,需选择正确的串口设备(如/dev/ttyUSB0)、波特率等参数,即可通过命令行与串口设备交互。
串口核心操作
Linux串口开发的核心操作包括打开设备、配置参数、数据读写及关闭设备,主要通过文件I/O系统调用和termios结构体实现。

1 打开与关闭串口
使用open()函数打开串口设备,需指定设备文件路径和标志位,常用标志位包括:
O_RDWR:以读写方式打开;O_NOCTTY:防止终端成为控制终端;O_NDELAY:非阻塞模式(可选)。
int fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY);
if (fd < 0) {
perror("Failed to open serial port");
exit(EXIT_FAILURE);
}
关闭串口使用close()函数:close(fd)。
2 配置串口参数
串口参数通过termios结构体配置,该结构体定义在<termios.h>中,配置步骤如下:
- 获取当前配置:
tcgetattr(fd, &oldtio); - 修改配置:清空输入/输出缓冲区,设置波特率、数据位、停止位、校验位、流控制等;
- 应用配置:
tcsetattr(fd, TCSANOW, &newtio)(TCSANOW表示立即生效)。
示例配置(波特率115200、8数据位、无校验、1停止位、无流控):
struct termios newtio; tcgetattr(fd, &newtio); newtio.c_cflag &= ~PARENB; // 无校验位 newtio.c_cflag &= ~CSTOPB; // 1停止位 newtio.c_cflag &= ~CSIZE; newtio.c_cflag |= CS8; // 8数据位 newtio.c_cflag &= ~CRTSCTS; // 无流控 newtio.c_cflag |= (CLOCAL | CREAD); // 忽略调制解调器控制线,启用接收 cfsetispeed(&newtio, B115200); // 设置输入波特率 cfsetospeed(&newtio, B115200); // 设置输出波特率 newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 原始输入模式,不回显 newtio.c_oflag &= ~OPOST; // 原始输出模式 newtio.c_cc[VMIN] = 1; // 最小接收字符数 newtio.c_cc[VTIME] = 0; // 超时时间(0.1秒单位) tcflush(fd, TCIFLUSH); // 清空输入缓冲区 tcsetattr(fd, TCSANOW, &newtio);
3 数据读写
串口数据读写使用read()和write()函数。read()会阻塞直到接收到指定字节数或超时,write()将数据写入串口缓冲区。
char buf[1024];
int n = read(fd, buf, sizeof(buf)); // 读取数据
if (n > 0) {
printf("Received: %.*s\n", n, buf);
}
const char *msg = "Hello Serial Port";
write(fd, msg, strlen(msg)); // 发送数据
若需设置非阻塞模式,可在open()时添加O_NDELAY标志,或使用fcntl(fd, F_SETFL, O_NONBLOCK)修改文件状态。
串口编程实践
以下是一个完整的串口通信示例程序,实现向串口发送数据并接收回显(假设串口设备连接了回环测试线):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
int main() {
int fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY);
if (fd < 0) {
perror("Open serial port failed");
return -1;
}
struct termios options;
tcgetattr(fd, &options);
// 配置串口参数
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cflag &= ~CRTSCTS;
options.c_cflag |= (CLOCAL | CREAD);
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
options.c_oflag &= ~OPOST;
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 0;
tcsetattr(fd, TCSANOW, &options);
// 发送数据
const char *send_data = "Test Serial Communication\n";
write(fd, send_data, strlen(send_data));
printf("Sent: %s", send_data);
// 接收数据
char recv_buf[1024];
int recv_len = read(fd, recv_buf, sizeof(recv_buf) - 1);
if (recv_len > 0) {
recv_buf[recv_len] = '\0';
printf("Received: %s", recv_buf);
} else {
perror("Read failed");
}
close(fd);
return 0;
}
编译并运行:gcc serial_test.c -o serial_test && ./serial_test,若串口设备正常,应能看到发送和接收的数据。
常见问题与解决方案
1 权限问题
串口设备通常属于root用户或dialout组,普通用户可能无读写权限,解决方案:
- 临时修改权限:
sudo chmod 666 /dev/ttyUSB0; - 永久权限:创建udev规则,在
/etc/udev/rules.d/99-usb-serial.rules中添加KERNEL=="ttyUSB*", MODE="0666",然后执行sudo udevadm control --reload-rules && sudo udevadm trigger。
2 数据乱码或丢失
原因多为波特率、数据位等参数配置错误,或流控未关闭,需检查通信双方参数是否一致,确保串口无硬件流控(RTS/CTS)。
3 阻塞与非阻塞模式
阻塞模式下,read()会无限等待数据,可能导致程序卡死,可通过设置VMIN=0(立即返回)和VTIME>0(超时返回)实现非阻塞读取,或使用select()/poll()监控串口可读事件。
4 多线程/多进程访问
串口设备不支持并发访问,多线程/多进程读写时需加锁(如使用pthread_mutex_t),避免数据冲突。
Linux串口开发是嵌入式通信的重要技能,核心在于掌握设备文件操作、termios参数配置及数据读写控制,通过合理配置串口参数、选择合适的读写模式,并结合错误处理机制,可稳定实现设备间的串口通信,实际开发中,还需结合具体硬件平台和应用场景,优化数据传输效率和可靠性,以满足不同需求。












