轉(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:
移植之前需要準備一份裸機工程,我使用STM32CubeMX生成,需要初始化以下配置:
配置一個串口,中斷方式接收數(shù)據(jù),查詢方式發(fā)送數(shù)據(jù);
printf重定向;
2.3. 添加ringbuff 到工程中
① 復制 ringbuff 源碼到工程中:
② 在keil中添加 ringbuff 組件的源碼文件:
③ 添加 ringbuff 的頭文件路徑:
2.4. 配置ringbuff
ringbuff中默認volatile關(guān)鍵詞沒有定義,需要手動配置一下,在ringbuff.h中:
至此,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é)議如下:
數(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é)果如下,可以做到不丟包解析:
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];
再次編譯下載,查看串口輸出:
4. 設(shè)計思想解讀
關(guān)于環(huán)形緩沖區(qū)背后的設(shè)計實現(xiàn),請閱讀這篇文章,寫的非常棒:
STM32進階之串口環(huán)形緩沖區(qū)實現(xià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)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論