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

相关文章

Python实现字典转字符串的五种方法

《Python实现字典转字符串的五种方法》本文介绍了在Python中如何将字典数据结构转换为字符串格式的多种方法,首先可以通过内置的str()函数进行简单转换;其次利用ison.dumps()函数能够... 目录1、使用json模块的dumps方法:2、使用str方法:3、使用循环和字符串拼接:4、使用字符

Linux云服务器手动配置DNS的方法步骤

《Linux云服务器手动配置DNS的方法步骤》在Linux云服务器上手动配置DNS(域名系统)是确保服务器能够正常解析域名的重要步骤,以下是详细的配置方法,包括系统文件的修改和常见问题的解决方案,需要... 目录1. 为什么需要手动配置 DNS?2. 手动配置 DNS 的方法方法 1:修改 /etc/res

Redis中Hash从使用过程到原理说明

《Redis中Hash从使用过程到原理说明》RedisHash结构用于存储字段-值对,适合对象数据,支持HSET、HGET等命令,采用ziplist或hashtable编码,通过渐进式rehash优化... 目录一、开篇:Hash就像超市的货架二、Hash的基本使用1. 常用命令示例2. Java操作示例三

Linux创建服务使用systemctl管理详解

《Linux创建服务使用systemctl管理详解》文章指导在Linux中创建systemd服务,设置文件权限为所有者读写、其他只读,重新加载配置,启动服务并检查状态,确保服务正常运行,关键步骤包括权... 目录创建服务 /usr/lib/systemd/system/设置服务文件权限:所有者读写js,其他

Redis中Set结构使用过程与原理说明

《Redis中Set结构使用过程与原理说明》本文解析了RedisSet数据结构,涵盖其基本操作(如添加、查找)、集合运算(交并差)、底层实现(intset与hashtable自动切换机制)、典型应用场... 目录开篇:从购物车到Redis Set一、Redis Set的基本操作1.1 编程常用命令1.2 集

Linux挂载linux/Windows共享目录实现方式

《Linux挂载linux/Windows共享目录实现方式》:本文主要介绍Linux挂载linux/Windows共享目录实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录文件共享协议linux环境作为服务端(NFS)在服务器端安装 NFS创建要共享的目录修改 NFS 配

通过React实现页面的无限滚动效果

《通过React实现页面的无限滚动效果》今天我们来聊聊无限滚动这个现代Web开发中不可或缺的技术,无论你是刷微博、逛知乎还是看脚本,无限滚动都已经渗透到我们日常的浏览体验中,那么,如何优雅地实现它呢?... 目录1. 早期的解决方案2. 交叉观察者:IntersectionObserver2.1 Inter

Spring Gateway动态路由实现方案

《SpringGateway动态路由实现方案》本文主要介绍了SpringGateway动态路由实现方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随... 目录前沿何为路由RouteDefinitionRouteLocator工作流程动态路由实现尾巴前沿S

JavaScript对象转数组的三种方法实现

《JavaScript对象转数组的三种方法实现》本文介绍了在JavaScript中将对象转换为数组的三种实用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友... 目录方法1:使用Object.keys()和Array.map()方法2:使用Object.entr

k8s中实现mysql主备过程详解

《k8s中实现mysql主备过程详解》文章讲解了在K8s中使用StatefulSet部署MySQL主备架构,包含NFS安装、storageClass配置、MySQL部署及同步检查步骤,确保主备数据一致... 目录一、k8s中实现mysql主备1.1 环境信息1.2 部署nfs-provisioner1.2.