Linux串口独占打开技巧:顺利实现设备连接 (linux 串口独占打开)

序言

作为一台计算机的基本输入/输出设备之一,串口在很多场合得到重视。但是Linux系统下,对于串口的使用并不像我们平时想象中的那样简单。在Linux系统下,上电之后,针对每一个串口都会开启一个设备文件。通过串口访问器可以实现终端的连接,实现与设备的通讯。然而,由于Linux系统系统的多用户,多任务并发特性,串口的并发访问很容易造成竞争,进而导致系统异常,阻碍设备的访问。本文旨在分享一些Linux串口独占打开技巧,帮助用户实现串口的顺利连接。

一、串口设备特别之处

与其他的设备不同,串口有特别的地方。串口的写操作可以直接进入硬件缓冲区,而实际的写操作是异步完成的;串口的读操作也是异步的,当缓冲区有数据时,Linux内核会通知应用程序调用指定的的读缓冲函数。因此,每个串口都有独立的读写缓冲区,读/写操作互不干扰,此处不作深入讨论。

二、串口独占打开技巧

(1)文件IO模型

在使用Linux系统串口接口时,首先要了解Linux的文件IO模型,并据此进行串口数据通讯的设计。

在Linux系统中,IO与具体的设备无关,对于系统任何一个文件都是可以操作的。对于Linux内核来说,每一个打开的文件都会对应一个结构体,其中包含了打开这个文件的进程信息、IO缓冲信息、FIFO缓冲、文件位置指针等信息。LINUX文件IO模型大概如下图所示:

![linux io](https://img-blog.csdn.net/20231019154818793)

(2)串口用户空间API

Linux下的串口读写相关的API接口有如下几组:

– 打开串口:open

– 配置串口参数:ioctl

– 读:read

– 写:write

– 关闭串口:close

其中需要注意的是,串口在读写数据时,需要设置一个合适的读写超时,否则会出现卡住现象。

(3)串口独占打开

在Linux系统下,串口的打开方式是独占方式。即每个串口只支持被一个程序打开,当一个进程打开一个串口时,其他进程无法打开此串口,直到打开这个串口的进程关闭此串口之后,其他进程才有机会打开此串口。因此,我们在设计应用程序时,要特别注意对串口进行独占文件IO访问,防止出现结果混乱的现象。

接下来,我们以一个串口实际的使用场景作为例子,介绍串口独占打开技巧。假设在底层,有一个嵌入式设备需要通过串口与PC机进行通讯。因此,我们需要设计一个上位机程序,与此嵌入式设备进行通讯。同时,我们也要进行编程,将相应的系统接口封装起来,供其他应用程序调用。在具体的代码实现中,需遵循如下的原则:

– 独占串口,防止串口访问冲突

– 进行数据的接收和处理

– 设置读写超时,避免出现卡死现象

三、串口数据的收发操作

在设计串口数据的发送操作时,需要先打开串口设备,然后通过write函数将要发送的数据写入串口缓冲区,核对数据无误后,可以将设备关闭。在实现的时候,根据需要,还可以添加等待数据传输完成的超时计时器。串口发送操作的示例代码如下:

“`

#include

#include

#include

#include

int mn(void)

{

int fd;

if((fd = open (“dev/ttyS0”, O_RDWR | O_NONBLOCK))

{

perror(“open fled”);

return -1;

}

struct termios opt;

tcgetattr (fd, &opt);

cfsetispeed (&opt, B115200);

cfsetospeed (&opt, B115200);

opt.c_cflag |= CLOCAL;

opt.c_cflag |= CREAD;

opt.c_cflag &= ~CSIZE;

opt.c_cflag |= CS8;

opt.c_cflag &= ~PARENB;

opt.c_cflag &= ~CSTOPB;

tcsetattr (fd, TCSANOW, &opt);

sleep(5);

char buf[] = {0x31,0x32,0x33,0x34,0x35};

int len = write(fd,buf,sizeof(buf));

tcflush (fd, TCIOFLUSH);

close (fd);

return 0;

}

“`

在设计串口数据的接收操作时,也需先打开串口,然后再读取串口缓冲区中的数据。如果读取的数据比较少,可以将read函数设置为非阻塞方式;如果读取的数据较多,可以将read函数设置为阻塞方式,直到缓冲区中有足够的数据可以读取。数据的接收操作示例代码如下:

“`

#include

#include

#include

#include

int mn(void)

{

int fd;

if((fd = open(“dev/ttyS0”, O_RDWR | O_NONBLOCK))

{

perror(“open fled”);

return -1;

}

struct termios opt;

tcgetattr (fd, &opt);

cfsetispeed (&opt, B115200);

cfsetospeed (&opt, B115200);

opt.c_cflag |= CLOCAL;

opt.c_cflag |= CREAD;

opt.c_cflag &= ~CSIZE;

opt.c_cflag |= CS8;

opt.c_cflag &= ~PARENB;

opt.c_cflag &= ~CSTOPB;

tcsetattr (fd, TCSANOW, &opt);

sleep(5);

char buf[1024] ={0};

int len = 0, total = 0;

while(1)

{

len = read(fd,buf,total + 1024);

if(len > 0)

{

total += len;

printf(“read total %d data is %s”, total, buf);

fflush(stdout);

}

else

printf(“no data to read\n”);

usleep(100);

}

tcflush (fd, TCIOFLUSH);

close (fd);

return 0;

}

“`

四、


数据运维技术 » Linux串口独占打开技巧:顺利实现设备连接 (linux 串口独占打开)