在處理大量通信或者數據傳輸的應用中,為了減小丟幀率增強通信的健壯性,充當高速與低速設備之間的橋梁,環形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語言自帶庫函數,因為效率更高,僅個人使用,如需進一步封裝請自行完善。