前言
嵌入式開發過程中,各個模組之間,各個裝置之間進行互動時,都會存在資料的輸入輸出,由於處理的方式不同,資料不會立即同步處理,因此通常在設計時都會設計緩衝區進行資料的處理,方式資料丟失等問題;一個專案中存在不同模組都需要緩衝區的設計,設計策略基本都一樣,不同的是資料結構,在 C 語言中可以編寫緩衝區功能函式,入參型別通常為無型別指標,適配所有需要儲存的不同資料結構,但是這種方式必須先知道不同資料結構體的大小,在寫入和讀取時按一個個位元組操作。
下面介紹的是使用巨集定義函式實現該方式,按照資料結構的形式賦值速度快,效率高,但是需要一定記憶體(巨集定義),以空間換時間。
實現方式
巨集定義函式實現資料佇列的功能,適用不同資料結構,類似於 C++ 的模板方式,相同的實現邏輯,不同的資料結構。
點選檢視程式碼
/**
* @brief 快取區操作資訊結構體定義
*/
typedef struct{
uint8_t state; /*!< 控制狀態 */
uint8_t end; /*!< 迴圈佇列尾哨兵 */
uint8_t head; /*!< 迴圈佇列首哨兵 */
uint8_t num; /*!< 迴圈佇列中能儲存的最多組數 */
} QueueCtrl_t;
#define QUEUE_ENABLE_COVER (0X80)
#define QUEUE_EXIT_DATA (0X01)
#define QUEUE_DATA_FULL (0X02)
#define QUEUE_DATA_LOCK (0X04)
/**
* @brief 佇列控制初始化
*
* @param[in,out] ctrl - 佇列控制控制代碼
* @param[in] num - 佇列數目大小
* @param[in] cover - 0,不覆蓋; 1,佇列滿了覆蓋頂端資料
*/
#define QUEUE_INIT(ctrl, maxNum, cover) ({\
ctrl.end = 0;\
ctrl.head = 0;\
ctrl.num = (maxNum);\
ctrl.state = 0x00;\
ctrl.state |= ((cover) ? QUEUE_ENABLE_COVER : 0);\
})
/**
* @brief 在佇列末尾加入新的資料
*
* @param[in,out] dstLists - 佇列快取區
* @param[in] src - 新的資料
* @param[in,out] ctrl - 佇列控制控制代碼
* @retval 返回的值含義如下
* @arg 0: 寫入成功
* @arg -1: 寫入失敗
*/
#define QUEUE_PUSH_DATA(dstLists, src, ctrl) ({ \
int ret = 0;\
\
if (QUEUE_DATA_LOCK != ((ctrl.state) & QUEUE_DATA_LOCK)) \
{\
dstLists[(ctrl.end)++] = src;\
(ctrl.state) |= QUEUE_EXIT_DATA; \
\
if ((ctrl.end) >= (ctrl.num))\
{\
(ctrl.end) = 0;\
}\
\
if (((ctrl.state) & QUEUE_DATA_FULL) == QUEUE_DATA_FULL)\
{\
(ctrl.head) = (ctrl.end);\
}\
else if ((ctrl.end) == (ctrl.head))\
{\
(ctrl.state) |= QUEUE_DATA_FULL;\
\
if ((ctrl.state & QUEUE_ENABLE_COVER) != QUEUE_ENABLE_COVER) \
{\
(ctrl.state) |= QUEUE_DATA_LOCK;\
}\
}\
\
ret = 0;\
}\
else\
{\
ret = -1;\
}\
\
ret;\
})
/**
* @brief 在佇列頂端讀取資料
*
* @param[in,out] dstLists - 佇列快取區
* @param[out] dst - 讀取的資料
* @param[in,out] ctrl - 佇列控制控制代碼
* @retval 返回的值含義如下
* @arg 0: 讀取成功
* @arg -1: 讀取失敗
*/
#define QUEUE_POP_DATA(dstLists, dst, ctrl) ({\
\
int ret = -1;\
\
if (((ctrl.state) & QUEUE_EXIT_DATA) == QUEUE_EXIT_DATA)\
{\
dst = dstLists[ctrl.head++];\
\
if ((ctrl.head) >= (ctrl.num))\
{\
ctrl.head = 0;\
}\
\
if ((ctrl.head) == (ctrl.end))\
{\
if (((ctrl.state) & QUEUE_DATA_FULL) != QUEUE_DATA_FULL)\
{\
(ctrl.state) &= ~QUEUE_EXIT_DATA;\
}\
}\
\
ret = 0;\
}\
\
(ctrl.state) &= ~QUEUE_DATA_LOCK;\
(ctrl.state) &= ~QUEUE_DATA_FULL;\
\
ret;\
})