嵌入式常用算法:环形缓冲区算法

在嵌入式开发中离不开设备通信,而在通信中稳定性最高的莫过于环形缓冲区算法,当读取速度大于写入速度时,在环形缓冲区的支持下不会丢掉任何一个字节(硬件问题除外)。下面我分享一段由我原创的Ringbuffer代码。

C文件:

/**
  ******************************************************************************
  * @file    cx_ringbuff.c
  * @author  CX
  * @version V1.0.0.2
  * @date    2016-07-13
  * @brief   1.0.0.2 期望帧逻辑优化
		     修改匹配期望帧任务的条件
		     增加匹配期望帧函数
             1.0.0.1 优化耦合性
		     优化读取逻辑
		     增加多缓冲区支持
	     1.0.0.0 主体架构搭建,完成读写环形结构化
  ******************************************************************************
  * @attention
  *
  * 项目   :None
  * 官网   : None
  * 实验室 :None
  *
  ******************************************************************************
  */

#include "cx_ringbuff.h"


/* 除了必须的缓冲区外没有向外部模块公开一个变量,实现高内聚,低耦合 */
RingBuff_Typedef  RingBuffStruct;


/**
* @brief   缓冲区实例化
* @param   rb_ptr 缓冲区结构体地址
* @retval  None
* @notice  None
*/
void RingBuff_New(RingBuff_Typedef* rb_ptr)
{
	rb_ptr->Readpos = rb_ptr->RxBuff;
	rb_ptr->Writepos = rb_ptr->RxBuff;
	rb_ptr->ReadRetStateStruct.Readstate = Fail;
	rb_ptr->ReadRetStateStruct.ptr = NULL;
	rb_ptr->RingbufCount = 0;
	memset(rb_ptr->RxBuff, 0, MaxBuffSize);
}


/**
  * @brief   定位函数
  * @param   rb_ptr 缓冲区结构体地址,addr 当前读写地址
  * @retval  addr+1 or 0 
  * @notice  None
  */
unsigned char* NextDataAddrHandle(RingBuff_Typedef* rb_ptr, unsigned char* addr)
{
	return (addr + 1) == (rb_ptr->RxBuff + MaxBuffSize) ? rb_ptr->RxBuff : (addr + 1);
}


/**
  * @brief   读字节函数
  * @param   rb_ptr 缓冲区结构体地址
  * @retval  data
  * @notice  None
  */
ReadRetState_Typedef* ReadDataFromRingbuff(RingBuff_Typedef* rb_ptr)
{
	if (rb_ptr->RingbufCount > 0)
	{
		rb_ptr->ReadRetStateStruct.ptr = rb_ptr->Readpos;
		rb_ptr->ReadRetStateStruct.Readstate = Success;
		rb_ptr->Readpos = NextDataAddrHandle(rb_ptr, rb_ptr->Readpos);
		rb_ptr->RingbufCount--;
		return &rb_ptr->ReadRetStateStruct;
	}
	rb_ptr->ReadRetStateStruct.Readstate = Fail;
	rb_ptr->ReadRetStateStruct.ptr = NULL;
	return &rb_ptr->ReadRetStateStruct;
}


/**
  * @brief   写字节函数
  * @param   rb_ptr 缓冲区结构体地址,data 写入数据
  * @retval  None
  * @notice  None
  */
void WriteDataToRingbuff(RingBuff_Typedef* rb_ptr, unsigned char data)
{
	*(rb_ptr->Writepos) = data;
	rb_ptr->Writepos = NextDataAddrHandle(rb_ptr,rb_ptr->Writepos);
	rb_ptr->RingbufCount++;
}


/**
  * @brief   读指定包长函数
  * @param   rb_ptr 缓冲区结构体地址,head 包头,length 包长
  * @retval  读取状态及数据包地址
  * @notice  length为整个数据包长即头置尾
*/
ReadRetState_Typedef* ReadEfectiveFrameFixLength(RingBuff_Typedef* rb_ptr, unsigned char head, unsigned char length)
{
	unsigned char count = rb_ptr->RingbufCount;              //标记触发前有效数据大小
	if (count < length)
	{
		rb_ptr->ReadRetStateStruct.Readstate = Fail;
		rb_ptr->ReadRetStateStruct.ptr = NULL;
		return &rb_ptr->ReadRetStateStruct;
	}
	while (count >= length)
	{
		rb_ptr->ReadRetStateStruct = *ReadDataFromRingbuff(rb_ptr);
		count--;
		if (rb_ptr->ReadRetStateStruct.Readstate == Success && *rb_ptr->ReadRetStateStruct.ptr == head)
		{
			return &rb_ptr->ReadRetStateStruct;
		}
	}
	rb_ptr->ReadRetStateStruct.Readstate = Fail;
	rb_ptr->ReadRetStateStruct.ptr = NULL;
	return &rb_ptr->ReadRetStateStruct;
}


/**
  * @brief   读期望帧
  * @param   rb_ptr 缓冲区结构体地址,str 期望帧
  * @retval  读取状态
  * @notice  None
*/
ReadRetState_Enum ReadEfectiveFrame(RingBuff_Typedef* rb_ptr, const char* str)
{
	unsigned char count = rb_ptr->RingbufCount;                 //标记触发前有效数据大小                
	unsigned char length = strlen(str);
	unsigned char i = 0;
	if (count < length)
	{
		return Fail;
	}
	while (count >= length)
	{
		rb_ptr->ReadRetStateStruct = *ReadDataFromRingbuff(rb_ptr);
		count--;
		if (rb_ptr->ReadRetStateStruct.Readstate == Success && *rb_ptr->ReadRetStateStruct.ptr == *(str + i))
		{
			count++;
			i++;
		}
		else
		{
			i = 0;
		}
		if (i == length)
		{
			return Success;
		}
	}
	return Fail;
}


/**
  * @brief   匹配期望帧
  * @param   rb_ptr 缓冲区结构体地址,str 期望帧所在注册表地址, ExpectFrameCount 期望帧注册表的个数
  * @retval  读取状态
  * @notice  None
*/
ReadRetState_Typedef* MatchExpectFrame(RingBuff_Typedef* rb_ptr, const char** str, unsigned char ExpectFrameCount)
{
	unsigned char Retcount = rb_ptr->RingbufCount;              
	unsigned char* RetPos = rb_ptr->Readpos;

	unsigned char i = 0;
	for (i = 0; i < ExpectFrameCount; i++)
	{
		if (ReadEfectiveFrame(rb_ptr, *(str + i)) == Success)
		{
			rb_ptr->ReadRetStateStruct.pos = i;
			rb_ptr->ReadRetStateStruct.Readstate = Success;
			return &rb_ptr->ReadRetStateStruct;
		}
		else
		{
			rb_ptr->RingbufCount = Retcount;
			rb_ptr->Readpos = RetPos;
		}
	}
	rb_ptr->ReadRetStateStruct.Readstate = Fail;
	return &rb_ptr->ReadRetStateStruct;
}


/******************** (C)COPYRIGHT(2016) YFTC  END OF FILE **********************/
H文件

#ifndef __CX_RINGBUFF_H
#define __CX_RINGBUFF_H


#include "stdlib.h"
#include "string.h"


#define         MaxBuffSize        256        //缓冲区大小可任意设置,但最好为2^X


typedef enum
{
	Success = 1,
	Fail = !Success,
}ReadRetState_Enum;


typedef struct
{
	ReadRetState_Enum Readstate;                //读状态
	unsigned char* ptr;                         //读取字节地址
	unsigned char  pos;                         //期望帧在注册表中位置
}ReadRetState_Typedef;



typedef struct
{
	unsigned char* Writepos;                    //写入地址
	unsigned char* Readpos;                     //读取地址
	unsigned char RingbufCount;                 //有效未读数据大小
	ReadRetState_Typedef ReadRetStateStruct;    //读缓冲相关
	unsigned char RxBuff[MaxBuffSize];          //数据缓存区
}RingBuff_Typedef;


void RingBuff_New(RingBuff_Typedef* rb_ptr);
unsigned char* NextDataAddrHandle(RingBuff_Typedef* rb_ptr,unsigned char* addr);
ReadRetState_Typedef* ReadDataFromRingbuff(RingBuff_Typedef* rb_ptr);
void WriteDataToRingbuff(RingBuff_Typedef* rb_ptr,unsigned char data);
ReadRetState_Typedef* ReadEfectiveFrameFixLength(RingBuff_Typedef* rb_ptr, unsigned char head, unsigned char length);
ReadRetState_Enum ReadEfectiveFrame(RingBuff_Typedef* rb_ptr, const char* str);
ReadRetState_Typedef* MatchExpectFrame(RingBuff_Typedef* rb_ptr, const char** str, unsigned char ExpectFrameCount);


#endif

以上就是我所编写的Ringbuffer源码。

从.H文件中可看到Ringbuff的数据结构,当中有读写地址以及有效未读数据大小,以及读状态等。

向外部提供的API接口就是常规的读数据包,读期望帧以及匹配期望帧,整段代码可用于普通的通信数据帧读取,也可以在单片机中用于shell组件的实现。还是希望广大网 友能对我的代码进行功能补充,BUG修复等。

        

使用过程中出现任何BUG请联系我本人QQ:951253606,说明bug现象以及重现过程。

寻求MCU产品开发请联系我本人QQ:951253606。

感谢,感恩!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值