串口在持续接收数据时容易发生数据黏包(先接收的数据尚未被处理,后面的数据已经将内存覆盖)的情况,循环缓冲区的本质就是将串口接受到的数据马上拷贝到另外一块内存之中。为了避免新来的数据覆盖掉尚未处理的数据,一方面缓冲区的长度需要有一定的冗余,另外一方面需要引入写索引(写指针)始终指向未写数据区域的开头。
当一包数据发生溢出的时候,也可以被切割为两部分,一部分写在缓冲区最后,另外一部分写在缓冲区开头。
与此同时,为了防止写入buffer的新数据把尚未处理的旧数据覆盖掉,我们还需要引入读索引的机制,让其指向正在解析的数据的开头。CPU解析完成一帧数据之后再让readIndex指向下一帧需要解析的数据。
综上,当新数据到来之时,我们就需要判断writeIndex和readIndex之间的空闲区域是否能装下新的数据,如果装不下,就只能抛弃这一帧数据。出现这种情况后,我们就需要调整这三个参数:(增大)缓冲区大小、(减慢)发送方发送速度、(加快)数据处理速度。
循环缓冲区算法示意图:
注意,readIndex(读指针)除了防止未处理的数据被覆盖之外,还可以用来寻找完整的数据包,用来破解拆包、粘包以及坏包问题。
假定数据帧通过以下数据格式发送,包头为0xAA代表一帧数据包的开始,随后是一字节的数据包长度,然后是一定长度的数据,最后一位则是校验和(计算方式是将前面所有位相加取最后一字节数据)。
IOC文件准备:
①开启调试接口与外部时钟晶振,设置时钟主频为72Mhz。
②使能串口2的全局中断。
③在Core和Src文件目录下分别新建command.c与command.h文件