Linux下利用select实现串口数据读取过程

2025-09-30 01:50

本文主要是介绍Linux下利用select实现串口数据读取过程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Linux下利用select实现串口数据读取过程》文章介绍Linux中使用select、poll或epoll实现串口数据读取,通过I/O多路复用机制在数据到达时触发读取,避免持续轮询,示例代码展示设...

linux 系统里,我们可以借助 selectpoll 或者 epoll 这些 I/O 多路复用机制达成串口数据读取的触发方式。

这些机制能够让程序在特定文件描述符(像串口设备文件描述符)有数据可读时得到通知,进而进行数据读取操作,而不是像轮询方式那样持续调用 read 函数。

示例代码(使用select实现)

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <termIOS.h>
#include <unistd.h>
#include <sys/select.h>

// 设置串口波特率
void SetSpeed(int fd, int speed) {
    struct termios options;
    tcgetattr(fd, &options);
    switch (speed) {
        case 115200:
            cfsetispeed(&options, B115200);
            cfsetospeed(&options, B115200);
            break;
        // 可以添加更多波特率设置
        default:
            cfsetispeed(&options, B115200);
            cfsetospeed(&options, B115200);
            break;
    }
    tcsetattr(fd, TCSANOW, &options);
}

// 设置串口参数
void SetParity(int fd, int databits, int stopbits, char parity) {
    struct termios options;
    tcgetattr(fd, &options);

    // 设置数据位
    options.c_cflag &= ~CSIZE;
    switch (databits) {
        case 7:
            options.c_cflag |= CS7;
            break;
        case 8:
            options.c_cflag |= CS8;
            break;
        default:
            options.c_cflag |= CS8;
            break;
    }

    // 设置奇偶校验位
    switch (parity) {
        case 'n':
        case 'N':
            options.c_cflag &= ~PARENB;
            options.c_cflag &= ~PARODD;
            break;
        case 'o':
        case 'O':
            options.c_cflag |= (PARODD | PARENB);
            break;
  China编程      case 'e':
        case 'E':
            options.c_cflag |= PARENB;
            options.c_cflag &= ~PARODD;
            break;
        default:
            options.c_cflag &= ~PARENB;
            options.c_cflag &= ~PARODD;
            break;
    }

    // 设置停止位
    switch (stopbits) {
        case 1:
            options.c_cflag &= ~CSTOPB;
            break;
        case nhVqZVTH2:
            options.c_cflag |= CSTOPB;
            break;
        default:
            options.c_cflag &= ~CSTOPB;
            break;
    }

    tcsetattr(fd, TCSANOW, &options);
}

int main(void) {
    int fd;
    unsigned char buf[300];
    unsigned short len;
    fd = open("/dev/ttyS1", O_RdwR);
    if (fd == -1) {
        perror("can't open serial\n");
        return -1;
    }

    SetParity(fd, 8, 1, 'n');
    SetSpeed(fd, 115200);

    fd_set readfds;
    struct timeval timeout;

    while (1) {
        // 清空文件描述符集
        FD_ZERO(&readfds);
        // 将串口文件描述符加入读文件描述符集
        FD_SET(fd, &readfds);

        // 设置超时时间
        timeout.tv_sec = 0;
        timeout.tv_usec = 20000;

        // 调用 select 函数等待事件发生
        int activity = select(fd + 1, &readfds, NULL, NULL, &timeout);

        if (activityjavascript < 0) {
            perror("select error");
            break;
        www.chinasem.cn} else if (activity > 0) {
            // 检查是否是串口文件描述符有数据可读
            if (FD_ISSET(fd, &readfds)) {
                len = read(fd, buf, 100);
                if (len > 0) {
    python                write(fd, buf, len);
                }
            }
        }
    }

    close(fd);
    return 0;
}

代码解释

SetSpeed 函数

  • 此函数用于设置串口的波特率,
  • 它借助 tcsetattr 函数来配置串口的输入和输出波特率

SetParity 函数

  • 该函数用于设置串口的数据位、停止位和奇偶校验位
  • 同样是通过 tcsetattr 函数来完成串口参数的配置

main 函数

  • 打开串口设备文件 /dev/ttyS1,并且设置串口参数。
  • 构建一个 fd_set 类型的文件描述符集 readfds,把串口文件描述符 fd 添加到该集合中。
  • 设定一个超时时间 timeout,防止 select 函数一直阻塞。
  • 调用 select 函数等待事件发生,若有数据可读,select 函数会返回大于 0 的值。
  • 利用 FD_ISSET 宏检查是否是串口文件描述符有数据可读,若有则调用 read 函数读取数据,然后将数据回写到串口。

通过这种方式,程序就无需持续轮询 read 函数,而是在有数据到达时才进行读取操作。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持China编程(www.chinasem.cn)。

这篇关于Linux下利用select实现串口数据读取过程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1156102

相关文章

C#借助Spire.XLS for .NET实现在Excel中添加文档属性

《C#借助Spire.XLSfor.NET实现在Excel中添加文档属性》在日常的数据处理和项目管理中,Excel文档扮演着举足轻重的角色,本文将深入探讨如何在C#中借助强大的第三方库Spire.... 目录为什么需要程序化添加Excel文档属性使用Spire.XLS for .NET库实现文档属性管理Sp

Python+FFmpeg实现视频自动化处理的完整指南

《Python+FFmpeg实现视频自动化处理的完整指南》本文总结了一套在Python中使用subprocess.run调用FFmpeg进行视频自动化处理的解决方案,涵盖了跨平台硬件加速、中间素材处理... 目录一、 跨平台硬件加速:统一接口设计1. 核心映射逻辑2. python 实现代码二、 中间素材处

Linux镜像文件制作方式

《Linux镜像文件制作方式》本文介绍了Linux镜像文件制作的过程,包括确定磁盘空间布局、制作空白镜像文件、分区与格式化、复制引导分区和其他分区... 目录1.确定磁盘空间布局2.制作空白镜像文件3.分区与格式化1) 分区2) 格式化4.复制引导分区5.复制其它分区1) 挂载2) 复制bootfs分区3)

Java数组动态扩容的实现示例

《Java数组动态扩容的实现示例》本文主要介绍了Java数组动态扩容的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1 问题2 方法3 结语1 问题实现动态的给数组添加元素效果,实现对数组扩容,原始数组使用静态分配

Python实现快速扫描目标主机的开放端口和服务

《Python实现快速扫描目标主机的开放端口和服务》这篇文章主要为大家详细介绍了如何使用Python编写一个功能强大的端口扫描器脚本,实现快速扫描目标主机的开放端口和服务,感兴趣的小伙伴可以了解下... 目录功能介绍场景应用1. 网络安全审计2. 系统管理维护3. 网络故障排查4. 合规性检查报错处理1.

MySQL快速复制一张表的四种核心方法(包括表结构和数据)

《MySQL快速复制一张表的四种核心方法(包括表结构和数据)》本文详细介绍了四种复制MySQL表(结构+数据)的方法,并对每种方法进行了对比分析,适用于不同场景和数据量的复制需求,特别是针对超大表(1... 目录一、mysql 复制表(结构+数据)的 4 种核心方法(面试结构化回答)方法 1:CREATE

Python轻松实现Word到Markdown的转换

《Python轻松实现Word到Markdown的转换》在文档管理、内容发布等场景中,将Word转换为Markdown格式是常见需求,本文将介绍如何使用FreeSpire.DocforPython实现... 目录一、工具简介二、核心转换实现1. 基础单文件转换2. 批量转换Word文件三、工具特性分析优点局

Springboot3统一返回类设计全过程(从问题到实现)

《Springboot3统一返回类设计全过程(从问题到实现)》文章介绍了如何在SpringBoot3中设计一个统一返回类,以实现前后端接口返回格式的一致性,该类包含状态码、描述信息、业务数据和时间戳,... 目录Spring Boot 3 统一返回类设计:从问题到实现一、核心需求:统一返回类要解决什么问题?

详解C++ 存储二进制数据容器的几种方法

《详解C++存储二进制数据容器的几种方法》本文主要介绍了详解C++存储二进制数据容器,包括std::vector、std::array、std::string、std::bitset和std::ve... 目录1.std::vector<uint8_t>(最常用)特点:适用场景:示例:2.std::arra

Java使用Spire.Doc for Java实现Word自动化插入图片

《Java使用Spire.DocforJava实现Word自动化插入图片》在日常工作中,Word文档是不可或缺的工具,而图片作为信息传达的重要载体,其在文档中的插入与布局显得尤为关键,下面我们就来... 目录1. Spire.Doc for Java库介绍与安装2. 使用特定的环绕方式插入图片3. 在指定位