文章目录
1 什么是环形缓冲区
环形缓冲区是一个先进先出(FIFO)的闭环的存储空间。通俗的理解为,在内存中规划了一块连续等分的环形内存,然后分别通过写指针和读指针对缓冲区的数据进行读写。而实际上,计算机内存的空间位置不一定是环形的,所以我们可以开辟一段连续的内存,然后将其首尾相连,如下图所示:
存储数据:当每有一个数据需要存储时,就存储在Write所指向的位置,存储完毕后Write将指向下一个位置。
读取数据:每当读取一个数据时,将读取Read指向的位置,当读取完毕后Read指向下一个位置。
2 环形缓冲区代码实现(基于C语言)
2.1 结构体定义
定义结构体类型 RingQueueBuffer_t 用于开辟环形缓冲区。
#define RING_QUEUE_BUFF_SIZE 1024 //配置缓冲区开辟大小
typedef struct ring_queue {
uint16_t head; //记录读位置,相当于Read
uint16_t tail; //记录写位置,相当于Write
uint16_t lenth; //记录缓冲区的数据个数
uint8_t buff[RING_QUEUE_BUFF_SIZE]; //缓冲区
}RingQueueBuffer_t;
2.2 缓冲区的初始化
初始化过程只需要将头指针、尾指针、缓冲区数据长度清零即可。
void RQBuff_Init(RingQueueBuffer_t* RQ_Buff) {
RQ_Buff->head = RQ_Buff->tail = RQ_Buff->lenth = 0;
}
2.3 缓冲区添加数据
1.在添加数据的过程中需要保证缓冲区非满,通过检测缓冲区的数据长度是否等于所开辟缓冲区大小RING_QUEUE_BUFF_SIZE 即可。
2.添加数据:在缓冲区的tail写入要添加的数据即可。
3.添加数据完毕后,将tail指向下一个位置,并记录缓冲区的数据长度 lenth++
注意:(RQ_Buff->tail + 1) % RING_QUEUE_BUFF_SIZE 可以实现tail 指向末尾位置后自动跳转到缓冲区的0位置。
uint8_t RQBuff_AddData(RingQueueBuffer_t* RQ_Buff, uint8_t data) {
///--溢出检测
if (RQ_Buff->lenth >= RING_QUEUE_BUFF_SIZE) {
return 0;
}
///---写入数据
RQ_Buff->buff[RQ_Buff->tail] = data;
///写指针位置+1,防溢出
RQ_Buff->tail = (RQ_Buff->tail + 1) % RING_QUEUE_BUFF_SIZE;
///数据长度计数
RQ_Buff->lenth++;
return 1;
}
2.4 读取数据
1.在读取数据的过程中需要保证缓冲区非空,通过检测缓冲区的数据长度是否等于0即可。
2.读取数据:读出缓冲区head指向的数据。
3.读取数据完毕后,将head指向下一个位置。由于读取后缓冲区数据少了一个,则记录缓冲区的数据长度 lenth–
注意:(RQ_Buff->head + 1) % RING_QUEUE_BUFF_SIZE 可以实现*head * 指向末尾位置后自动跳转到缓冲区的0位置。
uint8_t RQBuff_ReadData(RingQueueBuffer_t* RQ_Buff,uint8_t* data) {
///--缓冲区空检测
if (RQ_Buff->lenth == 0) {
return 0;
}
///---读出数据
*data = RQ_Buff->buff[RQ_Buff->head];//FIFO
///读指针位置+1,防溢出
RQ_Buff->head = (RQ_Buff->head + 1) % RING_QUEUE_BUFF_SIZE;
///数据长度计数
RQ_Buff->lenth--;
return 1;
}
2.5 获取缓冲区数据长度
uint16_t RQBuff_GetBuffLenth(RingQueueBuffer_t* RQ_Buff) {
return RQ_Buff->lenth;
}
3 环形缓冲区的完整代码
3.1 头文件
#ifndef __DATAPROCE_H
#define __DATAPROCE_H
#include <stdint.h>
/*
* 数据缓冲区配置
*/
#define RING_QUEUE_BUFF_SIZE 1024 //配置缓冲区开辟大小
typedef struct ring_queue {
uint16_t head;
uint16_t tail;
uint16_t lenth;
uint8_t buff[RING_QUEUE_BUFF_SIZE];
}RingQueueBuffer_t;
/*
*
*/
void RQBuff_Init(RingQueueBuffer_t* RQ_Buff); //初始化指定缓冲区
uint8_t RQBuff_AddData(RingQueueBuffer_t* RQ_Buff, uint8_t data); //指定缓冲区添加数据
uint8_t RQBuff_ReadData(RingQueueBuffer_t* RQ_Buff, uint8_t* data); //指定缓冲区读取数据
uint16_t RQBuff_GetBuffLenth(RingQueueBuffer_t* RQ_Buff); //读取指定缓冲区的数据长度
#endif
3.2 源文件
#include "DataProce.h"
/**
==============================================================================
##### 数据缓冲区系列函数 #####
==============================================================================
[..]
(#) 初始化缓冲区函数: RQBuff_Init()
(#) 添加数据使用函数: RQBuff_AddData()
(#) 读取数据使用函数: RQBuff_ReadData()
(#) 获得缓冲区数据长度使用函数: RQBuff_GetBuffLenth()
(++)输入参数RQ_Buff类型为RingQueueBuffer_t,该参数作为被操作的对象,必须为
提前定义好的全局变量
******************************************************************************
*/
/**
* 函数:RQBuff_Init()
* 该函数初始化指定的缓冲区
* 输入参数:
* RQ_Buff:待操作的缓冲区
* 返回值: 无
**/
void RQBuff_Init(RingQueueBuffer_t* RQ_Buff) {
RQ_Buff->head = RQ_Buff->tail = RQ_Buff->lenth = 0;
}
/**
* 函数:RQBuff_AddData()
* 该函数向指定的缓冲区添加一个指定的u8数据
* 输入参数:
* RQ_Buff:待操作的缓冲区
* data:需要添加的数据
* 返回值: 0:添加失败 1:添加成功
**/
uint8_t RQBuff_AddData(RingQueueBuffer_t* RQ_Buff, uint8_t data) {
///--溢出检测
if (RQ_Buff->lenth >= RING_QUEUE_BUFF_SIZE) {
return 0;
}
///---写入数据
RQ_Buff->buff[RQ_Buff->tail] = data;
///写指针位置+1,防溢出
RQ_Buff->tail = (RQ_Buff->tail + 1) % RING_QUEUE_BUFF_SIZE;
///数据长度计数
RQ_Buff->lenth++;
return 1;
}
/**
* 函数:RQBuff_ReadData()
* 该函数从指定的缓冲区读取一个数据
* 输入参数:
* RQ_Buff:待操作的缓冲区
* data:读取数据的存储地址
* 返回值: 0:读取失败 1:读取成功
**/
uint8_t RQBuff_ReadData(RingQueueBuffer_t* RQ_Buff,uint8_t* data) {
///--缓冲区空检测
if (RQ_Buff->lenth == 0) {
return 0;
}
///---读出数据
*data = RQ_Buff->buff[RQ_Buff->head];//FIFO
///读指针位置+1,防溢出
RQ_Buff->head = (RQ_Buff->head + 1) % RING_QUEUE_BUFF_SIZE;
///数据长度计数
RQ_Buff->lenth--;
return 1;
}
/**
* 函数:RQBuff_GetBuffLenth()
* 该函数获得指定缓冲区的数据长度
* 输入参数:
* RQ_Buff:待操作的缓冲区
* 返回值: 缓冲区的数据长度
**/
uint16_t RQBuff_GetBuffLenth(RingQueueBuffer_t* RQ_Buff) {
return RQ_Buff->lenth;
}
4 环形缓冲区使用方法
1.建立一个缓冲区
RingQueueBuffer_t RQBuff1;
2.初始化缓冲区
RQBuff_Init(&RQBuff1);
3.添加缓冲数据
/*其他得到数据的代码*/
RQBuff_AddData(&RQBuff1,data);
4.处理数据
if(RQBuff_GetBuffLenth(&RQBuff1)!=0){//缓冲区有数据
/*读取数据,处理数据/
}