前言
嵌入式開發程序中,各個模塊之間,各個設備之間進行互動時,都會存在資料的輸入輸出,由于處理的方式不同,資料不會立即同步處理,因此通常在設計時都會設計緩沖區進行資料的處理,方式資料丟失等問題;
一個專案中存在不同模塊都需要緩沖區的設計,設計策略基本都一樣,不同的是資料結構,在 C 語言中可以撰寫緩沖區功能函式,入參型別通常為無型別指標,適配所有需要儲存的不同資料結構,但是這種方式必須先知道不同資料結構體的大小,在寫入和讀取時按一個個位元組操作,
下面介紹的是使用宏定義函式實作該方式,按照資料結構的形式賦值速度快,效率高,但是需要一定記憶體(宏定義替換),以空間換時間,
背景
之前我寫的資料佇列功能函式,有兩種實作方式,
固定型別指標入參
佇列的入參型別為固定型別指標,如: QueuePushData(TestInfo_t *pQueueBuf, TestInfo_t *pSrcData, QueueCtrl *pCtrl),
優點是資料寫入/讀取效率高(型別的大小記憶體拷貝),缺點是函式功能不能復用,
無型別指標入參
佇列的入參型別為無型別指標,如: QueuePushData(void *pQueueBuf, void *pSrcData, QueueCtrl *pCtrl),
優點是函式功能可復用(無型別編譯不報錯),缺點是資料寫入/讀取效率和固定型別比較低(通過單位元組或 memcpy() 等方式拷貝),且佇列控制中需要增加佇列資料的占用大小
實作方式
為了達到資料寫入/讀取效率高和函式功能可復用兩種優點,通過宏定義函式的方式實作(相對函式來說,占用代碼空間,記憶體足夠的情況下目的是以空間換時間),
宏定義函式實作資料佇列的功能,適用不同資料結構,類似于 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;\
})
Demo測驗代碼
正在加載Demo編譯器插件,可能較慢,稍等
<iframe src="https://www.cnblogs.com//jsrun.net/iWVKp/embedded/quick/dark" width="100%" height="1000" frameborder="0" allowfullscreen="allowfullscreen"></iframe>
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/285524.html
標籤:C
上一篇:Linux C 信號
