STM32/GD32 スタディガイド ピットを踏む (3) リングバッファの使い方、リングバッファの読み方

受信データを処理する場合、特にシングルチップマイコンではメモリ容量が少ないため、メモリ使用量を節約する必要があるため、処理用のデータを保存するためにリングバッファが使用されることがよくあります。

リング バッファの使用は、データの先頭と末尾のポインタ オフセットを介してデータの書き込みと読み取りを行うことです。

例: 外部からデータを受信し、それをリング バッファに格納し、リング バッファからデータを読み取り、いくつかのフレーム フォーマットとデータ検証操作を実行してから、リングからデータを読み取るシリアル ポートがあります。シリアルポートが送信されます。

次に、2 つの方法でリング バッファを導入します。

1. シンプルなリングバッファの使用 - シングルバイトの書き込みと読み取り

1. リングバッファの構造を定義する

バッファ長は、処理する必要があるデータ量のサイズに応じて定義できます。

Head: 現在のキューの先頭、つまり次のデータ読み取りの先頭アドレスは、データのアクセス状況に応じて動的に変更されます。

Tail: 現在のキューの末尾、つまり次のデータが書き込まれるときの最初のアドレスは、データのアクセス状況に応じて動的に変化します。

Length: 現在のバッファに格納されているデータの長さ、つまり、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