RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

分享一個嵌入式通用FIFO環(huán)形緩沖區(qū)實現(xiàn)庫

strongerHuang ? 來源:Mculover666 ? 2024-10-23 16:20 ? 次閱讀

轉(zhuǎn)自| Mculover666

今天給大家分享一個開源的嵌入式通用FIFO環(huán)形緩沖區(qū)實現(xiàn)庫:ringbuff 地址:

https://github.com/MaJerle/ringbuff

1. 關(guān)于ringbuff

開源項目ringbuff ,是一款通用FIFO環(huán)形緩沖區(qū)實現(xiàn)的開源庫,作者MaJerle,遵循 MIT 開源許可協(xié)議。

目前 ringbuff 的特點有:

使用C99語法編寫,并且沒有平臺相關(guān)代碼;

沒有動態(tài)內(nèi)存分配;

使用更優(yōu)的內(nèi)存復制而不是循環(huán)從內(nèi)存讀取數(shù)據(jù)/向內(nèi)存寫入數(shù)據(jù);

2. 移植ringbuff

2.1. 移植思路

在移植過程中主要參考兩個資料:項目的readme文檔和demo工程。

對于這些開源項目,其實移植起來也就兩步:

① 添加源碼到裸機工程中;

② 實現(xiàn)需要的接口即可;

2.2. 準備裸機工程

本文中我使用的是小熊派IoT開發(fā)套件,主控芯片STM32L431RCT6:

c81da2cc-9074-11ef-a511-92fbcf53809c.png

移植之前需要準備一份裸機工程,我使用STM32CubeMX生成,需要初始化以下配置:

配置一個串口,中斷方式接收數(shù)據(jù),查詢方式發(fā)送數(shù)據(jù);

printf重定向;

2.3. 添加ringbuff 到工程中

① 復制 ringbuff 源碼到工程中:

c85233c0-9074-11ef-a511-92fbcf53809c.png

② 在keil中添加 ringbuff 組件的源碼文件:

c86925c6-9074-11ef-a511-92fbcf53809c.png

③ 添加 ringbuff 的頭文件路徑:

c878e1e6-9074-11ef-a511-92fbcf53809c.png

2.4. 配置ringbuff

ringbuff中默認volatile關(guān)鍵詞沒有定義,需要手動配置一下,在ringbuff.h中:

c89419e8-9074-11ef-a511-92fbcf53809c.png

至此,ringbuff移植修改完成,可以愉快的使用ringbuff啦~

3. 使用ringbuff

3.1. 為什么使用ringbuff

緩沖區(qū)一般用于解決設(shè)備接收數(shù)據(jù)的速度和設(shè)備處理速度不匹配的情況下,防止丟包,通俗的來說就是:收到數(shù)據(jù)先存進緩沖區(qū),等到CPU來處理的時候一次性取出處理。

緩沖區(qū)有兩種形式,一種是數(shù)組,一種就是本文所介紹的環(huán)形緩沖區(qū)ringbuff。

相較于數(shù)組,環(huán)形緩沖區(qū)對整段內(nèi)存的利用達到最大,并且使用非常方便,如下:

① 寫入的時候不用手動維護下標,直接寫入即可(由緩沖區(qū)的實現(xiàn)維護);

② 讀取的時候不用判斷從哪里讀,直接讀取即可(有緩沖區(qū)的實現(xiàn)維護)

本文設(shè)計的一個簡單的不定長串口協(xié)議如下:

c8a75a26-9074-11ef-a511-92fbcf53809c.png

數(shù)據(jù)類型:比如0x3F表示這是通道1的數(shù)據(jù),0x4E表示通道2的數(shù)據(jù);

數(shù)據(jù)長度:表示后面跟著有效數(shù)據(jù)的長度;

有效數(shù)據(jù):有效字節(jié)數(shù);

校驗數(shù)據(jù):省略;

接下來演示如何用環(huán)形緩沖區(qū)做到不丟包解析。

3.2. 計算緩沖區(qū)大小

假定數(shù)據(jù)每200ms處理一次,而數(shù)據(jù)10ms接收一次,每次接收的數(shù)據(jù)包長度為7個字節(jié)。

要想做到不丟包,就需要將200ms內(nèi)接收到的所有數(shù)據(jù)包都存進緩沖區(qū),所以緩沖區(qū)大小至少為:200/10*7 = 140 個字節(jié)。

保險起見,可以將緩沖區(qū)適當?shù)臄U大一下,設(shè)置為150個字節(jié)。

3.3. 初始化緩沖區(qū)

使用時包含頭文件:

#include"ringbuff/ringbuff.h"

接著初始化緩沖區(qū):

uint8_tringbuff_init(RINGBUFF_VOLATILEringbuff_t*buff,void*buffdata,size_tsize);

該 API 用來初始化一個ringbuff句柄(指向ringbuff結(jié)構(gòu)體的指針),其中傳入的參數(shù)分別為:

buff:ringbuff句柄;

buffdata:緩沖區(qū)地址;

size:緩沖區(qū)大??;

首先創(chuàng)建一個緩沖區(qū)句柄,開辟一塊緩沖區(qū):

/*Privateusercode---------------------------------------------------------*/
/*USERCODEBEGIN0*/
//用于串口接收
uint8_trecv_data=0;

//用于存儲從緩沖區(qū)讀取出的數(shù)據(jù)
uint8_tread_data=0;

//用于串口1的ringbuff句柄
ringbuff_tusart1_ringbuff;

//開辟一塊內(nèi)存用于緩沖區(qū)
#defineUSART1_BUFFDATA_SIZE150
uint8_tusart1_buffdata[USART1_BUFFDATA_SIZE];

/*USERCODEEND0*/

然后在main函數(shù)中初始化ringbuff:

/*USERCODEBEGIN2*/
printf("ringbuffPortByMculover666
");

//初始化ringbuff句柄
if(1!=ringbuff_init(&usart1_ringbuff,(uint8_t*)usart1_buffdata,USART1_BUFFDATA_SIZE))
{
printf("usart1ringbuffinitfail.
");
}

//使能串口中斷接收
HAL_UART_Receive_IT(&huart1,(uint8_t*)&recv_data,1);

/*USERCODEEND2*/

3.4. 數(shù)據(jù)接收

接收到一個字節(jié)數(shù)據(jù)后,話不多說,直接往緩沖區(qū)扔:

/*USERCODEBEGIN4*/
/*中斷回調(diào)函數(shù)*/
voidHAL_UART_RxCpltCallback(UART_HandleTypeDef*huart)
{
/*判斷是哪個串口觸發(fā)的中斷*/
if(huart->Instance==USART1)
{
/*將接收到的數(shù)據(jù)寫入緩沖區(qū)*/
ringbuff_write(&usart1_ringbuff,&recv_data,1);
//重新使能串口接收中斷
HAL_UART_Receive_IT(huart,(uint8_t*)&recv_data,1);
}
}
/*USERCODEEND4*/

3.5. 數(shù)據(jù)處理

數(shù)據(jù)處理在while(1)中進行,每隔200ms將緩沖區(qū)數(shù)據(jù)全部讀出進行處理:

/*USERCODEBEGINWHILE*/
while(1)
{
/*USERCODEENDWHILE*/


/*USERCODEBEGIN3*/
while((len=ringbuff_read(&usart1_ringbuff,(uint8_t*)&read_data,sizeof(read_data)))>0)
{
/*捕獲起始標志*/
if(read_data==0x3F)
{
//讀取數(shù)據(jù)字節(jié)數(shù),最大支持0xFF
if((len=ringbuff_read(&usart1_ringbuff,(uint8_t*)&read_data,sizeof(read_data)))>0)
{
data_len=read_data;
printf("yourdatahas%dbyte(s):
	",data_len);
}

//提取data_len個數(shù)據(jù)
for(i=0;i0)
{
printf("[0x%02x]",read_data);
}
}
printf("over
");
}
}
HAL_Delay(200);

}
/*USERCODEEND3*/

編譯下載測試,實驗結(jié)果如下,可以做到不丟包解析:

c8c4dc2c-9074-11ef-a511-92fbcf53809c.png

3.6. 丟包測試

經(jīng)過3.2節(jié)的計算,不丟包的最小緩沖區(qū)大小是140個字節(jié),接下里我們將緩沖區(qū)大小修改為100個字節(jié),測試一下是否產(chǎn)生丟包:

//開辟一塊內(nèi)存用于緩沖區(qū)
#defineUSART1_BUFFDATA_SIZE100//會發(fā)生丟包
//#defineUSART1_BUFFDATA_SIZE150//10ms接收7byte的協(xié)議包時不丟包
uint8_tusart1_buffdata[USART1_BUFFDATA_SIZE];

再次編譯下載,查看串口輸出:

c8db1294-9074-11ef-a511-92fbcf53809c.png

4. 設(shè)計思想解讀

關(guān)于環(huán)形緩沖區(qū)背后的設(shè)計實現(xiàn),請閱讀這篇文章,寫的非常棒:

STM32進階之串口環(huán)形緩沖區(qū)實現(xiàn)

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 緩沖區(qū)
    +關(guān)注

    關(guān)注

    0

    文章

    33

    瀏覽量

    9107
  • 嵌入式
    +關(guān)注

    關(guān)注

    5082

    文章

    19104

    瀏覽量

    304791
  • fifo
    +關(guān)注

    關(guān)注

    3

    文章

    387

    瀏覽量

    43647
  • 串口
    +關(guān)注

    關(guān)注

    14

    文章

    1551

    瀏覽量

    76421
  • 開源
    +關(guān)注

    關(guān)注

    3

    文章

    3309

    瀏覽量

    42471

原文標題:分享一個嵌入式通用FIFO環(huán)形緩沖區(qū)實現(xiàn)庫

文章出處:【微信號:strongerHuang,微信公眾號:strongerHuang】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    基于C語言實現(xiàn)環(huán)形緩沖區(qū)/循環(huán)隊列

    這里分享自己用純C實現(xiàn)環(huán)形緩沖區(qū)
    的頭像 發(fā)表于 04-11 10:39 ?3283次閱讀
    基于C語言<b class='flag-5'>實現(xiàn)</b><b class='flag-5'>環(huán)形</b><b class='flag-5'>緩沖區(qū)</b>/循環(huán)隊列

    基于宏高效實現(xiàn)環(huán)形緩沖區(qū)教程

    來源 | 小麥大叔 循環(huán)緩沖區(qū)嵌入式軟件工程師在日常開發(fā)過程中的關(guān)鍵組件。 多年來,互聯(lián)網(wǎng)上出現(xiàn)了許多不同的循環(huán)緩沖區(qū)實現(xiàn)和示例。我非常喜歡這個模塊,可以GitHub上找到這個開源的
    的頭像 發(fā)表于 09-02 09:24 ?6729次閱讀
    基于宏高效<b class='flag-5'>實現(xiàn)</b><b class='flag-5'>環(huán)形</b><b class='flag-5'>緩沖區(qū)</b>教程

    STM32進階之串口環(huán)形緩沖區(qū)實現(xiàn)

    完了數(shù)據(jù),‘0’地址空間的數(shù)據(jù)進行釋放掉,列隊頭指向下一個可以處理數(shù)據(jù)的地址‘1’。從而實現(xiàn)整個環(huán)形緩沖區(qū)的數(shù)據(jù)讀寫??磮D,隊列頭就是指向已經(jīng)存儲的數(shù)據(jù),并且這個數(shù)據(jù)是待處理的。下
    發(fā)表于 06-08 14:03

    STM32串口環(huán)形緩沖區(qū)實現(xiàn)

    是列隊頭的數(shù)據(jù),處理完了數(shù)據(jù),‘0’地址空間的數(shù)據(jù)進行釋放掉,列隊頭指向下一個可以處理數(shù)據(jù)的地址‘1’。從而實現(xiàn)整個環(huán)形緩沖區(qū)的數(shù)據(jù)讀寫??磮D,隊列頭就是指向已經(jīng)存儲的數(shù)據(jù),并且這個數(shù)
    發(fā)表于 10-16 11:40

    環(huán)形緩沖區(qū)的設(shè)計分享!

    以下內(nèi)容轉(zhuǎn)自網(wǎng)絡(luò),感謝網(wǎng)友:玩笑joker 環(huán)形緩沖區(qū)嵌入式系統(tǒng)中十分重要的種數(shù)據(jù)結(jié)構(gòu),比如在
    發(fā)表于 10-28 23:29

    環(huán)形緩沖區(qū)簡介

    程序中,經(jīng)常使用環(huán)形緩沖器作為數(shù)據(jù)結(jié)構(gòu)來存放通信中發(fā)送和接收的數(shù)據(jù)。環(huán)形緩沖區(qū)先進先出的循
    發(fā)表于 08-17 06:56

    請問怎么實現(xiàn)串口環(huán)形緩沖區(qū)FIFO

    請問怎么實現(xiàn)串口環(huán)形緩沖區(qū)FIFO?
    發(fā)表于 12-06 07:23

    環(huán)形緩沖區(qū)讀寫操作的分析與實現(xiàn)

    環(huán)形緩沖區(qū)嵌入式系統(tǒng)中種重要的常用數(shù)據(jù)結(jié)構(gòu)。在多任務環(huán)境下實現(xiàn)時,如果有多個讀寫任務,般需
    發(fā)表于 04-15 11:35 ?40次下載

    環(huán)形緩沖區(qū)實現(xiàn)原理

    在通信程序中,經(jīng)常使用環(huán)形緩沖區(qū)作為數(shù)據(jù)結(jié)構(gòu)來存放通信中發(fā)送和接收的數(shù)據(jù)。環(huán)形緩沖區(qū)先進先
    的頭像 發(fā)表于 03-22 10:03 ?7529次閱讀
    <b class='flag-5'>環(huán)形</b><b class='flag-5'>緩沖區(qū)</b>的<b class='flag-5'>實現(xiàn)</b>原理

    緩沖區(qū)是啥意思 STM32串口數(shù)據(jù)接收之環(huán)形緩沖區(qū)

    緩沖區(qū)顧名思義是緩沖數(shù)據(jù)用的。實現(xiàn)緩沖區(qū)最簡單的辦法時,定義多個數(shù)組,接收包數(shù)據(jù)到數(shù)組A,就把接收數(shù)據(jù)的地址換成數(shù)組B,每個數(shù)據(jù)有
    的頭像 發(fā)表于 07-22 15:33 ?1.1w次閱讀

    STM32串口數(shù)據(jù)接收 --環(huán)形緩沖區(qū)

    程序中,經(jīng)常使用環(huán)形緩沖器作為數(shù)據(jù)結(jié)構(gòu)來存放通信中發(fā)送和接收的數(shù)據(jù)。環(huán)形緩沖區(qū)先進先出的循
    發(fā)表于 12-28 19:24 ?31次下載
    STM32串口數(shù)據(jù)接收 --<b class='flag-5'>環(huán)形</b><b class='flag-5'>緩沖區(qū)</b>

    環(huán)形緩沖區(qū)實現(xiàn)思路

    單片機程序開發(fā)般都會用到UART串口通信,通過通信來實現(xiàn)上位機和單片機程序的數(shù)據(jù)交互。通信中為了實現(xiàn)正常的收發(fā),般都會有對應的發(fā)送和接收緩存來暫存通信數(shù)據(jù)。這里使用
    的頭像 發(fā)表于 01-17 15:07 ?1631次閱讀

    STM32進階之串口環(huán)形緩沖區(qū)實現(xiàn)

    STM32進階之串口環(huán)形緩沖區(qū)實現(xiàn)
    的頭像 發(fā)表于 09-19 09:20 ?2283次閱讀
    STM32進階之串口<b class='flag-5'>環(huán)形</b><b class='flag-5'>緩沖區(qū)</b><b class='flag-5'>實現(xiàn)</b>

    C++環(huán)形緩沖區(qū)設(shè)計與實現(xiàn)

    的存儲空間。環(huán)形緩沖區(qū)的特點是其終點和起點是相連的,形成環(huán)狀結(jié)構(gòu)。這種數(shù)據(jù)結(jié)構(gòu)在處理流數(shù)據(jù)和實現(xiàn)數(shù)據(jù)緩存等場景中具有廣泛的應用。
    的頭像 發(fā)表于 11-09 11:21 ?2024次閱讀
    C++<b class='flag-5'>環(huán)形</b><b class='flag-5'>緩沖區(qū)</b>設(shè)計與<b class='flag-5'>實現(xiàn)</b>

    嵌入式環(huán)形隊列與消息隊列的實現(xiàn)原理

    嵌入式環(huán)形隊列,也稱為環(huán)形緩沖區(qū)或循環(huán)隊列,是種先進先出(FIFO)的數(shù)據(jù)結(jié)構(gòu),用于在固定大小
    的頭像 發(fā)表于 09-02 15:29 ?476次閱讀
    RM新时代网站-首页