打印
[应用方案]

环形缓冲区算法

[复制链接]
37|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
minzisc|  楼主 | 2024-11-15 13:04 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在嵌入式开发中离不开设备通信,而在通信中稳定性最高的莫过于环形缓冲区算法,当读取速度大于写入速度时,在环形缓冲区的支持下不会丢掉任何一个字节(硬件问题除外)。下面我分享一段由我原创的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文件
[html]  view plain  copy
#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的数据结构,当中有读写地址以及有效未读数据大小,以及读状态等。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

57

主题

5391

帖子

4

粉丝