速览体育网

Good Luck To You!

Linux串口函数如何正确配置波特率及数据位收发?

串口通信作为一种基础的数据传输方式,在嵌入式开发、工业控制、设备调试等领域仍被广泛应用,Linux系统提供了丰富的串口操作函数,这些函数基于POSIX标准,通过终端设备文件(如/dev/ttyS0、/dev/ttyUSB0等)实现对串口的配置、读写及控制,本文将详细介绍Linux串口相关的核心函数、配置参数、读写操作及实战应用,帮助开发者掌握串口编程的关键技术。

Linux串口函数如何正确配置波特率及数据位收发?

Linux串口设备文件与权限管理

在Linux系统中,串口设备以文件形式存在于/dev目录下,常见的有物理串口(如/dev/ttyS0对应COM1)和USB转串口设备(如/dev/ttyUSB0),应用程序通过标准文件I/O函数(如open、read、write)操作这些设备文件,但需确保进程对设备文件具有读写权限,默认情况下,串口设备属于dialout组(或特定用户组),可通过chmod 666 /dev/ttyS0修改权限,或将用户添加到dialout组(sudo usermod -aG dialout $USER)以获得访问权限。

打开串口设备时,推荐使用open()函数的O_RDWR(读写模式)、O_NOCTTY(防止终端成为控制终端)和O_NDELAY(非阻塞模式,可选)标志位组合,

int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);  
if (fd < 0) {  
    perror("Failed to open serial port");  
    exit(EXIT_FAILURE);  
}  

核心串口配置函数:termios结构体详解

Linux串口的配置通过termios结构体实现,该结构体定义在<termios.h>中,包含控制模式、输入模式、输出模式、本地模式及控制字符等参数,核心配置函数包括tcgetattr()(获取当前配置)、tcsetattr()(设置配置)及波特率设置函数cfsetispeed()cfsetospeed()

获取与设置串口属性

tcgetattr()函数用于读取当前串口配置,存储到termios结构体中:

struct termios options;  
tcgetattr(fd, &options);  

tcsetattr()函数用于修改配置,其第三个参数决定生效时机:TCSANOW(立即生效)、TCSADRAIN(输出完成后生效)、TCSAFLUSH(清空输入/输出缓冲区后生效)。

Linux串口函数如何正确配置波特率及数据位收发?

波特率配置

波特率通过c_cflag成员的Baud Rate位域设置,例如设置9600波特率:

cfsetispeed(&options, B9600);  // 输入波特率  
cfsetospeed(&options, B9600);  // 输出波特率  

常用波特率常量包括B300、B1200、B9600、B115200等,需确保两端设备波特率一致。

数据位、停止位与校验位

  • 数据位:通过c_cflag的CSIZE位域设置,如CS8(8位数据位),需先清除原有设置:
    options.c_cflag &= ~CSIZE;  // 清除数据位设置  
    options.c_cflag |= CS8;     // 设置8位数据位  
  • 停止位:通过c_cflag的CSTOPB位控制,1位停止位时不设置该位,2位停止位时设置options.c_cflag |= CSTOPB;
  • 校验位:通过c_cflag的PARENB、PARODD控制,如无校验位时options.c_cflag &= ~PARENB;奇校验时options.c_cflag |= PARENB | PARODD;偶校验时options.c_cflag |= PARENB并清除PARODD

其他关键配置

  • 硬件流控:禁用RTS/CTS流控时,需清除c_cflag的CRTSCTS位(options.c_cflag &= ~CRTSCTS)。
  • 软件流控:通过c_iflag的IXON、IXOFF等位控制,通常禁用软件流控(options.c_iflag &= ~(IXON | IXOFF | IXANY))。
  • 输入/输出模式:默认为规范模式(ICANON),此时数据按行处理;非规范模式适合二进制数据传输,需设置options.c_lflag &= ~ICANON,并通过c_cc中的VMIN(最小读取字节数)和VTIME(超时时间,单位为0.1秒)控制读取行为。

串口读写操作与错误处理

串口数据传输主要通过read()write()函数实现,需注意串口是流式设备,数据可能被拆分成多次读取。

读取数据

read()函数从串口缓冲区读取数据到指定缓冲区,返回读取的字节数(出错时返回-1),非阻塞模式下,若无数据可读则返回-1并设置errno为EAGAIN;阻塞模式下会等待数据到达,读取10字节数据:

char buffer[1024];  
int n = read(fd, buffer, 10);  
if (n < 0) {  
    perror("Failed to read from serial port");  
} else {  
    printf("Read %d bytes: %.*s\n", n, n, buffer);  
}  

写入数据

write()函数将缓冲区数据写入串口,返回实际写入的字节数,需处理部分写入的情况(例如网络延迟导致写入中断),可通过循环写入确保数据完整:

Linux串口函数如何正确配置波特率及数据位收发?

const char *data = "Hello, Serial Port!";  
int len = strlen(data);  
int written = 0;  
while (written < len) {  
    int n = write(fd, data + written, len - written);  
    if (n < 0) {  
        perror("Failed to write to serial port");  
        break;  
    }  
    written += n;  
}  

缓冲区控制与错误恢复

  • 清空缓冲区tcflush()函数可清空输入/输出缓冲区,参数TCIFLUSH(输入缓冲区)、TCOFLUSH(输出缓冲区)、TCIOFLUSH(双向清空)。
  • 等待输出完成tcdrain()函数阻塞程序,直到所有输出数据发送完毕。
  • 错误处理:串口通信中常见错误包括帧错误(FE)、奇偶校验错误(PE)、溢出错误(OE),可通过c_iflag的IGNPAR(忽略奇偶校验错误)或PARMRK(标记错误字符)处理。

实战示例:简单串口回显程序

以下是一个完整的串口回显程序,实现从串口读取数据并写回:

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <fcntl.h>  
#include <termios.h>  
int main() {  
    int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY);  
    if (fd < 0) {  
        perror("Failed to open serial port");  
        return -1;  
    }  
    struct termios options;  
    tcgetattr(fd, &options);  
    // 配置串口参数:9600波特率,8数据位,无校验,1停止位  
    cfsetispeed(&options, B9600);  
    cfsetospeed(&options, B9600);  
    options.c_cflag &= ~PARENB;   // 无校验位  
    options.c_cflag &= ~CSTOPB;   // 1停止位  
    options.c_cflag &= ~CSIZE;  
    options.c_cflag |= CS8;       // 8数据位  
    options.c_cflag &= ~CRTSCTS;  // 禁用硬件流控  
    // 输入/输出模式:非规范模式,不处理控制字符  
    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);  
    options.c_oflag &= ~OPOST;    // 原始输出模式  
    // 设置超时:100ms内读取至少1字节  
    options.c_cc[VMIN] = 1;  
    options.c_cc[VTIME] = 1;  
    tcsetattr(fd, TCSANOW, &options);  
    char buffer[1024];  
    while (1) {  
        int n = read(fd, buffer, sizeof(buffer) - 1);  
        if (n > 0) {  
            buffer[n] = '\0';  
            printf("Received: %s", buffer);  
            write(fd, buffer, n);  // 回显  
        }  
    }  
    close(fd);  
    return 0;  
}  

编译并运行程序后,串口助手发送数据即可看到回显效果。

应用场景与注意事项

Linux串口函数广泛应用于嵌入式设备调试(如树莓派、Arduino)、工业传感器数据采集(如温湿度、GPS模块)、医疗设备通信等领域,开发时需注意:

  1. 权限管理:确保程序对串口设备具有访问权限,避免因权限不足导致操作失败。
  2. 参数匹配:串口两端需保持波特率、数据位、停止位、校验位一致,否则数据传输会出现乱码。
  3. 异常处理:对read()write()等函数的返回值进行检查,处理部分读写、设备断开等情况。
  4. 资源释放:程序退出前需调用close()关闭串口,避免资源泄漏;若程序异常终止,可通过flock()或文件锁机制防止其他进程访问。

通过合理配置termios结构体和灵活运用串口函数,可高效实现Linux系统下的串口通信功能,满足不同场景的数据传输需求。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

«    2026年2月    »
1
2345678
9101112131415
16171819202122
232425262728
控制面板
您好,欢迎到访网站!
  查看权限
网站分类
搜索
最新留言
文章归档
网站收藏
友情链接

Powered By Z-BlogPHP 1.7.4

Copyright Your WebSite.Some Rights Reserved.