STM32/GD32学习指南-踩坑之(三)环形buffer使用方法,环形缓存区的读取操作方法

文章介绍了环形buffer在处理串口接收数据时的作用,通过定义结构体存储数据,使用头部和尾部指针进行数据的写入和读取操作。在数据溢出时,会清空并重新初始化buffer。在中断中接收数据并写入环形buffer,主循环中读取数据并发送出去,实现串口通信的数据流转。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在处理接收数据时,经常使用到环形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◕∀◕)ノ

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

披着假发的程序唐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值