嵌入式常用算法:环形缓冲
C文件:view plaincopy
/**
******************************************************************************
* @file cx_ringbuff.c
* @authorCX
* @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_TypedefRingBuffStruct;
/**
* @brief 缓冲区实例化
* @param rb_ptr 缓冲区结构体地址
* @retvalNone
* @noticeNone
*/
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 当前读写地址
* @retvaladdr+1 or 0
* @noticeNone
*/
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 缓冲区结构体地址
* @retvaldata
* @noticeNone
*/
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 写入数据
* @retvalNone
* @noticeNone
*/
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读取状态及数据包地址
* @noticelength为整个数据包长即头置尾
*/
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读取状态
* @noticeNone
*/
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读取状态
* @noticeNone
*/
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) YFTCEND OF FILE **********************/
H文件
view plaincopy
#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 charpos; //期望帧在注册表中位置
}ReadRetState_Typedef;
typedef struct
{
unsigned char* Writepos; //写入地址
unsigned char* Readpos; //读取地址
unsigned char RingbufCount; //有效未读数据大小
ReadRetState_Typedef ReadRetStateStruct; //读缓冲相关
unsigned char RxBuff; //数据缓存区
}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
在嵌入式开发中,环形缓冲区常用于设备通信,以确保数据在读取速度大于写入速度时不会丢失任何字节 环形缓冲区(Ring Buffer)是一种固定大小的数据结构,适用于嵌入式系统中的缓冲管理,特别是在处理流数据时。 环形缓冲区的实现可以通过数组或链表来完成。数组实现方式简单且高效,适用于已知缓冲区大小的场景。链表实现方式则更加灵活,适用于需要动态扩展缓冲区大小的场景 环形缓冲算法是一种用于管理固定大小循环数组的数据结构,它允许数据以先进先出(FIFO)的方式存储和访问
环形缓冲区通常由一个固定大小的数组和一个写指针(tail)组成,读指针(head)指向缓冲区中的第一个数据元素;另一个是写指针(tail),指向下一个可写入数据的位置
环形缓冲区可以高效地利用内存空间,避免了动态内存分配带来的开销和碎片问题
在实际应用中,环形缓冲区被广泛用于需要高效数据传输的场景,如实时数据处理、网络通信等
环形缓冲区还可以与生产者-消费者模型结合使用,实现多线程或多任务之间的数据同步和通信
环形缓冲区的读写操作可以通过简单的索引计算来实现,无需复杂的指针操作。 由于环形缓冲区的大小是固定的,因此可以预先分配一块连续的内存空间,避免了动态内存分配带来的开销。 #define BUFFER_SIZE 1024
typedef struct {
int buffer;
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 = 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 + 1) % BUFFER_SIZE;
rb->count--;
return 0;
}
通常用于在生成数据和消费数据之间提供平滑的数据流,特别是在数据生成速率和消费速率不一致的情况下。 头指针(Head):指向下一个数据将要写入的位置。
尾指针(Tail):指向下一个数据将要被读取的位置。
空状态:当头指针和尾指针指向同一个位置时,缓冲区为空。
满状态:当头指针紧随尾指针时(考虑缓冲区大小),缓冲区为满。 环形缓冲区是一种先进先出(FIFO)的存储空间,其特点是首尾相连形成了闭环。这种结构允许数据在达到缓冲区末尾时自动回绕到起始位置,从而实现数据的循环存储和管理。 环形缓冲区是嵌入式系统中一个非常实用且高效的数据结构,适用于各种需要缓冲区的场景,如信号处理、通信协议处理等。 环形缓冲的优势是什么? 环形缓冲区的特点是其两端相连,形成一个闭环,当缓冲区填满后,新的数据会覆盖旧的数据。这种数据结构非常适合于需要缓存连续数据流的场景,如音频处理、网络通信和实时数据采集等。 环形缓冲区可以存储一定数量的数据,并在数据满后通过覆盖最早的数据来继续存储新数据,实现“先进先出”(FIFO)的数据管理方式。 环形缓冲的实现相对简单,主要涉及到读指针和写指针的操作。与其他复杂的缓冲区管理方式相比,它的代码量较少,易于理解和维护。在嵌入式软件开发中,简单的代码结构可以降低系统的复杂度,减少出错的可能性。
页:
[1]
2