用于接收数据流的 UART 同步算法

UART Synchronization Algorithm for receiving Stream of Data

我正在使用此代码通过 UART 接收此帧 [=11=],S1,B2,Kffffffffffff,T61*34

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

帧的开头总是$,结尾总是*,之后两个字节保存前一个字节的校验和(例如34)。

帧长度不固定,但最小长度为 26(从 $*)+ 2 个字节的校验和,最大长度为 62 以及 + 2 个字节的校验和校验和。

但这不是最好的使用方法,因为可能会发生很多情况使它不稳定,例如,如果 * 没有到达,这将使我读取的每一帧都是错误的。

我搜索了通过 UART 接收数据的更好方法,但没有找到任何东西。 我正在寻找更好的方法来处理这样的接收帧。

此解决方案基于没有尾随 CR 或 LF 的假设,但在这种情况下也可以通过跳过 CR 和 LF 直到找到 $

我建议将您的算法与检查 $ 相结合,这会将位置重置为 0 并将 $ 存储在位置 0。这将忽略不包含 * 在预期的位置。

您可能应该在进入循环之前将 size 初始化为最大值,并确保 size 不会增加,以防收到 * 太晚。

此外,我会确保第一个字符是 '$',如果不是这样,则不会增加索引。

对于索引的这种条件递增,while 循环更适合。

未经测试的提议:

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++;
    }
}

附加提示:为了在 PC 上测试算法,您可以将 EUSART1_Read 替换为 fgetcgetchar。请注意,这些函数 return 一个 int 值,应在将其转换为 unsigned char.

之前检查 EOF

如果您对特殊的数据包标记感兴趣,请寻找它们:等到开始($),然后记录并计算所有内容直到结束(*),然后再阅读两个字符。

在记录和计数的同时,检查空间以免溢出。根据您预期的错误数量,按照@Bodo 的建议,在收到“*”时重置计数可能是个好主意。

有没有办法知道 EUSART1_Read() 是否真的找到了一个角色?还是永远等待(危险)?最好不要等待太多,并且知道有更多的字符要读取。