Linux下串口通信的基础概念
串口通信是一种历史悠久且应用广泛的异步串行通信方式,通过数据线、地线等少数几根物理线路实现设备间的数据传输,在Linux系统中,串口设备通常被抽象为字符设备文件,位于/dev目录下,常见的命名包括/dev/ttyS0(主板串口)、/dev/ttyUSB0(USB转串口设备)和/dev/ttyAMA0(树莓派等嵌入式平台的串口),Linux通过文件操作接口(如open()、read()、write()、close())对串口设备进行统一管理,使得串口通信编程与普通文件操作类似,降低了开发难度。

串口通信的核心参数包括波特率、数据位、停止位、校验位和流控,波特率(Baud Rate)决定了数据传输的速率,常见的有9600、19200、115200等;数据位(Data Bits)通常为5~8位,默认为8位;停止位(Stop Bits)为1、1.5或2位;校验位(Parity)包括无校验、奇校验、偶校验等;流控(Flow Control)分为硬件流控(RTS/CTS)和软件流控(XON/XOFF),用于防止数据溢出,这些参数必须在通信双方保持一致,否则会导致数据解析错误。
串口设备的配置与权限管理
在Linux中使用串口前,需确保设备已正确识别并拥有操作权限,通过ls /dev/tty*命令可查看系统中的串口设备列表,dmesg | grep tty命令则可查看设备加载日志,USB转串口设备(如CH340、FT232)插入后,通常会自动识别为/dev/ttyUSBx设备,若未识别,可能需要安装usbutils工具和对应驱动(如libftdi或ch341-seria驱动)。
权限问题是串口通信常见的障碍,串口设备默认属于root用户或dialout用户组,普通用户直接访问会提示“Permission denied”,解决方案有两种:一是使用sudo命令提权;二是将当前用户加入dialout用户组,执行sudo usermod -aG dialout $USER后需重新登录生效,可通过chmod命令修改设备权限,如chmod 666 /dev/ttyUSB0允许所有用户读写,但此方法安全性较低,仅推荐临时测试使用。
串口编程的核心流程
Linux下串口编程主要基于C语言的文件I/O操作,核心流程包括设备打开、参数配置、数据读写和设备关闭。
打开串口设备
使用open()函数打开串口设备,需指定设备路径和访问标志(如O_RDWR表示读写模式),若设备被占用,open()会返回错误,可通过O_NDELAY或O_NONBLOCK标志设置非阻塞模式,示例代码:

int fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd < 0) {
perror("Failed to open serial port");
exit(EXIT_FAILURE);
}
配置串口参数
串口参数通过termios结构体配置,需包含头文件<termios.h>,配置步骤包括:获取当前参数、修改参数、设置参数到设备,关键参数包括波特率、数据位、停止位、校验位和流控,示例代码:
struct termios options; tcgetattr(fd, &options); // 获取当前参数 cfsetispeed(&options, B115200); // 设置输入波特率 cfsetospeed(&options, B115200); // 设置输出波特率 options.c_cflag &= ~PARENB; // 无校验位 options.c_cflag &= ~CSTOPB; // 1位停止位 options.c_cflag &= ~CSIZE; // 清除数据位设置 options.c_cflag |= CS8; // 8位数据位 options.c_cflag &= ~CRTSCTS; // 无硬件流控 options.c_cflag |= (CLOCAL | CREAD); // 忽略调制解调器控制信号,启用接收 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); // 立即应用参数
数据读写
串口数据读写使用read()和write()函数。read()函数会阻塞直到接收到指定字节数或超时,write()函数将数据写入串口缓冲区,示例代码:
char send_buf[] = "Hello, Serial Port!";
char recv_buf[1024];
ssize_t bytes_written = write(fd, send_buf, strlen(send_buf));
if (bytes_written < 0) {
perror("Failed to write data");
}
ssize_t bytes_read = read(fd, recv_buf, sizeof(recv_buf) - 1);
if (bytes_read < 0) {
perror("Failed to read data");
} else {
recv_buf[bytes_read] = '\0';
printf("Received: %s\n", recv_buf);
}
关闭串口设备
使用close()函数关闭串口,释放资源:
close(fd);
高级功能与错误处理
串口状态控制
termios结构体提供了丰富的控制功能,如tcflush()可清空输入/输出缓冲区(TCIFLUSH清空输入缓冲区,TCOFLUSH清空输出缓冲区,TCIOFLUSH清空两者);tcdrain()等待所有输出数据发送完成;tcflow()控制数据流(如TCOOFF暂停输出,TCOON恢复输出)。
多线程与异步通信
在复杂应用中,可采用多线程实现读写分离:一个线程负责发送数据,另一个线程负责接收数据,并通过互斥锁(pthread_mutex_t)保护共享资源,异步通信则可通过select()或poll()函数实现,监控串口文件描述符的可读/可写状态,避免阻塞,示例代码:

fd_set read_fds;
struct timeval timeout;
FD_ZERO(&read_fds);
FD_SET(fd, &read_fds);
timeout.tv_sec = 1; // 超时时间1秒
timeout.tv_usec = 0;
int ret = select(fd + 1, &read_fds, NULL, NULL, &timeout);
if (ret > 0 && FD_ISSET(fd, &read_fds)) {
// 串口可读,执行读取操作
}
错误处理与调试
串口通信中常见的错误包括设备未找到、权限不足、波特率不匹配、数据帧错误等,可通过perror()打印错误信息,或使用strerror(errno)获取错误描述,调试时,可借助minicom、screen等串口调试工具:
minicom -b 115200 -D /dev/ttyUSB0:以115200波特率打开串口screen /dev/ttyUSB0 115200:进入串口交互界面
实际应用场景
Linux串口通信在嵌入式系统、工业控制、物联网设备等领域应用广泛。
- 嵌入式设备开发:树莓派通过串口与传感器、单片机通信,实现数据采集或控制指令下发。
- 工业自动化:PLC(可编程逻辑控制器)通过串口与上位机通信,传输生产数据或控制参数。
- 物联网网关:串口作为低速设备接口,连接串口模块(如ESP8266)、RFID读卡器等,实现数据汇聚与上报。
在实际开发中,需根据场景选择合适的串口参数和通信协议(如Modbus、自定义协议),并注意处理数据帧的封装与解析,确保通信的可靠性和稳定性。
Linux下串口通信通过文件接口和termios结构体提供了灵活高效的解决方案,从设备配置、权限管理到数据读写与错误处理,开发者需掌握核心流程和高级功能,并结合实际场景优化通信参数,无论是简单的数据传输还是复杂的工业控制,Linux串口通信都凭借其稳定性和易用性,成为嵌入式与物联网开发的重要技术基础。

















