RS-232 communication with RPi

2019-09-01 17:37发布

问题:

This is a follow up question to this original post:

RaspberryPi RS-232 trouble

I made changes to my code per the accepted answer, the terminal is now set up for blocking and canonical input. The read() now works as expected, with the exception of the very first read(which is typically some extra random symbols mixed with some good data) I get single lines of data from the laser range finder representing exactly what I expect to see.

However, I now have an issue that if I do too many reads, the laser range finder is put into a non-operating state, stops communication, and can only be reset by doing a power cycle. This has happened with as few as 4 reads on the device, and I haven't been able to do more than 8 reads. It doesn't matter if the reads are all at once, or spanned across several program starts.

int main(){
    int uart0_filestream = -1;
    int loop, i, sentBytes;
    int isError, rx_length;
    unsigned char rx_buffer[256];

    uart0_filestream = open("/dev/ttyAMA0", O_RDWR | O_NOCTTY | O_NDELAY);
    fcntl(uart0_filestream, F_SETFL, 0);

    if(uart0_filestream == -1){
        printf("ERROR: Unable to open UART\n");
        checkError(errno);
        exit(1);
    }

    struct termios options;

    isError = tcgetattr(uart0_filestream, &options);

    if(isError < 0){
        printf("ERROR: tcgetattr failed.\n");
        checkError(errno);
        exit(1);
    }

    //set c ontrol options and baud
    options.c_cflag |= (CLOCAL | CREAD);
    cfsetispeed(&options, B19200);
    cfsetospeed(&options, B19200);

    //set 8 data bits, 1 stop bit, no parity
    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;

    //set input options
    options.c_iflag |= (INPCK | ISTRIP);        //strip parity
    options.c_iflag &= ~(IXON | IXOFF | IXANY); //turn off software flow control

    //set canonical input processing
    options.c_lflag |= (ICANON | ECHO | ECHOE);

    tcflush(uart0_filestream, TCIFLUSH);
    isError = tcsetattr(uart0_filestream, TCSANOW, &options);

    if(isError < 0){
        printf("ERROR: tcsetattr failed.\n");
        checkError(errno);
        exit(1);
    }

    //read() successfully returns expected data, with the exception of the first 
    //read. Reading more than 6-8 times, regardless of same session or restarting
    //program puts LRF in non-working state which requires a power cycle to fix
    for(i=0; i<4;i++ ){
        rx_length = read(uart0_filestream, (void*)rx_buffer, 255);

        if(rx_length < 0){
            printf("ERROR: read() failed.\n");
            checkError(errno);
        }

        if(rx_length > 0){
            printf("rx_lentgh = %i:\t ", rx_length);
            for(loop=0; loop<rx_length; loop++){
                printf("%c", rx_buffer[loop]);
            }
            printf("\n");
        }
    }

    //writing once has no affect, sending command has no affect
    //looping the write, eventually 'something' gets to the LRF
    //but it puts it in the same state as when reading too many
    //times and have to power cycle
    for(i = 0; i<8; i++){
        sentBytes = write(uart0_filestream, "o\n", 2);

        if(sentBytes < 2){
            printf("ERROR: write() failed.\n");
            checkError(errno);
        }   
    }

    close(uart0_filestream);
}

I don't believe it is the range finder, as I can run minicom and it will continuously display the output successfully.

As noted in the comments of my code, I also have trouble writing any commands to the laser range finder. Each command consists of a single character, followed by a new line. One write has no affect, but looping several times can put the device in the same state as reading too many times.

I have read Posix Serial Programming Guide, and tried different combinations of flags that I believe might affect either the reading or writing, but have had no success.

回答1:

[Edit] This lead suggestion is my embarrassment - thought the string was "o/n".

The amount of data sent is short by 1.

// sentBytes = write(uart0_filestream, "o\n", 2);
// if(sentBytes < 2){
sentBytes = write(uart0_filestream, "o\n", 3);
if(sentBytes < 3){

Minor: Unclear why read buffer is reduced by 1 (sizeof rx_buffer is 256). read() is not going to append a \0 and neither does this code. Code nicely treats the incoming data as an array of bytes. Although in printf("%c"... something could be done if !isgraph(rx_buffer[loop])`.

// rx_length = read(uart0_filestream, (void*)rx_buffer, 255)
rx_length = read(uart0_filestream, (void*)rx_buffer, sizeof rx_buffer)