上面我们给出了程序源码,然后根据自己的工程框架放到自己工程下面,接下来我们就来实际说明一下怎么使用。
我们这里把标准库 和 HAL 库的串口数据处理都说明一下。
3.1 标准库
首先我们需要定义一个环形缓冲区,在我们的 STM32 上也就是顶一个结构体变量。 在我们上面的 ringbuff.h
文件中有一个名为 RingBuff_t
的结构体,我们需要定义一下:
我们可以通过定义 BUFFER_SIZE
来定义自己的缓冲区大小。
#define BUFFER_SIZE 1024 /* 环形缓冲区的大小 */
然后在程序初始化阶段,使用 RingBuff_Init
初始化一下这个变量,如下图:
数据写入:
好,对于标准库而言,我们串口接收数据一般在串口中断中实现,我们实现的方式如下:
以前我们每次收到数据或许也会放到自己定义的缓冲区中,使用了环形缓冲区,我们直接使用Write_RingBuff
函数即可。
数据读取:
那么怎么读取数据呢?
我们在环形缓冲区实现代码里面有Read_RingBuff_Byte
读取数据的函数,读取的关键在于什么时候读!
有一种通用的方式,就是隔一段时间检查一下环形缓冲区是否为空,如果不为空,就进行读取。这个可以放在 while
循环中进行,我这里给个例子:
当然,除了这种等待一段时间让数据接收完成的方式,对于 STM32 而言,还有利用空闲中断(IDLE)的方式,具体实现如下:
当然,在标准库中使用 IDLE 中断,记得使能一下中断,如下图:
在程序中,如果需要清空缓存,也是直接使用 RingBuff_Init
即可。实际上都不用清空缓冲区内的数据,即便其他位置有数据也没有关系,因为我们判断是否有数据都是先通过指针位置来判断,才进行读写操作,所以内存中即便有数据,也会被覆盖。
3.2 HAL库
接下来说说 HAL 库,其实操作逻辑也是一样的,只不过 HAL 库开启接收中断的时候需要使用 HAL_UART_Receive_IT
函数 。
第一步,当然是定义 RingBuff_t
结构体变量,初始化,流程和标准库一样,只不过初始化函数需要多加上一句话,使用 HAL_UART_Receive_IT
开启接收中断,而且还需要额外定义一个变量,用来配合这个函数 ,具体的如下图:
使用上面 RingBuff_Init
完成初始化。
数据写入:
数据的接收也是在串口中断的时候进行,在 HAL 库中操作如下:
因为定义了一个变量 data_tmp
用来存放接收到的串口数据,而且每次接收完以后,接收到的数据又存放于 data_tmp
。
数据读取:
至于数据读取, HAL 的方式完全和 标准库一样,好像没有什么特别需要注意的,可以循环中判断缓冲区非空,进行读取数据,也可以通过 IDLE 中断,进行读取数据然后处理。
3.3 数据处理的细节说明
上面我们已经掌握了如何存环形缓冲区,什么时候取数据,怎么取数据,这里再补充一下数据处理中的一个问题。
因为我们处理数据都是一帧一帧的,我们不管接受到正确的数据,还是不需要的数据,我们都需要把一帧数据读取完。 否者会影响下一帧数据的处理。 如果不用环形缓冲区,用最简单粗暴的方法就是一旦检测到错误的数据,直接清空缓冲区,但是这在数据量大的时候很容易会导致丢包的情况。我们采用环形缓冲区就是为了尽可能的避免丢包。
所以呢即便我们收到不需要的数据,我们也需要把这个错误的数据读取完毕。
我们接受的数据协议,一般在包头后面都会跟上本条数据的长度,所以,我们可以根据读到的长度信息,使用RingBuff_ReadNByte
把剩余的数据读取完毕。
比如:
知道如何处理不需要的数据,基本上环形缓冲区的使用也没有什么问题了。