Home > database >  UART Synchronization Algorithm for receiving Stream of Data
UART Synchronization Algorithm for receiving Stream of Data

Time:12-10

I am receiving this frame $0,S1,B2,Kffffffffffff,T61*34 through UART with this code.

//Receive Data
for(uint8_t i = 0; i < size; i  ){
    receivedFrame[i] = EUSART1_Read();
    if(receivedFrame[i] == '*'){
        size = i   3;
    }
}

The start of the frame is always $ and the end is always * after that comes two bytes holds the check sum for the previous bytes (ex 34).

The frame length is not fixed but it has a minimum length of 26(from $ to *) 2 bytes of check sum and maximum length of 62 and also 2 bytes of check sum.

but it is not the best thing to use since so many scenarios could happen to make this unstable for example if the * didn't arrive, this will make every frame I read is wrong.

I searched for better way to receive data through UART but didn't manage to find any thing. I am looking for better ways to deal with receiving frames like this.

CodePudding user response:

This solution is based on the assumption that there is no trailing CR or LF, but it will also work in this case by skipping CR and LF until $ is found.

I suggest to combine your algorithm with a check for $ which whould reset the position to 0 and store the $ at position 0. This will ignore frames that don't contain * at the expected position.

You probably should initialize size to the maximum before entering the loop and make sure that size is not increased in case the * is received too late.

Additionally I would make sure that the first character is '$' and not increment the index if this is not true.

For this conditional incrementing of the index, a while loop is better suited.

Untested proposal:

unsigned char receivedFrame[64];
uint8_t size = sizeof(receivedFrame);
uint8_t i = 0;
while(i < size)
{
    unsigned char ch = EUSART1_Read();
    if(ch == '$')
    {
        // in case i was > 0, ignore wrong frame, start from beginning
        i = 0;
    }
    else if(receivedFrame[i] == '*'){
        uint8_t new_size = i   3;
        if(new_size < size)
        {
            size = new_size;
        }
    }
    receivedFrame[i] = ch;
    // stay at the first position if the character is not '$'
    if((i > 0) || (ch == '$'))
    {
        i  ;
    }
}

Additional hint: For testing the algorithm on a PC you could replace EUSART1_Read with fgetc or getchar. Note that these functions return an int value which should be checked for EOF before converting it to an unsigned char.

CodePudding user response:

If you are interested in special packet markers, then look for them: wait until a start ($), then record and count everything until end (*), then read two chars more.

While recording and counting, check for room in order to not overflow. Depending of how many errors you expect, it could be a nice idea to reset the count when an "*" is received, as suggested by @Bodo.

Is there a way to know if EUSART1_Read() really found a character? Or does it wait for ever (dangerous)? Better would be to not wait too much, and knowing there are more chars to read.

  • Related