linux学习笔记-读《Linux编程技术详解》(6-1)-设备文件

设备文件简述:

Linux系统中,存在一个抽象化的设备目录,名为/dev,该目录下存有指向系统中硬件的特殊文件。这些指向硬件设备的文件,极大的简化了程序员对硬件的操作。程序员可以像访问普通文件一样来访问硬件,而无需使用特殊的接口函数。

Linux系统将设备分成了3中类型:字符设备、块设备和网络接口。

l  字符设备:字符设备就是能够像字节流一样访问的设备,字符终端和串口就属于字符设备;

l  块设备:块设备上可以容纳文件系统。与字符设备不同,在读写操作时,块设备每次只能传输一个或多个完整的块。在Linux操作系统中,应用程序可以像访问字符设备一样读写块设备(一次读取或写入任意的字节数据)。因此,块设备和字符设备的区别仅仅是在内核中对于数据的管理不同。

l  网络接口:网络接口存在一定的特殊性,其与内核的通信完全不同于内核与字符设备或块设备的通信。网络接口可以是一个硬件设备,也可以是一个软件设备。

内核通过主从设备号将设备文件与真实设备关联起来。第一个数字称为主设备号,指向硬件设备,而次设备号指向子设备。

有同一个设备驱动控制的所有设备具有相同的主设备号。从设备号则被用来区分具有相同主设备号且由相同的设备驱动程序控制的不同设备。

Linux设备驱动工作流程:

Linux系统启动时,设备驱动将被加载。设备驱动成功加载后,将向系统反馈一个主设备号,驱动程序将根据主设备号在/dev目录下创建对应的设备文件。然后,程序就可以调用openreadwrite函数或命令实现对对设备的访问。

linux学习笔记-读《Linux编程技术详解》(6-1)-设备文件_第1张图片

 

终端控制:

传统终端指的是计算机外部的设备,而现在终端为显示器、控制器及键盘等设备的总称。终端与平常使用的计算机的根本区别在于:没有自己的CPU单元和内存单元。目前终端的含义:一切接入网络的计算机设备成为终端,如电脑、PDA、智能电话、数字电视等。

Linux系统中,所有终端设备都被称为ttytty被认为是TeletypesTele-typewriters的缩写。终端是一种字符型的设备,有多种类型。查看/dev/目录下的以tty开头的设备名称,可以了解Linux系统中所有的终端设备。

Linux系统中的终端设备文件主要有下面几种类型:

l  串行端口终端(/dev/ttySn):串行端口终端是使用计算机的串行端口连接的终端设备,在Linux系统中,系统将每个串行接口看做是一个字符设备。串行端口对应的设备名称是/dev/ttyS0/dev/ttyS1/dev/ttyS2/dev/ttyS3,分别对应于硬件的COM1COM2COM3COM4

l  伪终端(/dev/pts/n):使用Telnet登录到Linux系统实际上是登录到了一个伪终端上。使用who命令可以看到谁登录到了伪终端上。

l  控制终端(/dev/tty):如果当前进程存在控制终端,/dev/ttyN就是当前进程的控制终端的设备文件。使用”ps ax”可以查看进程与控制终端的关系。

l  控制台终端(/dev/ttyn/dev/console):在Linux系统中,常将显示器称为控制台终端。当从控制台登录到系统时,使用的是tty1Linux系统将tty1~tty6称为虚拟终端。

 

通过stty命令可以直接修改和查询终端驱动程序的设置。

有时候运行一些程序,需要修改终端的设置。对于用户而言,这些修改往往是不可见的,因为程序在退出后,会将终端设置为原有情况。但是,如果出现程序崩溃或被kill命令杀死的情况,有可能来不及将终端设置为原有的参数。这时,终端就有可能出现异常的情况,有可能不能正常处理换行字符,或不能恰当的显示输入的字符,甚至可能不能正确执行命令。在这种情况下,可以使用reset命令将终端恢复到正确的状态。

Linux提供了ttyname函数,用于判断某个打开的文件描述符是否是某个终端设备,如果是,则返回终端设备名称。

           char *ttyname(int fd);

 

tcgetattry用于获取终端的相关参数,而tcsetattr函数用于设置终端参数。

           int tcgetattr(int fd, struct termios *termios_p);

           int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);

 

curses库用于处理Linux/UNIX上的光标移动及屏幕显示问题。使用curses库中的函数前,需要进行必要的初始化工作。程序需要使用initscr函数来开启curses模式,在结束前调用endwin函数来关闭curses模式。

 

串口通信:

Linux系统通过串口终端设备文件来实现对串口设备的访问。串口是计算机上常见的接口,往往用于调试设备和连接一些对传输速度要求不高的设备。

串口的数据传输是以串行方式进行的。串口在数据通信中,一次只传输一个比特的数据。串行数据的传输速度用bps或波特率来描述。串行通信设备也被称为数据通信设备(DCE, Data Communication Equipment)或数据终端设备(DTE, Data Terminal Equipment)

常用的串口是RS-232C接口(又称EIA RS-232C),是一个25脚的DB25连接器。RS-232C定义的传输长度为8m

串口一般用于ASCII码字符的传输。最基本的串口通信只需3个引脚即可实现,分别是地线、接收和发送,其他引脚用于握手协议。由于串口通信属于异步通信,可以在进行通信时不使用握手协议。

为了正确实现串口间的通信,必须对串口的参数进行设置。

l  每秒位数:即波特率。该参数表示每秒传输的比特数。例如,对于发送端,2400波特率表示每秒发送2400bit;对于接收端而言,2400波特率意味着串口通信在数据线上的采样率为2400Hz。由于波特率和距离之间成反比,距离相隔很近的设备间才可以实现高波特率通信。

l  数据位:表示通信中实际数据位的参数。在计算机发送的数据包中,实际的数据往往不会是8位。在串口通信中,可以选择5678位,设定数据位主要考虑所要传输的数据内容。如果要传输的是标准ASCII码,由于ASCII码的范围是0~127,因此使用7为就可以了。如果要传输的是扩展ASCII码,其范围是0~255,必须使用8位。当然,7位或8位数据位中不仅仅是数据,还包括开始/停止位、数据位以及奇偶校验位等。

l  奇偶校验位:该位用于串口通信中的简单检错。器偶校验位主要有:偶校验、奇校验、标记、空格的方式,也可以不使用校验。奇/偶校验是通过统计数据中高位或低位的个数来是实现校验的。而标记、空格并不真正检测数据,只是通过简单的置位来实现对数据的检测。通过置位方式,可以判断出是否存在噪声干扰数据通信或数据传输,以及接收是否存在不同步的现象。

l  停止位:停止位用于标志该数据包数据结束,可以取1位、1.5位或2位。停止位不仅仅用于数据包的传输结束标志,还提供了计算机之间校正同步时钟的机会。用于停止位的位数越多,不同时钟同步的容忍程度越大。但由于停止位占用数据空间,过多的停止位将导致数据传输速度的下降。

l  数据流控制:通过串口传输数据时,由于计算机之间处理速度或其他因素的影响,会造成数据丢失的现象。例如,台式机与单片机之间的通信,接收端数据缓冲区已满的情况下,继续收到数据,新发送来的数据就会由于无法处理造成丢失。数据流控制用于解决这个问题。通过控制发送数据的速度,确保数据不会出现丢失。数据流控制可以分为软件流控制(Xon/Xoff)和硬件流控制,也可以选择不适用数据流控制。软件流控制使用特殊的字符作为启动或停止的标志,而硬件流控制通过使用硬件信号(CTR/RTS)来实现。使用硬件流控制时,在接收端准备好接收数据后,设定CTS1,否则CTS0。同样,如果发送端准备好要发送数据,则设定RTS1;如果还未准备好,设置CTS0

 

Linux系统中,串口设备是通过串口终端设备文件来访问的,也就是通过访问/dev/ttyS0/dev/ttyS1/dev/ttyS02/dev/ttyS3这些设备文件实现对串口的访问。对串口进行读写要经过下面几个步骤:

1.         打开串口

与打开文件类似,打开串口同样使用open函数。注意对于串口的打开操作,必须使用O_NOCTTY参数。该参数表示:如果打开的是一个终端设备,程序不会成为对应这个端口的控制终端。如果没有使用该标志,任何一个输入(例如,键盘中止信号等)都将影响进程。

           if((fd=open(“/dev/ttyS0”, O_RDWR | O_NOCTTY)) == -1)

{ … … ;}

2.         设置串口通信参数

串口通信参数指的是波特率、数据位、奇偶校验位和停止位。对串口实现控制的时候同样要用到termio结构体。

波特率设置

获得端口波特率信息是通过cfgetispeed函数和cfgetospeed函数来实现的。cfgetispeed函数用于获得结构体termios_p中的输入波特率信息,而cfgetospeed函数用于获得结构体termios_p中的输出波特率信息。

           speed_t cfgetispeed(const struct termios *termios_p);

           speed_t cfgetospeed(const struct termios *termios_p);

cfsetispeed函数和cfsetospeed函数用于设置端口的输入/输出波特率。一般情况下,输入和输出波特率是相等的。

           int cfsetispeed(struct termios *termios_p, speed_t speed);

           int cfsetospeed(struct termios *termios_p, speed_t speed);

cfsetispeed函数和cfsetospeed函数会修改结构体termios_p中的波特率信息。

           tcgetattr(fd, &opt);

           cfsetispeed(&opt, B9600);

           cfsetospeed(&opt, B9600);

           tcsetattr(fd, TCANOW, &opt);

           … …

数据位

数据位指的是每字节中实际数据所占的比特数。要修改数据位可以通过修改termios结构体中的c_cflag成员来实现。CS5CS6CS7CS8分别表示数据位为5678。在设置数据位时,必须先使用CSIZE做位屏蔽。具体设置如下:

           tcgetattr(fd, &opt);

          

           opt.c_cflag &= ~CSIZE;

           opt.c_cflag |= CS8;

          

           tcsetattr(fd, TCANOW, &opt);

奇偶校验位

           奇偶校验可以选择偶校验、奇校验、空格等方式,也可以不使用校验。如果要设置为偶校验的话,首先要将termios结构体中c_cflag设置PARENB标志,并清除PARODD标志。如果要设置奇校验,要同时设置termios结构体中c_cflag设置PARENB标志和PARODD标志。如果不想使用任何校验的话,清除termios结构体中c_cflagPARENB位。

 

设置奇偶校验位

设置

具体代码

无校验

opt.c_cflag &= ~PARENB;

奇校验

opt.c_cflag |= (PARODD | PARENB);

偶校验

opt.c_cflag &= ~PARENB;

opt.c_cflag &= ~PARODD;

空格

opt.c_cflag &= ~PARENB;

opt.c_cflag &= ~CSTOPB;

         数据流控制

           数据流控制指使用何种方法来标志数据传输的开始和结束。可以选择不使用数据流控制、使用硬件进流控制和使用软件进行流控制。

数据流控制设置

设置

具体代码

不使用数据流控制

opt.c_cflag &= ~CRTSCTS

硬件

opt.c_cflag |= CRTSCTS

软件

opt.c_cflag |= IXON|OXOFF|IXANY

           由于使用硬件流控制需要相应连接的电缆,常用的流控制方法还是使用软件进行流控制。

3.         读写串口

读写串口是通过调用readwrite实现。

4.         关闭串口

完成对设备文件读写操作后,调用close关闭该文件描述符。

你可能感兴趣的:(编程,linux,网络,struct,终端,Terminal)