简体   繁体   中英

linux serial port read() wrong data

I am writing a small program to communicate with a AVR MCU, on PC side I used posix write() and read() to access the serial port, I connected the serial port's RX and TX pins to test if it can properly send and receive data, in theory everything sent out should end up exactly the same in the receive buffer, it is the case when the message being sent is short and sending frequency is low, read() returns the same message as sent out, but when the message gets longer and sent more frequently, read() returns the wrong data, the characters seem to be in the wrong order, my guess is read() or write() is not in block mode, so when old transfer hasn't finish yet, new transfer(write()?) arrived, interrupts the old transfer and changed the TX buffer.

I am a newbie in Linux programing, please anybody help me on this, it's killing me ... any help is greatly appreciated.

Edit: I noticed in the write() man page: A successful return from write() does not make any guarantee that data has been committed to disk. In fact, on some buggy implementations, it does not even guarantee that space has successfully been reserved for the data. The only way to be sure is to call fsync(2) after you are done writing all your data.

I tried the fsync() function, still getting the same wrong result.

Here is the code:

#include <stdio.h>
#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */

int main(void) {

    int fd;
//  fd = open("/dev/tty.usbmodem1a21", O_RDWR | O_NOCTTY | O_NDELAY);
    fd = open("/dev/tty.usbmodem1a21", O_RDWR | O_NOCTTY);
    if (fd == -1) {
        //Could not open the port.
        perror("open_port: Unable to open port ");
    }
        else
        fcntl(fd, F_SETFL, 0);

    char s[] = "Hello, this is a test of the serial port access";

    int cnt;
    unsigned char in[100];
    for(cnt=0; cnt<10; cnt++) {
        int n = write(fd, s, sizeof(s));
        if (n < 0)
            fputs("write() failed!\n", stderr);

        usleep(50000);  // works fine with delay

        read(fd, in, 100);


            printf("%s\n", in);
    }

    return 0;
}

在write()和read()之间使用sleep()在write()和read()之间没有sleep()

Eric

Start by using the return value from read() . Remember: read does not yield nul-terminated strings.

n=read(fd, in, 100);

        printf("%*.*s\n", n,n, in);

(1) Always check return codes. (2) If you try to printf a string that hasn't been null terminated you are going to end up printing any junk that is in memory (or worse).

My guess is that your real problem is that read/write are NOT guaranteed to write the number of bytes you specify. The number that they actually read/write is in the return code. So as the fd buffer fills up you could be writing 1 byte and then trying to print a non-null string of that 1 byte and everything after it.

Try something like this and see if things change.

int cnt;
unsigned char in[100];

for(cnt=0; cnt<10; cnt++) 
{
    int n = write(fd, s, sizeof(s));

    if (n < 0)
    {
        perror("write");
        exit(EXIT_FAILURE);
    }

    n = read(fd, in, 100);

    if (n < 0)
    {
        perror("read");
        exit(EXIT_FAILURE);
    }

    in[n] = '\0';

    printf("%s\n", in);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM