Linux串口poll实现稳定读写 (linux串口poll读写)

在嵌入式开发中,串口是一种常用的通信方式,可以实现设备之间的数据传输。在Linux系统中,串口通信可以通过串口设备文件来实现。但是,在高速数据传输或大量数据读写的情况下,直接使用串口设备文件会出现延迟或数据丢失等问题。为了解决这些问题,可以使用串口poll技术来实现串口的稳定读写。

一、Linux串口通信

Linux系统将串口设备当作字符设备来进行管理,串口设备文件一般位于/dev/ttyS*,其中“*”代表串口号。例如,之一个串口设备文件为/dev/ttyS0,第二个串口设备文件为/dev/ttyS1。在使用串口之前,需要先打开串口设备文件以获取文件描述符,然后就可以进行串口读写操作。

串口读写操作一般使用系统调用 read() 和 write() 来实现。read() 函数用于从串口中读取数据,函数原型为:

ssize_t read(int fd, void *buf, size_t count);

其中,fd为打开的串口设备的文件描述符,buf为存储读取数据的缓冲区,count为希望读取的字节数。函数返回值为实际读取到的字节数。

write() 函数用于向串口中写入数据,函数原型为:

ssize_t write(int fd, const void *buf, size_t count);

其中,fd为打开的串口设备的文件描述符,buf为待写入数据的缓冲区,count为待写入数据的字节数。函数返回值为实际成功写入的字节数。

二、poll函数介绍

poll() 函数是Linux系统中用于多路复用I/O的函数之一,可以在多个文件描述符上进行监视,当其中的任意一个文件描述符就绪时,函数就可以返回。poll() 函数的功能类似于 select() 函数,但是 select() 函数有一些限制,例如文件描述符的大小限制、效率较低等问题。因此,在Linux系统中,poll() 函数被广泛应用。

poll() 函数的原型如下:

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

其中,fds是指向 struct pollfd 结构体数组的指针,nfds为数组中结构体的数量,timeout为等待时间。poll() 函数的返回值为就绪文件描述符的数量。

struct pollfd 结构体定义如下:

struct pollfd {

int fd; /* 文件描述符 */

short events; /* 监视事件 */

short revents; /* 实际发生的事件 */

};

其中,fd为文件描述符,events为监视事件,可以是以下事件的任意组合:

·POLLIN:有数据可读

·POLLOUT:写数据不会阻塞

·POLLPRI:有紧急数据可读

·POLLRDNORM:有数据可读

·POLLRDBAND:有优先数据可读

·POLLWRNORM:写数据不会阻塞

·POLLWRBAND:写优先数据可读

revents为实际发生的事件,与 events 中的事件相对应。

三、

在Linux系统中,使用 poll() 函数可以实现串口的稳定读写。具体实现方法如下:

1. 打开串口设备文件并设置相关参数,例如波特率、数据位、停止位等。

2. 创建 struct pollfd 结构体数组,并将串口设备文件的文件描述符和监视事件加入数组中。

3. 调用 poll() 函数进行监视,当串口设备有数据可读时,poll() 函数将返回1,此时可以使用 read() 函数从串口中读取数据。

4. 当需要向串口中写入数据时,可以使用 write() 函数进行写入,但需要先判断串口是否可写(即 POLLOUT 事件是否已经就绪),如果没有就绪则需要等待。

具体代码实现如下:

// 打开串口设备文件

int fd = open(“/dev/ttyS0”, O_RDWR | O_NOCTTY | O_NDELAY);

if (fd

perror(“Open ttyS0 error.”);

return -1;

}

// 设置串口参数

struct termios opt;

tcgetattr(fd, &opt);

cfsetispeed(&opt, B9600);

cfsetospeed(&opt, B9600);

opt.c_cflag &= ~PARENB; // 无奇偶校验

opt.c_cflag &= ~CSTOPB; // 1位停止位

opt.c_cflag &= ~CSIZE; // 8位数据位

opt.c_cflag |= CS8; // 8位数据位

opt.c_cc[VTIME] = 0; // 读取超时时间0s

opt.c_cc[VMIN] = 1; // 最少读取1个字符

tcsetattr(fd, TCSANOW, &opt);

// 创建 struct pollfd 结构体

struct pollfd fds[1];

fds[0].fd = fd;

fds[0].events = POLLIN;

// 监视串口设备

while (1) {

int ret = poll(fds, 1, 1000); // 等待1000ms

if (ret

perror(“Poll error.”);

break;

} else if (ret == 0) {

printf(“Poll timeout.\n”);

} else {

if (fds[0].revents & POLLIN) { // 串口可读

char data[1024] = {0};

int len = read(fd, data, 1024);

if (len > 0) {

printf(“Read data: %s\n”, data);

}

}

if (fds[0].revents & POLLOUT) { // 串口可写

char data[1024] = “Hello World!”;

int len = strlen(data);

int n = write(fd, data, len);

if (n != len) {

printf(“Write error.\n”);

}

}

}

}

在上述代码中,打开串口设备文件后,使用 tcgetattr() 和 tcsetattr() 函数设置串口参数,然后创建 struct pollfd 结构体并将监视事件添加到数组中。在 while 循环中,使用 poll() 函数等待串口设备就绪,当有数据可读时使用 read() 函数读取数据,当需要写入数据时则使用 write() 函数,但必须先判断 POLLOUT 事件是否已经就绪。

四、

通过使用 Linux 中的 poll() 函数,可以实现串口的稳定读写。poll() 函数可以同时监视多个文件描述符的就绪状态,并且可以指定等待时间。使用 poll() 函数实现串口读写时,需要先设置串口参数,然后创建 struct pollfd 结构体,并将监视事件加入数组中。在进行串口读写时,必须先判断相应的事件是否已经就绪,以避免出现延迟或数据丢失等问题。

相关问题拓展阅读:

Linux中select poll和epoll的区别

============select、poll、epoll之间的区别=================

select,poll,epoll都是IO多路复用的机制。I/O多路复用就通过一种机制,

可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),

能够通知程序进行相应的读写操作,读写过程是阻塞的,

select的几大缺点:监视的文件描述符的数量存在更大限制

1 单个进程可监视的fd数量被限制

2 需要维护一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大

3 对socket进行扫描时是线性扫描

//select的3个缺点:1 连接数受限 2 查找配对速度慢 3 数据由内核拷贝到用户态。

poll的实现和select非常相似,pollfd并没有更大数量限制(但是数量过大后性能也是会下降)

select、poll的内部实现机制相似,它没有更大连接数的限制,原因是它是基纯闷于链肢念表来存储的,

但是同样有一个缺点:大量的fd的数组被整体复制于用户态和内核地址空间之间,

而不管这样的复制是不是有意义。它将用户传入的数组拷贝到内核空间,

然后查询每个fd对应的设备状态,如果做饥弯设备就绪则在设备等待队列中加入一项并继续遍历,这过程经历了多次无谓的遍历

epoll是对select和poll的改进

epoll:IO的效率不会随着监视fd的数量的增长而下降。epoll不同于select和poll轮询的方式,

而是通过每个fd定义的回调函数来实现的。只有就绪的fd才会执行回调函数。

一般情况下fd数量较少的时候poll略优于epoll,但是当fd增大到某个阈值时,

poll性能急剧下降。而epoll始终保持的稳定的性能。

希望采纳

linux串口poll读写的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于linux串口poll读写,Linux串口poll实现稳定读写,Linux中select poll和epoll的区别的信息别忘了在本站进行查找喔。


数据运维技术 » Linux串口poll实现稳定读写 (linux串口poll读写)