Linux VTIME VMIN的作用以及使用有效的前提

前提条件


 1、fdcom = open(ptty, O_RDWR | O_NOCTTY);

 //other attributions default
 /*Canonical Input*/
 //termios_new.c_lflag |= (ICANON | ECHO | ECHOE);
 2、/*Raw Input*/
 //termios_new.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

下面解释:
options.c_cc[VTIME] = 0; /* 设置超时0 seconds*/  

options.c_cc[VMIN] = 13; /* define the minimum bytes data to be readed*/


这两句话决定了对串口读取的函数read()的一些功能。我将着重介绍一下他们对read()函数的影响。

1、在数组c_cc中有两个下标(VTIME和VMIN)对应的元素不是控制符,并且只是在原始模式下有效。

      只有在原始模式下,他们决定了read()函数在什么时候返回。

2、在标准模式下,除非设置了O_NONBLOCK选项,否则只有当遇到文件结束符或各行的字符都已经编辑完毕后才返回。


 
解释一:
控制符VTIME和VMIN之间有着复杂的关系。

1、VTIME定义要求等待的零到几百毫秒的时间量(通常是一个8位的unsigned char变量,取值不能大于cc_t)。
2、VMIN定义了要求等待的最小字节数(不是要求读的字节数——read()的第三个参数才是指定要求读的最大字节数),这个字节数可能是0。

如果VTIME取0,VMIN定义了要求等待读取的最小字节数。函数read()只有在读取了VMIN个字节的数据或者收到一个信号的时候才返回。
如果VMIN取0,VTIME定义了即使没有数据可以读取,read()函数返回前也要等待几百毫秒的时间量。这时,read()函数不需要像其通常情况那样要遇到一个文件结束标志才返回0。
如果VTIME和VMIN都不取0,VTIME定义的是当接收到第一个字节的数据后开始计算等待的时间量。如果当调用read函数时可以得到数据,计时器马上开始计时。如果当调用read函数时还没有任何数据可读,则等接收到第一个字节的数据后,计时器开始计时。函数read可能会在读取到VMIN个字节的数据后返回,也可能在计时完毕后返回,这主要取决于哪个条件首先实现。不过函数至少会读取到一个字节的数据,因为计时器是在读取到第一个数据时开始计时的。
如果VTIME和VMIN都取0,即使读取不到任何数据,函数read也会立即返回。同时,返回值0表示read函数不需要等待文件结束标志就返回了。


解释二:

    VTIME指定了等待的时间,VMIN指定了读取字符的最小数量。


    它们不同组合地取值会得到不同的结果,分别如下:


    1.当VTIME>0,VMIN>0时。read调用将保持阻塞直到读取到第一个字符,读到了第一个字符之后开始计时,此后若时间到了VTIME或者时间未到但已读够了VMIN个字符则会返回;若在时间未到之前又读到了一个字符(但此时读到的总数仍不够VMIN)则计时重新开始。

    2. 当VTIME>0,VMIN=0时。read调用读到数据则立即返回,否则将为每个字符最多等待VTIME时间。

    3. 当VTIME=0,VMIN>0时。read调用一直阻塞,直到读到VMIN个字符后立即返回。

    4. 若在open或fcntl设置了O_NDELALY或O_NONBLOCK标志,read调用不会阻塞而是立即返回,那么VTIME和VMIN就没有意义,效果等同于与把VTIME和VMIN都设为了0。


解释三:

VTIME定义要求等待的时间量(取值不能大于cc_t)。


VMIN定义了要求等待的最小字节数。


options.c_cc[VTIME] = X;   //设置从获取到1个字节后开始计时的超时时间


options.c_cc[VMIN] = Y;     //设置要求等待的最小字节数


在原始模式下对read()函数的影响:


1、X=0,Y!=0。函数read()只有在读取了Y个字节的数据或者收到一个信号的时候才返回;


2、X!=0,Y=0。即使没有数据可以读取,read()函数等待X时间量后返回;


3、X!=0,Y!=0。第一个字节数据到时开始,最先满足收到Y个字节或达超时时间X任意一个条件,read()返回;


4、X=0,Y=0。即使读取不到任何数据,函数read也会立即返回。


示例:


通过串口连ID卡读卡器,要求读串口至少收6个字节数据立即返回,可以将串口的上述两个设置项设置如下:


options.c_cc[VTIME]=0;


options.c_cc[VMIN]=6;


下面再举例子说明:


VTIME 和  VMIN


VTIME  定义要求等待的零到几百毫秒的值(通常是一个8位的unsigned char变量)。
VMIN 定义了要求等待的最小字节数, 这个字节数可能是0。
只有设置为阻塞时这两个参数才有效,仅针对于读操作。
说起来比较复杂,举个例子吧,设置为阻塞状态,写操作未进行实验,这里仅讨论读操作,
read(fd,&buf,8); // 读串口


1、


options.c_cc[VTIME] = 0;
options.c_cc[VMIN] = 0;
VMIN = 0,当缓冲区字节数 >= 0 时进行读操作,实际上这时读串口操作并未被阻塞,因为条件始终被满足。


2、
options.c_cc[VTIME] = 0;
options.c_cc[VMIN] = 1;
VMIN = 1,当缓冲区字节数 >= 1 时进行读操作,当没有数据时读串口操作被阻塞。


3、


options.c_cc[VTIME] = 0;
options.c_cc[VMIN] = 4;
VMIN = 4,当缓冲区字节数 >= 4 时进行读操作,否则读串口操作被阻塞。每次读出的最大字节数由read函数中第三个参数决定。直到缓冲区剩下的数据< read 第三个参数 并且< 4 (如果这时read第三参数为 1 则进行4次读操作直至读完缓冲区,如read第三参数为2,连续进行读操作,直至缓冲区空或还剩一个字符)。没有设置VTIME,剩下的字符没有确定的期限,直到下次满足读条件的时候才被读出。


----------------------------------考虑VTIME-----------------------------


4
options.c_cc[VTIME] = 10; //单位百毫秒
options.c_cc[VMIN] = 4;
同3的区别就是,没满足条件或读缓冲区中剩下的数据会在1秒(10百毫秒)后读出。另外特别注意的是当设置VTIME后,如果read第三个参数小于VMIN ,将会将VMIN 修改为read的第三个参数,即,使用read(fd,&buf,2);,以上设置变为:
options.c_cc[VTIME] = 10;
options.c_cc[VMIN] = 2;
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux是一款兼容UNIX的操作系统,它提供了广泛的开发和应用环境。在许多嵌入式应用、通信设备和实时控制应用中,串口通讯被广泛应用。本文将介绍如何使用C语言在Linux中操作串口进行传输数据的相关知识。 串口是计算机中重要的外设之一,它是一种通过RS-232标准接口进行数据传输的设备。在Linux中,可以使用tty设备来表示串口。串口的读写操作,可以通过使用Linux系统提供的设备驱动程序进行实现。 对于通过串口进行通讯的应用场景来说,需要使用C语言来控制串口的打开、关闭、读写等操作。下面就来介绍一下如何使用C语言进行串口编程。 首先,要使用fopen()函数打开串口设备文件,代码如下: ``` #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <termios.h> #include <unistd.h> int main() { int fd; fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY); if(fd == -1) { printf("Error: cannot open serial port.\n"); exit(0); } /* Other operations */ close(fd); return 0; } ``` 在这个例子中,"/dev/ttyUSB0"代表的是一个USB口设备。O_RDONLY或O_WRONLY为文件打开时的读写权限,O_NOCTTY表示不把串口作为控制终端,O_NDELAY表示无阻塞方式。 接下来需要对串口进行配置。配置的内容有:波特率、数据位、停止位等。这些配置通过termios结构体进行配置。代码如下: ``` struct termios opt; tcgetattr(fd, &opt); cfsetispeed(&opt, B9600); cfsetospeed(&opt, B9600); opt.c_cflag &= ~CSIZE; opt.c_cflag |= CS8; opt.c_cflag &= ~CSTOPB; opt.c_cflag &= ~(PARENB | PARODD); opt.c_cflag |= IGNPAR; opt.c_cflag &= ~(ICANON | ECHO | ECHOE | ISIG); opt.c_oflag &= ~OPOST; opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); opt.c_cc[VMIN] = 1; opt.c_cc[VTIME] = 0; tcsetattr(fd, TCSANOW, &opt); } ``` 其中,cfsetispeed()和cfsetospeed()用于设置输入输出波特率,CSIZE也就是数据位有五个选项,分别是CS5、CS6、CS7、CS8、CS16,这里选择了CS8。CSTOPB代表停止位有一个或两个,这里选择了一个。PARENB和PARODD代表是否开启奇偶校验位,这里选择了不开。IGNPAR为忽略校验错。ICANON、ECHO、ECHOE、ISIG等代表输入方式、输出方式和控制模式。VTIME和VMIN代表在无数据到来的情况下读取的最大等待时间和最小字符数。 若要在串口中传送数据,需要使用write()函数进行写入操作。代码如下: ``` write(fd, buf, len); ``` 其中,fd为串口设备文件描述符,buf为写入缓存区的数据,len为数据长度。如果要读取数据,则需要使用read()函数。代码如下: ``` read(fd, buf, len); ``` 当从串口读取数据时,这个函数会一直阻塞,直到读到足够的数据或者时间超时。同样地,fd为串口设备文件描述符,buf为存放读取数据的缓冲区,len为读取数据的字节数。 最后,要关闭串口设备文件,使用close()函数就可以了。代码如下: ``` close(fd); ``` 在本文中,我们介绍了如何使用C语言在Linux中操作串口进行数据传输。针对不同的串口设备,我们需要根据不同的设备文件进行调整。串口编程本质上是使用Linux系统提供的设备文件读写操作函数进行控制。如果您需要深入学习Linux中串口编程的相关技术,请关注Linux内核驱动开发等相关方面的知识。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值