3

这里我复制了串口配置的例子:

tcgetattr (serialfd, &tty);

cfsetospeed(&tty,B115200);
cfsetispeed(&tty,B115200);

tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
tty.c_iflag &= ~IGNBRK;
tty.c_lflag = 0;

tty.c_oflag = 0;
tty.c_cc[VMIN]  = 0;
tty.c_cc[VTIME] = 5;

tty.c_iflag &= ~(IXON | IXOFF | IXANY);
tty.c_cflag |= (CLOCAL | CREAD);
tty.c_cflag &= ~(PARENB | PARODD);
tty.c_cflag |= 0;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;

我的实际代码是这样的:

char buf[100];
write(serialfd, "PING", strlen("PING"));
fsync(serialfd);

while (1) 
{
    read(serialfd, buf, sizeof(buf));
    printf("length: %d\n", strlen(buf));
}

在这种情况下,它会length: 6无限打印而不会停止。当我更改tty.c_cc[VMIN] = 1并且tty.c_cc[VTIME] = 0它不读取时。(它阻塞read()

我正在使用带有 USB 到串行转换器的 debian 6.0.5。我这样打开串口:

serialfd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_SYNC);
4

1 回答 1

2

看你的代码

while (1) 
{
    read(serialfd, buf, sizeof(buf));
    printf("length: %d\n", strlen(buf));
}

您已经在此循环之前编写了一个数据包,然后在第一次迭代中您读取了读入缓冲区的可用数据。您需要memset每次将缓冲区归零,或者使用调用返回值中给出的读取字节数将缓冲区归零read。然后您无限循环,每次再次读取 - 但后续读取不会复制任何更多数据,因为没有要读取的数据。但是,由于调用 read 因此,您的缓冲区保持不变,并且您的打印输出每次迭代都保持不变,因为缓冲区每次迭代都保持不变。

至于阻塞方面,你应该阅读以下指南(之前在SO上推荐过,作为串口编程的入门非常好)

http://www.easysw.com/~mike/serial/serial.html

本节描述将 VMIN 和 VTIME 设置为各种值时的行为。特别是最后一段解释了您看到的阻塞行为。

VMIN 指定要读取的最小字符数。如果设置为 0,则 VTIME 值指定等待读取每个字符的时间。请注意,这并不意味着对 N 个字节的读取调用将等待 N 个字符进入。相反,超时将应用于第一个字符,并且读取调用将返回立即可用的字符数(最多为您要求)。

如果 VMIN 非零,则 VTIME 指定等待读取第一个字符的时间。如果在给定时间内读取了一个字符,则任何读取都将阻塞(等待),直到读取所有 VMIN 字符。也就是说,一旦读取了第一个字符,串行接口驱动程序就期望接收整个字符包(总共 VMIN 字节)。如果在允许的时间内没有读取任何字符,则 read 调用返回 0。此方法允许您告诉串行驱动程序您需要 N 个字节,并且任何 read 调用将返回 0 或 N 个字节。但是,超时仅适用于读取的第一个字符,因此如果由于某种原因驱动程序错过了 N 字节数据包中的一个字符,则读取调用可能会永远阻塞等待其他输入字符。

VTIME 指定等待传入字符的时间量,以十分之一秒为单位。如果 VTIME 设置为 0(默认值),读取将无限期地阻塞(等待),除非在带有 open 或 fcntl 的端口上设置了 NDELAY 选项。

于 2012-07-16T21:51:17.990 回答