STM32 C语言编写环形存储区

本文介绍了一种可靠的环形存储区实现方案,通过使用环形存储区来避免帧数据丢失或接收非整帧的问题。提供了完整的C语言代码实现,并详细解释了各个函数的功能。

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

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

在产品开发中经常碰到帧数据丢失或接收过来非整帧的情况,为增加代码的可靠性,采用环形存储区的方式将数据先行缓存,然后进行帧判断、解析、执行。

一、环形存储区简介

简言之,环形存储区就是我们定义或者动态分配的一段连续的数据存储区域。其工作过程是通过头和尾两个索引在这段连续的存储区域进行数据的读出和写入,就好像将这一块儿连续的数据存储区行程了一个闭环,这就是环形的含义。
当数据写入时尾索引增加,当数据读取时头索引增加。具有FIFO的特性。
由以上可知,要将一个连续存储区域作为环形存储区需要四个元素:连续存储区域首地址、连续存储区域大小、头索引及尾索引。

二、环形存储区C语言代码实现

废话不多说,直接贴出代码。本代码亲测通过,希望能够帮助有需要的同学。如果正式你需要的或者能够帮助你希望点个赞呦。

1、RingBuff.c文件实现

#include "RingBuff.h"

/**
 * @brief 环形缓冲区初始化
 * @param[in] pRingBuff 环形缓冲区结构体地址
 * @param[in] buf_size  环形缓存区大小(字节数)
 * @return[out]  
 */
void RingBuff_Init(RingBuff_t *pRingBuff, unsigned int buf_size)
{
	RingBuff_t 		*ringbuff 	= NULL;
	unsigned int 	size 		= 0;

	ringbuff = pRingBuff;
	size	 = buf_size;
	
	ringbuff->buffer = (uint8_t*)calloc(size, sizeof(uint8_t));
	ringbuff->size = size;
	ringbuff->head = 0;
	ringbuff->tail = 0;	
}


/**
 * @brief 判断环形缓冲区是否为空
 * @param[in] pRingBuff 环形缓冲区结构体地址
 * @return[out]  	RING_TRUE		空
 * 					RING_FALSE		非空
 */
static unsigned char RingBuff_isEmpty(RingBuff_t *pRingBuff) 
{
	RingBuff_t *ringbuff = NULL;

	ringbuff = pRingBuff;

	if(ringbuff->head == ringbuff->tail)
	{
		return RING_TRUE;
	}
	return RING_FALSE;
}


/**
 * @brief 判断环形缓冲区是否为满
 * @param[in] pRingBuff 环形缓冲区结构体地址
 * @return[out]  	RING_TRUE		满
 * 					RING_FALSE		非满
 */
static unsigned char RingBuff_isFull(RingBuff_t *pRingBuff)
{
	RingBuff_t *ringbuff = NULL;

	ringbuff = pRingBuff;

	if((ringbuff->tail + 1) % ringbuff->size == ringbuff->head)
	{
		return RING_TRUE;
	}
	return RING_FALSE;
}


/**
 * @brief 从环形缓冲区头部读出一个字节
 * @param[in] pRingBuff 环形缓冲区结构体地址
 * @param[in] pData 	读出缓冲区字节所将要存储的地址
 * @return[out]  RING_OK	读出成功,
 * 				 RING_ERR	读出失败
 */
static unsigned char RingBuff_ReadOneByte(RingBuff_t *pRingBuff, unsigned char *pData)
{
	RingBuff_t 		*ringbuff = NULL;
	unsigned char 	*temp = NULL;

	ringbuff = pRingBuff;
	temp	 = pData;

	//判空
	if(RING_TRUE == RingBuff_isEmpty(ringbuff))
	{
		SYSlog("ring buffer is empty!\r\n");
		return RING_ERR;
	}

	*temp = ringbuff->buffer[ringbuff->head];
	ringbuff->head = (ringbuff->head + 1) % ringbuff->size;
	return RING_OK;
}


/**
 * @brief 向环形缓冲区的尾部写入一个字节
 * @param[in] pRingBuff 环形缓冲区结构体地址
 * @param[in] pData 	将要写入缓冲区的字节的地址
 * @return[out]  RING_OK	写入成功,
 * 				 RING_ERR	写入失败
 */
static unsigned char RingBuff_WriteOneByte(RingBuff_t *pRingBuff, unsigned char *pData)
{
	RingBuff_t 		*ringbuff = NULL;
	unsigned char 	*temp = NULL;

	ringbuff = pRingBuff;
	temp	 = pData;

	//判满
	if(RING_TRUE == RingBuff_isFull(ringbuff))
	{
		SYSlog("ring buffer is full!\r\n");
		return RING_ERR;
	}

	ringbuff->buffer[ringbuff->tail] = *temp;
	ringbuff->tail = (ringbuff->tail + 1) % ringbuff->size;
	return RING_OK;
}


/**
 * @brief 从环形缓冲区读出多个字节
 * @param[in] pRingBuff 环形缓冲区结构体地址
 * @param[in] pData 	读出缓冲区多字节将要存储的首地址
 * @param[in] Size		读出环形缓冲区的字节数
 * @return[out]  RING_OK	读出成功,
 * 				 RING_ERR	读出失败
 */
unsigned char RingBuff_ReadNByte(RingBuff_t *pRingBuff, unsigned char *pData, int Size)
{
	RingBuff_t 		*ringbuff = NULL;
	unsigned char 	*temp = NULL;
	int				size = 0;

	ringbuff = pRingBuff;
	temp	 = pData;
	size	 = Size;

	for(int i = 0; i < size; i++)
	{
		if(RingBuff_ReadOneByte(ringbuff, temp + i) == RING_ERR)
		{
			return RING_ERR;
		}
	}
	return RING_OK;
}

//
/**
 * @brief 向环形缓冲区写入多个字节
 * @param[in] pRingBuff 环形缓冲区结构体地址
 * @param[in] pData 	将要写入缓冲区多字节的首地址
 * @param[in] Size		写入环形缓冲区的字节数
 * @return[out]  RING_OK	写入成功,
 * 				 RING_ERR	写入失败
 */
unsigned char RingBuff_WriteNByte(RingBuff_t *pRingBuff, unsigned char *pData, int Size)
{
	RingBuff_t 		*ringbuff = NULL;
	unsigned char 	*temp = NULL;
	int				size = 0;

	ringbuff = pRingBuff;
	temp	 = pData;
	size	 = Size;

	for(int i = 0; i < size; i++)
	{
		if(RingBuff_WriteOneByte(ringbuff, temp + i) == RING_ERR)
		{
			return RING_ERR;
		}
	}
	return RING_OK;
}


/**
 * @brief 获取当前环形缓冲区中有效数据的长度
 * @param[in] pRingBuff 环形缓冲区结构体地址
 * @return[out]  	有效数据长度
 */
int RingBuff_GetValidLen(RingBuff_t *pRingBuff)
{
	RingBuff_t 	*ringbuff 	= NULL;
	int 		temp 		= 0;
	ringbuff = pRingBuff;

	if(ringbuff->tail >= ringbuff->head)
	{
		temp = ringbuff->tail - ringbuff->head;
	}
	else
	{
		temp =  ringbuff->tail + ringbuff->size - ringbuff->head;
	}

	return temp;
}


/**
 * @brief 获取当前环形缓冲区中空闲数据的长度
 * @param[in] pRingBuff 环形缓冲区结构体地址
 * @return[out]  	空闲数据长度
 */
int RingBuff_GetIdleLen(RingBuff_t *pRingBuff)
{
	RingBuff_t 	*ringbuff 	= NULL;
    int 		temp 		= 0;
	ringbuff = pRingBuff;

	if(ringbuff->tail >= ringbuff->head)
	{
		temp = ringbuff->size - ringbuff->tail + ringbuff->head;
	}
	else
	{
		temp = ringbuff->head - ringbuff->tail;
	}
	
	return temp;
}


/**
 * @brief 获取当前头部数据
 * @param[in] pRingBuff 环形缓冲区结构体地址
 * @return[out]  	当前头部数据
 */
unsigned char RingBuff_GetHeadItem(RingBuff_t *pRingBuff)
{
	unsigned char temp = 0;
	RingBuff_t 	*ringbuff = NULL;

	ringbuff = pRingBuff;
	
	temp = ringbuff->buffer[ringbuff->head];

	return temp;
}


/**
 * @brief 获取指定下标数据
 * @param[in] pRingBuff 环形缓冲区结构体地址
 * @param[in] index     环形缓冲区下标(环形缓冲区首地址的偏移量)
 * @return[out]  	环形缓冲区下标指定的数据
 */
unsigned char RingBuff_GetIndexItem(RingBuff_t *pRingBuff, int index)
{
	unsigned char res = 0;
	RingBuff_t 	*ringbuff = NULL;
	int 		temp	  = 0;

	ringbuff = pRingBuff;
	temp	 = index;

	res = ringbuff->buffer[temp % ringbuff->size];

	return res;
}


/**
 * @brief 释放环形缓冲区
 * @param[in] pRingBuff 环形缓冲区结构体地址
 * @return[out]  	
 */
void RingBuff_Release(RingBuff_t *pRingBuff)
{
	RingBuff_t 	*ringbuff = NULL;

	ringbuff = pRingBuff;

	free(ringbuff->buffer);
	ringbuff->size = 0;
	ringbuff->head = 0;
	ringbuff->tail = 0;
}

2、RingBuff.h文件实现

#ifndef __RingBuff_H_
#define __RingBuff_H_

#include    <stdlib.h>
#include    <string.h>
#include    "main.h"
#include    "usart.h"


enum
{
	RING_FALSE,
	RING_TRUE,
};

enum
{
	RING_ERR,
	RING_OK,
};

typedef struct ringBuff{
    unsigned char *buffer; //数据缓冲区指针
    unsigned int size;     //队列的大小 
    unsigned int head;     //队列的头部,读取之后偏移            
    unsigned int tail;     //队列的尾部,写入之后偏移    
}RingBuff_t;

void RingBuff_Init(RingBuff_t *pRingBuff, unsigned int buf_size);
unsigned char RingBuff_ReadNByte(RingBuff_t *pRingBuff, unsigned char *pData, int Size);
unsigned char RingBuff_WriteNByte(RingBuff_t *pRingBuff, unsigned char *pData, int Size);
int RingBuff_GetValidLen(RingBuff_t *pRingBuff);
int RingBuff_GetIdleLen(RingBuff_t *pRingBuff);
unsigned char RingBuff_GetHeadItem(RingBuff_t *pRingBuff);
unsigned char RingBuff_GetIndexItem(RingBuff_t *pRingBuff, int index);
void RingBuff_Release(RingBuff_t *pRingBuff);
#endif /* __RingBuff_H_ */

总结

以上就是想要分享的内容,感谢大家阅读交流,不对之处敬请指正。
在此感谢如下原文:
嵌入式C语言_环形存储(Ring/Circular Buffer)
c语言环形存储,环形缓存区bufferC语言实现

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值