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;
}
“`
四、