理解
环形缓冲区就是一个带“头指针”和“尾指针”的数组。“头指针”指向环形缓冲区中可读的数据,“尾指针”指向环形缓冲区中可写的缓冲空间。通过移动“头指针”和“尾指针”就可以实现缓冲区的数据读取和写入。在通常情况下,应用程序读取环形缓冲区的数据仅仅会影响“头指针”,而串口接收数据仅仅会影响“尾指针”。当串口接收到新的数组,则将数组保存到环形缓冲区中,同时将“尾指针”加1,以保存下一个数据;应用程序在读取数据时,“头指针”加1,以读取下一个数据。当“尾指针”超过数组大小,则“尾指针”重新指向数组的首元素,从而形成“环形缓冲区”!,有效数据区域在“头指针”和“尾指针”之间。
如上面说的,环形缓冲区其实就是一个数组,将其“剪开”,然后“拉直”后如下图
环形缓冲区的特性
- 先进新出。
- 当缓冲区被使用完,且又有新的数据需要存储时,丢掉历史最久的数据,保存最新数据。
代码实现
创建环形缓冲区
首先需要创建一个环形缓冲区
当我们发现环形缓冲区被“冲爆”时,也就是缓冲区满了,但是还有待缓冲的数据时,只需要修改RINGBUFF_LEN的宏定义,增大缓冲区间即可。#define RINGBUFF_LEN (500) //定义最大接收字节数 500
#define RINGBUFF_OK 1
#define RINGBUFF_ERR 0
typedef struct
{
uint16_t Head;
uint16_t Tail;
uint16_t Lenght;
uint8_t Ring_data[RINGBUFF_LEN];
}RingBuff_t;
RingBuff_t DATA_ringBuff;//创建一个ringBuff的缓冲区
环形缓冲区的初始化
主要是将环形缓冲区的头,尾和长度清零,表示没有任何数据存入。void RingBuff_Init(RingBuff_t *ringBuff)
{
//初始化相关信息
ringBuff->Head = 0;
ringBuff->Tail = 0;
ringBuff->Lenght = 0;
}
环形缓冲区的写入
```c //写入一个char unsigned char Write_Single_RingBuff(RingBuff_t *ringBuff, unsigned char data) { if(ringBuff->Lenght >= RINGBUFF_LEN) //判断缓冲区是否已满 { return RINGBUFF_ERR; } ringBuff->Ring_data[ringBuff->Tail]=data; ringBuff->Tail = (ringBuff->Tail+1)%RINGBUFF_LEN;//防止越界非法访问 ringBuff->Lenght++; return RINGBUFF_OK; }
//写入多个char
unsigned char Write_RingBuff(RingBuff_t ringBuff, uint8_t data, rt_uint32_t len)
{
for(int i = 0;i
这个接口是写入一个字节到环形缓冲区。这里注意:大家可以根据自己的实际应用修改为一次缓冲多个字节。并且这个做了缓冲区满时报错且防止非法越界的处理,大家可以自行修改为缓冲区满时覆盖最早的数据。
<a name="TBDGK"></a>
## 环形缓冲区的读取
```c
unsigned char Read_RingBuff(RingBuff_t *ringBuff, unsigned char *rData)
{
if(ringBuff->Lenght == 0)//判断非空
{
return RINGBUFF_ERR;
}
*rData = ringBuff->Ring_data[ringBuff->Head];//先进先出FIFO,从缓冲区头出
ringBuff->Head = (ringBuff->Head+1)%RINGBUFF_LEN;//防止越界非法访问
ringBuff->Lenght--;
return RINGBUFF_OK;
}
使用
RingBuff_t DATA_ringBuff;
RingBuff_Init(&DATA_ringBuff);//初始化环形队列
unsigned char data;
if(Read_RingBuff(&DATA_ringBuff, &data)) //从环形缓冲区中读取数据
{
Command_ReceiveAndCheck(data);
}
串口接收中断
void EXCHANGE_USART_IRQHandler(void)
{
if(USART_GetITStatus( EXCHANGE_USART,USART_IT_RXNE)!=RESET)
{
Write_RingBuff(&DATA_ringBuff, USART_ReceiveData(EXCHANGE_USART));
USART_ClearITPendingBit(EXCHANGE_USART, USART_IT_RXNE);
}
}
RTT使用
RTT里面自带Ringbuffer
https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device-ipc/ringbuffer/ringbuffer