STM32/GD32 학습 가이드 - 구덩이를 밟다 (3) 링 버퍼 사용 방법, 링 버퍼 읽는 방법

수신된 데이터를 처리할 때 링 버퍼는 처리할 데이터를 저장하는 데 사용되는 경우가 많으며, 특히 메모리가 본질적으로 작은 단일 칩 마이크로컴퓨터에서는 메모리 사용량을 절약할 필요가 있습니다.

링 버퍼의 사용은 데이터 헤드와 테일의 포인터 오프셋을 통해 데이터를 쓰고 읽는 것입니다.

예를 들어, 이제 외부에서 데이터를 수신하고 이를 링 버퍼에 저장한 다음 링 버퍼에서 데이터를 읽고 일부 프레임 형식 및 데이터 확인 작업을 수행한 다음 링에서 데이터를 읽는 직렬 포트가 있습니다. 버퍼 직렬 포트가 전송됩니다.

다음으로 두 가지 방법으로 링 버퍼를 도입합니다.

1. 간단한 링 버퍼 사용 - 단일 바이트 쓰기 및 읽기

1. 링 버퍼의 구조 정의

버퍼 길이는 처리해야 하는 데이터 양의 크기에 따라 정의할 수 있습니다.

헤드(Head): 다음에 읽어올 데이터의 첫 번째 주소인 현재 큐의 헤드는 데이터의 접근 상태에 따라 동적으로 변경된다.

Tail: 현재 Queue의 tail, 즉 다음 데이터가 기록될 때의 첫 번째 주소는 데이터의 접근 상태에 따라 동적으로 변경됩니다.

길이 : 현재 버퍼에 저장된 데이터의 길이, 즉 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. 링 버퍼 데이터를 쓰는 코드

/**
  *功能:数据写入环形缓冲区
  *入参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. 링 버퍼의 데이터를 읽습니다.

/**
  *功能:读取缓存区整帧数据-单字节读取
  *入参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. 직렬 포트를 사용하여 데이터 테스트를 보내고 받는 경우 다음과 같이 직렬 포트 인터럽트 중에 수신된 데이터를 링 버퍼에 써야 합니다.

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. 메인 메인 스레드에서는 다음과 같이 while 루프를 통해 링 버퍼의 데이터를 읽고 직렬 포트에서 보냅니다.

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◕∀◕)ノ

추천

출처blog.csdn.net/qq_38584212/article/details/131727153