在处理接收数据时,经常使用到环形buffer存储数据进行处理,尤其是单片机中,内存本来就小,就需要节约内存的使用。
环形buffer的使用就是通过数据头、尾的指针偏移,进行数据的写入和读取
例如:现在有一个串口,接收到外部发来的数据,将其存入到环形buffer中,然后再从该环形buffer中将数据读取出来,进行一些帧格式、数据校验的操作,再从该串口发送出去。
接下来,分两种方式对环形buffer进行介绍
一、简单的环形buffer使用-单字节写入和读取
1. 定义环形buffer的结构体
buffer长度根据自己需要处理数据量的大小定义就行
Head:当前队列头部,也就是下次数据读取时的首地址,根据数据的存取状态,是动态变化的
Tail:当前队列尾,也就是下次数据写入时的首地址,根据数据的存取状态,是动态变化的
Length:当前buffer中存储的数据长度,也就是Head到Tail之间的数据长度
Ring_Buff:存储数据的内存区域
#define RINGBUFF_LEN 10240 //定义最大接收字节数 10240
//环形buffer结构体
typedef struct
{
uint32_t Head;
uint32_t Tail;
uint32_t Length;
uint8_t Ring_Buff[RINGBUFF_LEN];
} RingBuff_t;
2. 写入环形buffer数据的代码
/**
*功能:数据写入环形缓冲区
*入参1:要写入的数据
*入参2:buffer指针
*返回值:buffer是否已满
*/
uint8_t Write_RingBuff(volatile uint8_t data, RingBuff_t *ringBuff)
{
if(ringBuff->Length >= RINGBUFF_LEN) //判断缓冲区是否已满
{
//如果buffer爆掉了,清空buffer,进行重新初始化
memset(ringBuff, 0, RINGBUFF_LEN);
RingBuff_Init(ringBuff);
return 1;
}
//将单字节数据存入到环形buffer的tail尾部
ringBuff->Ring_Buff[ringBuff->Tail]=data;
//重新指定环形buffer的尾部地址,防止越界非法访问
ringBuff->Tail = ( ringBuff->Tail + 1 ) % RINGBUFF_LEN;
//存入一个字节数据成功,len加1
ringBuff->Length++;
return 0;
}
3. 读取环形buffer中的数据
/**
*功能:读取缓存区整帧数据-单字节读取
*入参1:存放提取数据的指针
*入参2:环形区buffer指针
*返回值:是否成功提取数据
*/
uint8_t Read_RingBuff_Byte(uint8_t *rData, RingBuff_t *ringBuff)
{
if(ringBuff->Length == 0)//判断非空
{
return 1;
}
//先进先出FIFO,从缓冲区头出,将头位置数据取出
*rData = ringBuff->Ring_Buff[ringBuff->Head];
//将取出数据的位置,数据清零
ringBuff->Ring_Buff[ringBuff->Head] = 0;
//重新指定buffer头的位置,防止越界非法访问
ringBuff->Head = (ringBuff->Head + 1) % RINGBUFF_LEN;
//取出一个字节数据后,将数据长度减1
ringBuff->Length--;
return 0;
}
4. 如果使用串口收发数据测试,需要在串口中断中将接收到的数据写入到环形buffer中,如下
extern RingBuff_t ringBuff0; //实例化一个环形buffer对象
/**
*功能:串口0中断接收函数
*/
void USART0_IRQHandler(void)
{
volatile uint16_t data;
if( usart_interrupt_flag_get(USART0,USART_INT_FLAG_RBNE) != RESET)
{
data = usart_data_receive(USART0); //接收串口数据
Write_RingBuff(data, &ringBuff0); //将窗口数据写入环形buffer
}
}
5. main主线程中,再通过while循环将数据从环形buffer中读取出来,从串口再发送出去,如下
uint8_t read_data = 0; //存放读取环形buffer的数据
RingBuff_t ringBuff0; //实例化一个环形buffer对象
int main(void)
{
/* configure systick */
systick_config();
//初始化环形buffer以及所有外设资源
all_peripheral_init();
while(1){
//开发板测试:USART0接收,USART0发送
ret = Read_RingBuff_Byte(&read_data, &ringBuff0);
if(ret == 0){
//将读取的环形buffer数据通过串口发送出去
uart_send_byte(USART0, read_data);
}
}
}
/**
*功能:串口数据发送函数
*入参1:串口号
*入参2:要发送的字节数据
*/
void uart_send_byte(uint32_t com, uint8_t ch)
{
while(usart_flag_get(com, USART_FLAG_TBE) == RESET );
usart_data_transmit(com, ch);
}
希望大家点赞、收藏、关注哦!!!ヾ(o◕∀◕)ノ