常用环形缓冲区
常用环形缓冲区
在处理大量通信或者数据传输的应用中,为了减小丢帧率增强通信的健壮性,充当高速与低速设备之间的桥梁,环形FIFO都非常的合适,这里介绍一种用数组实现环形FIFO的方法。此方法可以记录每一帧收到的数据的桢长,便于取出和分析。
#ifndef __RING_BUFFER_H
#define __RING_BUFFER_H
#include "stdbool.h"
#include "stdint.h"
#include "string.h"
/*是(1)否(0)使用环形缓冲区*/
#define IF_USE_RING_BUFFER 1U
/*数据缓冲区长度*/
#define DATA_BUF_LENGTH 250U
/*环形缓冲区相关结构体*/
typedef struct {
volatile uint8_t head;/*缓冲区头部*/
volatile uint8_t tail;/*缓冲区尾部*/
volatile uint8_t dataLen;/*缓冲区内数据长度*/
volatile uint8_t readWriteMutexFlag;/*读写互斥标志*/
uint8_t aFrameLen[25];/*存储接收帧的长度*/
volatile uint8_t frameNum;/*缓冲区内桢数*/
uint8_t ringBuf[DATA_BUF_LENGTH];/*缓冲区*/
}ringBufType_t;
/*多缓冲*/
typedef struct {
ringBufType_t RingBuf_1;
ringBufType_t RingBuf_2;
}multRingBufType_t;
#ifndef COUNTOF
#define COUNTOF(__BUFFER__) (sizeof(__BUFFER__) / sizeof(*(__BUFFER__)))
#endif
#if IF_USE_RING_BUFFER
/*外部声明*/
extern multRingBufType_t multRingBufDeal;
/*写入数据到环形缓冲区*/
bool WriteDataToRingBuffer(ringBufType_t *pRingBuf, uint8_t *pBuf, uint8_t len);
/*从环形缓冲区读出数据*/
uint8_t ReadDataFromRingBuffer(ringBufType_t *pRingBuf, uint8_t *pBuf, uint8_t len);
#endif/*IF_USE_RING_BUFFER*/
#endif/*__RING_BUFFER_H*/
#include "./UART/ringBuffer.h"
/*定义一个多缓冲结构体*/
multRingBufType_t multRingBufDeal;
/**
* @brief 写入数据到环形缓冲区
* @param pBuf: 待写入数据缓冲区
* len: 待写入数据长度
* @retval 执行状态
*/
bool WriteDataToRingBuffer(ringBufType_t *pRingBuf, uint8_t *pBuf, uint8_t len)
{
if (pRingBuf == NULL) { return false; }
if (pBuf == NULL) { return false; }
/*数据长度不能为 0*/
if (len <= 0) { return false; }
/*写入会导致缓冲区溢出*/
if (len > (COUNTOF(pRingBuf->ringBuf) - pRingBuf->dataLen)) { return false; }
/*再写入会导致桢长存储缓冲区溢出*/
if (pRingBuf->frameNum >= COUNTOF(pRingBuf->aFrameLen)) { return false; }
/*读写互斥*/
if (pRingBuf->readWriteMutexFlag) { return false; }
uint32_t tmp = 0;
pRingBuf->readWriteMutexFlag = true;/*打开互斥标志*/
pRingBuf->aFrameLen[pRingBuf->frameNum] = len;/*存储桢长*/
/*如果不满一圈则直接存储*/
if ((COUNTOF(pRingBuf->ringBuf) - pRingBuf->tail) >= pRingBuf->aFrameLen[pRingBuf->frameNum])
{
memcpy(&(pRingBuf->ringBuf[pRingBuf->tail]), pBuf, pRingBuf->aFrameLen[pRingBuf->frameNum]);
pRingBuf->tail += pRingBuf->aFrameLen[pRingBuf->frameNum];
/*如果满了一圈则回到"头部"*/
if (pRingBuf->tail == COUNTOF(pRingBuf->ringBuf))
{
pRingBuf->tail = 0;
}
}
/*满了一圈则分成两部分存储*/
else
{
memcpy(&(pRingBuf->ringBuf[pRingBuf->tail]), pBuf, COUNTOF(pRingBuf->ringBuf) - pRingBuf->tail);
tmp = COUNTOF(pRingBuf->ringBuf) - pRingBuf->tail;
pRingBuf->tail = 0;
memcpy(&(pRingBuf->ringBuf[pRingBuf->tail]), &pBuf[tmp], pRingBuf->aFrameLen[pRingBuf->frameNum] - tmp);
pRingBuf->tail = pRingBuf->aFrameLen[pRingBuf->frameNum] - tmp;
}
pRingBuf->dataLen += pRingBuf->aFrameLen[pRingBuf->frameNum];/*更新存储数据长度*/
pRingBuf->frameNum++;/*更新帧数*/
pRingBuf->readWriteMutexFlag = false;/*关闭互斥标志*/
return true;
}
/**
* @brief 从环形缓冲区读出数据
* @param pBuf: 存放读出数据缓冲区
* len: 存放读出数据缓冲区长度
* @retval 实际读出数据量
*/
uint8_t ReadDataFromRingBuffer(ringBufType_t *pRingBuf, uint8_t *pBuf, uint8_t len)
{
if (pRingBuf == NULL) { return 0x00; }
if (pBuf == NULL) { return 0x00; }
/*缓冲区过小*/
if (len < pRingBuf->aFrameLen[0]) { return 0x00; }
/*无数据可读*/
if (pRingBuf->dataLen <= 0) { return 0x00; }
/*读写互斥*/
if (pRingBuf->readWriteMutexFlag) { return 0x00; }
uint32_t ret = 0;
uint32_t tmp = 0;
pRingBuf->readWriteMutexFlag = true;/*打开互斥标志*/
pRingBuf->dataLen -= pRingBuf->aFrameLen[0];/*更新存储数据长度*/
ret = pRingBuf->aFrameLen[0];/*获取帧长*/
/*如果不满一圈则直接读取*/
if ((COUNTOF(pRingBuf->ringBuf) - pRingBuf->head) >= pRingBuf->aFrameLen[0])
{
memcpy(pBuf, &(pRingBuf->ringBuf[pRingBuf->head]), pRingBuf->aFrameLen[0]);
pRingBuf->head += pRingBuf->aFrameLen[0];
/*如果满了一圈则回到"尾部"*/
if (pRingBuf->head == COUNTOF(pRingBuf->ringBuf))
{
pRingBuf->head = 0;
}
}
/*满了一圈则分成两部分读取*/
else
{
memcpy(pBuf, &(pRingBuf->ringBuf[pRingBuf->head]), COUNTOF(pRingBuf->ringBuf) - pRingBuf->head);
tmp = COUNTOF(pRingBuf->ringBuf) - pRingBuf->head;
pRingBuf->head = 0;
memcpy(&pBuf[tmp], &(pRingBuf->ringBuf[pRingBuf->head]), pRingBuf->aFrameLen[0] - tmp);
pRingBuf->head = pRingBuf->aFrameLen[0] - tmp;
}
for (uint8_t i = 0; i < (pRingBuf->frameNum - 1); i++)
{
/*让未读缓冲区桢长始终在最前面*/
pRingBuf->aFrameLen[i] = pRingBuf->aFrameLen[i + 1];
}
pRingBuf->aFrameLen[pRingBuf->frameNum - 1] = 0x00;/*帧长缓冲区数据左移后补 0*/
pRingBuf->frameNum--;/*读取后帧数减 1*/
pRingBuf->readWriteMutexFlag = false;/*关闭互斥标志*/
return ret;
}
上述代码已用于工程通信中,其中部分采用C语言自带库函数,因为效率更高,仅个人使用,如需进一步封装请自行完善。
版权声明:本文为wei1598025967原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。