打印
[CW32F030系列]

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

[复制链接]
441|30
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
plsbackup|  楼主 | 2024-11-27 22:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
C文件:

[plain]  view plain  copy
/**  
  ******************************************************************************  
  * @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  

使用特权

评论回复
沙发
tpgf| | 2024-12-2 15:42 | 只看该作者
在嵌入式开发中,环形缓冲区常用于设备通信,以确保数据在读取速度大于写入速度时不会丢失任何字节

使用特权

评论回复
板凳
pentruman| | 2024-12-2 21:29 | 只看该作者
环形缓冲区(Ring Buffer)是一种固定大小的数据结构,适用于嵌入式系统中的缓冲管理,特别是在处理流数据时。

使用特权

评论回复
地板
mickit| | 2024-12-2 22:28 | 只看该作者
环形缓冲区的实现可以通过数组或链表来完成。数组实现方式简单且高效,适用于已知缓冲区大小的场景。链表实现方式则更加灵活,适用于需要动态扩展缓冲区大小的场景

使用特权

评论回复
5
heimaojingzhang| | 2024-12-3 09:40 | 只看该作者
环形缓冲算法是一种用于管理固定大小循环数组的数据结构,它允许数据以先进先出(FIFO)的方式存储和访问

使用特权

评论回复
6
keaibukelian| | 2024-12-3 13:43 | 只看该作者
环形缓冲区通常由一个固定大小的数组和一个写指针(tail)组成,读指针(head)指向缓冲区中的第一个数据元素;另一个是写指针(tail),指向下一个可写入数据的位置

使用特权

评论回复
7
paotangsan| | 2024-12-3 18:20 | 只看该作者
环形缓冲区可以高效地利用内存空间,避免了动态内存分配带来的开销和碎片问题

使用特权

评论回复
8
renzheshengui| | 2024-12-3 20:03 | 只看该作者
在实际应用中,环形缓冲区被广泛用于需要高效数据传输的场景,如实时数据处理、网络通信等

使用特权

评论回复
9
wowu| | 2024-12-3 21:59 | 只看该作者
环形缓冲区还可以与生产者-消费者模型结合使用,实现多线程或多任务之间的数据同步和通信

使用特权

评论回复
10
loutin| | 2024-12-6 19:36 | 只看该作者
环形缓冲区的读写操作可以通过简单的索引计算来实现,无需复杂的指针操作。

使用特权

评论回复
11
adolphcocker| | 2024-12-6 22:41 | 只看该作者
由于环形缓冲区的大小是固定的,因此可以预先分配一块连续的内存空间,避免了动态内存分配带来的开销。

使用特权

评论回复
12
mickit| | 2024-12-7 01:43 | 只看该作者
#define BUFFER_SIZE 1024

typedef struct {
    int buffer[BUFFER_SIZE];
    int head;
    int tail;
    int count;
} RingBuffer;

void RingBuffer_Init(RingBuffer *rb) {
    rb->head = 0;
    rb->tail = 0;
    rb->count = 0;
}

int RingBuffer_IsFull(RingBuffer *rb) {
    return rb->count == BUFFER_SIZE;
}

int RingBuffer_IsEmpty(RingBuffer *rb) {
    return rb->count == 0;
}

int RingBuffer_Put(RingBuffer *rb, int data) {
    if (RingBuffer_IsFull(rb)) {
        return -1; // Buffer is full
    }
    rb->buffer[rb->head] = data;
    rb->head = (rb->head + 1) % BUFFER_SIZE;
    rb->count++;
    return 0;
}

int RingBuffer_Get(RingBuffer *rb, int *data) {
    if (RingBuffer_IsEmpty(rb)) {
        return -1; // Buffer is empty
    }
    *data = rb->buffer[rb->tail];
    rb->tail = (rb->tail + 1) % BUFFER_SIZE;
    rb->count--;
    return 0;
}

使用特权

评论回复
13
ingramward| | 2024-12-7 04:46 | 只看该作者
通常用于在生成数据和消费数据之间提供平滑的数据流,特别是在数据生成速率和消费速率不一致的情况下。

使用特权

评论回复
14
sesefadou| | 2024-12-7 07:48 | 只看该作者
头指针(Head):指向下一个数据将要写入的位置。
尾指针(Tail):指向下一个数据将要被读取的位置。
空状态:当头指针和尾指针指向同一个位置时,缓冲区为空。
满状态:当头指针紧随尾指针时(考虑缓冲区大小),缓冲区为满。

使用特权

评论回复
15
jtracy3| | 2024-12-9 11:32 | 只看该作者
环形缓冲区是一种先进先出(FIFO)的存储空间,其特点是首尾相连形成了闭环。这种结构允许数据在达到缓冲区末尾时自动回绕到起始位置,从而实现数据的循环存储和管理。

使用特权

评论回复
16
rosemoore| | 2024-12-9 14:52 | 只看该作者
环形缓冲区是嵌入式系统中一个非常实用且高效的数据结构,适用于各种需要缓冲区的场景,如信号处理、通信协议处理等。

使用特权

评论回复
17
AdaMaYun| | 2024-12-10 08:17 | 只看该作者
环形缓冲的优势是什么?

使用特权

评论回复
18
ingramward| | 2024-12-10 16:58 | 只看该作者
环形缓冲区的特点是其两端相连,形成一个闭环,当缓冲区填满后,新的数据会覆盖旧的数据。这种数据结构非常适合于需要缓存连续数据流的场景,如音频处理、网络通信和实时数据采集等。

使用特权

评论回复
19
deliahouse887| | 2024-12-10 17:54 | 只看该作者
环形缓冲区可以存储一定数量的数据,并在数据满后通过覆盖最早的数据来继续存储新数据,实现“先进先出”(FIFO)的数据管理方式。

使用特权

评论回复
20
sesefadou| | 2024-12-10 18:23 | 只看该作者
环形缓冲的实现相对简单,主要涉及到读指针和写指针的操作。与其他复杂的缓冲区管理方式相比,它的代码量较少,易于理解和维护。在嵌入式软件开发中,简单的代码结构可以降低系统的复杂度,减少出错的可能性。

使用特权

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

本版积分规则

26

主题

3132

帖子

0

粉丝