打印
[其他ST产品]

STM32 C语言编写环形存储区

[复制链接]
516|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
梵蒂冈是神uy|  楼主 | 2022-11-30 15:43 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
前言
在产品开发中经常碰到帧数据丢失或接收过来非整帧的情况,为增加代码的可靠性,采用环形存储区的方式将数据先行缓存,然后进行帧判断、解析、执行。

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

使用特权

评论回复
沙发
梵蒂冈是神uy|  楼主 | 2022-11-30 15:44 | 只看该作者
环形存储区C语言代码实现
废话不多说,直接贴出代码。本代码亲测通过,希望能够帮助有需要的同学。如果正式你需要的或者能够帮助你希望点个赞呦。

使用特权

评论回复
板凳
梵蒂冈是神uy|  楼主 | 2022-11-30 15:45 | 只看该作者
RingBuff.c文件实现
#include "RingBuff.h"

/**
* [url=home.php?mod=space&uid=247401]@brief[/url] 环形缓冲区初始化
* @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;
}

使用特权

评论回复
地板
梵蒂冈是神uy|  楼主 | 2022-11-30 15:45 | 只看该作者
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_ */

使用特权

评论回复
5
梵蒂冈是神uy|  楼主 | 2022-11-30 15:46 | 只看该作者
总结
以上就是想要分享的内容,感谢大家阅读交流,不对支持敬请指正。

使用特权

评论回复
6
51xlf| | 2022-11-30 23:40 | 只看该作者
有完整的工程文件吗?

使用特权

评论回复
7
zerorobert| | 2022-12-14 10:03 | 只看该作者
如何创建环形缓存               

使用特权

评论回复
8
pl202| | 2022-12-14 10:58 | 只看该作者
这个数据会出现覆盖的吗?              

使用特权

评论回复
9
mikewalpole| | 2022-12-17 14:26 | 只看该作者
缓冲区其实就是一个存储区域,它是由专门的硬件寄存器所组成的。  

使用特权

评论回复
10
Undshing| | 2022-12-17 16:23 | 只看该作者
可以分享一下工程文件吗?

使用特权

评论回复
11
iyoum| | 2022-12-17 21:40 | 只看该作者
环形存储区就是我们定义或者动态分配的一段连续的数据存储区域。

使用特权

评论回复
12
mollylawrence| | 2022-12-18 11:23 | 只看该作者
调用同一接口如串口时,会出现干涉情况。  

使用特权

评论回复
13
51xlf| | 2022-12-18 12:06 | 只看该作者
这个可以应用其他的单片机上的吗?

使用特权

评论回复
14
mikewalpole| | 2022-12-18 17:03 | 只看该作者
环形缓冲区算法在哪里呢              

使用特权

评论回复
15
lihuami| | 2022-12-18 17:43 | 只看该作者
怎样用c语言实现一个环形缓存区!  

使用特权

评论回复
16
everyrobin| | 2022-12-18 19:50 | 只看该作者
STM32串口开发之环形缓冲区  

使用特权

评论回复
17
pixhw| | 2023-1-14 17:27 | 只看该作者
FIFO机制在嵌入式开发中串口数据收发处理相当方便

使用特权

评论回复
18
51xlf| | 2023-1-19 13:33 | 只看该作者
这个可以shixainFIFO环形存储器吗?

使用特权

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

本版积分规则

41

主题

583

帖子

1

粉丝