从C LINUX的串行端口读取不一致

时间:2019-01-29 18:29:48

标签: c linux serial-port termios

使用Linux和C读取串行端口时出现不一致问题。

我用来配置串行端口的代码是这样的:

serial = open("/dev/ttymxc1", O_RDWR | O_NOCTTY | O_SYNC);      //Open in non blocking read/write mode
    if (serial == -1)
    {
        //ERROR - CAN'T OPEN SERIAL PORT
        printf("Error - Unable to open UART.  Ensure it is not in use by another application\n");
    }

    struct termios tty;
    memset (&tty, 0, sizeof tty);
    if (tcgetattr (serial, &tty) != 0)
    {
        printf("error from tcgetattr");
        return -1;
    }

    cfsetospeed (&tty, B115200);

    tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;     // 8-bit chars
    // disable IGNBRK for mismatched speed tests; otherwise receive break
    // as \000 chars
    //tty.c_iflag &= ~IGNBRK;         // disable break processing
    tty.c_lflag = 0;                // no signaling chars, no echo,
                                            // no canonical processing
    tty.c_oflag = 0;                // no remapping, no delays
    tty.c_cc[VMIN]  = 0;            // read doesn't block
    tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

    tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl

    tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
                                            // enable reading
    tty.c_cflag &= ~(PARENB | PARODD);      // shut off parity
    tty.c_cflag |= 0;
    tty.c_cflag &= ~CSTOPB;
    tty.c_cflag &= ~CRTSCTS;

    if (tcsetattr (serial, TCSANOW, &tty) != 0)
    {
        printf("error from tcsetattr");
        return -1;
    }

然后我使用以下代码(从配置串行端口的同一线程)轮询UART:

while(1)
{
    if (serial != -1)
    {
        //memset(rx, 0, sizeof(rx));
        int rx_length = read(serial, &rx, MAX_TXRX_BUF);        //Filestream, buffer to store in, number of bytes to read (max)
        if(rx_length > 0){
            //Bytes received
            //rx[rx_length] = '\0';

            printf("1) %i bytes read : %s\n", rx_length, rx);
            //forward_data(rx, rx_length);
            printf("2) %i bytes read : %s\n", rx_length, rx);
            //tcflush(serial, TCIOFLUSH);
        }
        // else: NO DATA
    }
    else{
        fprintf(stderr, "TEST: %s SERIAL FAIL\n", __func__);
        releaseUart();
    }

}

问题在于此打印:

printf("1) %i bytes read : %s\n", rx_length, rx);

始终工作并打印从串行读取的正确数据。 在第二次打印时:

printf("2) %i bytes read : %s\n", rx_length, rx);

位于第一个字符的正下方,有时可以工作,而其他项目只是打印一个未知字符。

下面,我向您展示输出,但在这种情况下有效,在无效的情况下:

正确:

1) 2 bytes read : gv
2) 2 bytes read gv

错误:

1) 2 bytes read : gv
2) 2 bytes read: �

为什么即使两张照片都比另一张照片低,有时在打印SAME缓冲区时也会出现这种不一致的情况?

非常感谢您的帮助。

最好的问候, 马可

1 个答案:

答案 0 :(得分:1)

我无法解释为什么输出在第一个printf和第二个之间变化。但是,read不会NUL终止其缓冲区,这意味着在您这样做之后

int rx_length = read(serial, &rx, MAX_TXRX_BUF);

没有rx中没有有效的C字符串。您需要执行以下操作:

char rx[MAX_TXRX_BUF + 1]; // extra space for terminator
ssize_t rx_length = read(serial, rx, MAX_TXRX_BUF);
if (rx_length >= 0) {
    rx[rx_length] = '\0';
    // use rx here
    // if rx_length == 0, handle EOF
} else {
    // read error
}

即使我不知道为什么输出会发生变化,但我预计如果将两个printf放在我有// use rx here的位置,它们将始终打印相同的内容。

像使用&rx一样,获取整个数组的地址几乎总是一个错误。在大多数情况下,为了引用C中的数组,您真正想要的是第一个元素的地址,这就是您仅用rx获得的地址。 (由于过于繁琐和切线的原因,read不在乎您提供它的两个之一,但是在其他情况下,它可能导致细微的错误。因此,C的最佳实践是使用即使没有关系的情况下,第一个元素的地址也要保留;在特殊情况下确实需要整个数组的地址的情况下,请保留&rx。)