用于接收数据流的 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
替换为 fgetc
或 getchar
。请注意,这些函数 return 一个 int
值,应在将其转换为 unsigned char
.
之前检查 EOF
如果您对特殊的数据包标记感兴趣,请寻找它们:等到开始($),然后记录并计算所有内容直到结束(*),然后再阅读两个字符。
在记录和计数的同时,检查空间以免溢出。根据您预期的错误数量,按照@Bodo 的建议,在收到“*”时重置计数可能是个好主意。
有没有办法知道 EUSART1_Read() 是否真的找到了一个角色?还是永远等待(危险)?最好不要等待太多,并且知道有更多的字符要读取。
我正在使用此代码通过 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
替换为 fgetc
或 getchar
。请注意,这些函数 return 一个 int
值,应在将其转换为 unsigned char
.
EOF
如果您对特殊的数据包标记感兴趣,请寻找它们:等到开始($),然后记录并计算所有内容直到结束(*),然后再阅读两个字符。
在记录和计数的同时,检查空间以免溢出。根据您预期的错误数量,按照@Bodo 的建议,在收到“*”时重置计数可能是个好主意。
有没有办法知道 EUSART1_Read() 是否真的找到了一个角色?还是永远等待(危险)?最好不要等待太多,并且知道有更多的字符要读取。