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控制台,可以免去额外的键盘,显示卡和显示器,同时可将Linux主机作为一个任意用途的嵌入式黑匣。那么LINUX控制台怎么定向到串口终端?下面跟着学习啦小编一起来了解一下吧。

  LINUX控制台怎么定向到串口终端

  目的: 台机已经装好Linux,显示器有问题,平时一般都SSH控制,当Linux网络挂的时候,想通过串口来管理。

  硬件:台机自带两个串口(上面的是COM1) or ttyS0

  目标机器:安装的CentOS 5.2 Linux 内核2.6.18-92.1.22.el5和2.6.18-92.1.22.el5xen

  客户端: Windows XP SP3 IBM OEM. 安装USB转串口驱动。

  需要把输出定向到串口,一般有下面几处:

  BIOS中的设置

  GRUB设置

  /etc/inittab 设置

  /etc/securetty 设置

  BIOS中的设置

  BIOS设置的作用我没尝试过,如果是可以连BIOS设置都可以定向到串口,那个强大了。也不知道如何去掉机器需要连键盘的限制。没拿出显示器所以没看我台机的BIOS,不过这个功能一般只有服务器级数带猜别的机器有。【注1】台机一般没有串口重定向功能。

  GRUB设置

  这里的配置是为了把grub菜单定薯型向到串口,这样你就可以在串口操作grub,选择启动项,使用single mode等等。

  同时也要给kernel参数加上console选项。

  # cat /boot/grub/menu.lst

  # grub.conf generated by anaconda

  #

  # Note that you do not have to rerun grub after making changes to this file

  # NOTICE: You have a /boot partition. This means that

  # all kernel and initrd paths are relative to /boot/, eg.

  # root (hd0,0)

  # kernel /vmlinuz-version ro root=/dev/vg00/lv_root

  # initrd /initrd-version.img

  #boot=/dev/hdb1

  serial –unit=0 –speed=word=8 –parity=no –stop=1

  terminal –timeout=10 serial console

  default=2

  timeout=20

  行皮#splashimage=(hd0,0)/grub/splash.xpm.gz =>这些在console下会工作不正常,注释掉。

  #hiddenmenu

  title CentOS (2.6.18-92.1.22.el5)

  root (hd0,0)

  kernel /vmlinuz-2.6.18-92.1.22.el5 ro root=/dev/vg00/lv_root rhgb quiet

  initrd /initrd-2.6.18-92.1.22.el5.img

  title CentOS Serial – Console (2.6.18-92.1.22.el5)

  root (hd0,0)

  kernel /vmlinuz-2.6.18-92.1.22.el5 ro root=/dev/vg00/lv_root console=ttyS0,9600 console=tty0

  initrd /initrd-2.6.18-92.1.22.el5.img

  title CentOS Console – serial (2.6.18-92.1.22.el5)

  root (hd0,0)

  kernel /vmlinuz-2.6.18-92.1.22.el5 ro root=/dev/vg00/lv_root console=tty0 console=ttyS0,9600

  initrd /initrd-2.6.18-92.1.22.el5.img

  title CentOS Xen (2.6.18-92.1.22.el5xen)

  root (hd0,0)

  kernel /xen.gz-2.6.18-92.1.22.el5

  module /vmlinuz-2.6.18-92.1.22.el5xen ro root=/dev/vg00/lv_root rhgb quiet xencons=off

  module /initrd-2.6.18-92.1.22.el5xen.img

  title CentOS Xen Serial – Console (2.6.18-92.1.22.el5xen)

  root (hd0,0)

  kernel /xen.gz-2.6.18-92.1.22.el5

  module /vmlinuz-2.6.18-92.1.22.el5xen ro root=/dev/vg00/lv_root xencons=off console=ttyS0,9600 console=tty0

  module /initrd-2.6.18-92.1.22.el5xen.img

  title CentOS Xen Console – serial (2.6.18-92.1.22.el5xen)

  root (hd0,0)

  kernel /xen.gz-2.6.18-92.1.22.el5

  module /vmlinuz-2.6.18-92.1.22.el5xen ro root=/dev/vg00/lv_root xencons=off console=tty0 console=ttyS0,9600

  module /initrd-2.6.18-92.1.22.el5xen.img

  title Other

  rootnoverify (hd0,0)

  chainloader +1

  后面的console有顺序关系,详见下文【注2】,我常用串口所以console=tty0 console=ttyS0,9600这个顺序的输出信息比较多。

  因为我的机器有xen的内核,xen默认情况下会把串口做为xencons,所以这里设置xencons=off.

  When multiple consoles are listed output is sent to all consoles and input is taken from the last listed console. The last console is the one Linux uses as the /dev/consoledevice.

  /etc/inittab 设置

  系统系统后,需要在串口上监听请求,所以要有个类似服务器的程序(agetty, mgetty etc)。

  /etc/inittab中添加

  s0:2345:respawn:/in/agetty -L -f /etc/issue.serial 9600 ttyS0 vt100

  #s1:2345:respawn:/in/agetty -L -f /etc/issue.serial 9600 ttyS1 vt100

  #S0:2345:respawn:/in/mgetty -r -x 9 ttyS0 ==> mgetty 用来调试比较好,log也丰富。

  What is a getty?

  A getty is is a program that opens a tty port, prompts for a login name, and runs the /bin/login command. It is normally invoked by init.

  所以其他程序就不能再来占用ttyS0了,串口是独占模式的吧。

  vt100:

  vt100 is the terminal emulation. You can use others, but VT100 is the most common or “standard”. Another widely used termial type is VT102.

  OK都可以了,可以重启server了。这里如果想测试下串口线,推荐先在Linux启动下mgetty,因为他的debug信息和log比较丰富,适合排错和测试。

  #mgetty –r –x 9 ttyS0

  Log在/var/log/mgetty*中。

  /etc/securetty设置

  因为一般我们都是使用root登陆串口来维护,所以需要设置root可以在COM1和COM2登陆。

  在/etc/securetty中添加:

  ttyS0

  ttyS1

  Windows客户端连接可以用超级终端或者Putty。

  注意启动server的时候,putty就应该去连接串口了,这样才可以看到所有信息。

  本来正常情况下,接下去kernel的boot信息应该也会打到串口的。但是没有,确定是Xen内核的关系。

  系统启动起来后,过了init,agetty就起来了,这个时候就可以通过串口登陆了。(在/etc/securetty中需要添加ttyS0)

linux串口读取问题

首先你确定你那串口是否有东西可读? 就是你上面说的“一个文件不停的写数据到串口”!你可以先不这样读取,你可以在终端巧陵上用cat试试是否有数据可读:cat /dev/ttyS0

如果有的话,那你就检查串口设置是否正确,如波特率,数据位,停止位,校验位等!

最后就是你读取的函数了,看看先不要用printf打印字符串了,孝前戚先看看十六进制是否有,然后再看字符等!

就是以上一些,你还可以参考Linux下串口文档,百度上很多的……悔御

取设备描述符)的时候州猛瞎设置的是非阻塞方式。导致串口上没数据的时候read也立即返回,但是你的while已经把有效的数据读走了,if里面读到的一定是空的,所以什么也不打印。

建议

1. 在打开串口设备时使用阻知辩塞方式,不会册空设置的话查查open系统调用的帮助,它有个flag;

2. 把while循环内的if语句去掉。

另外,团IDC网上有许多产品团购,便宜有口碑

你串口有数据给读吗?

串口接了什么设备?

linux 串口独占打开的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于linux 串口独占打开,Linux串口独占打开技巧:顺利实现设备连接,LINUX控制台怎么定向到串口终端,linux串口读取问题的信息别忘了在本站进行查找喔。


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