STM32上使用的環形FIFO佇列,用於快取待發送資料
阿新 • • 發佈:2018-12-19
C語言實現的環形FIFO佇列,用於執行緒非同步通訊,資料傳送非常方便,比如GPRS傳送資料,一個執行緒將資料寫入到FIFO,傳送執行緒不停的從FIFO中讀取資料,然後傳送,又比如上位機中,資料接收執行緒不停的接收資料,寫入到FIFO,另一個非同步的處理執行緒不停的讀取資料,進行處理。
- /*************************************************************************************************************
- * 檔名: SendDataFIFO.c
- * 功能: 實時資料傳送緩衝區
- * 作者:
[email protected] - * 建立時間: 2015-08-09
- * 最後修改時間: 2017-08-26
- * 詳細: 用於資料傳送緩衝區
- 2017-08-26:增加溢位回撥函式,可以對溢位的資料進行處理,用於FIFO巢狀
- *************************************************************************************************************/
- #include "system.h"
- #include "usart.h"
- #include "led.h"
- #include "main.h"
- #include
"SendDataFIFO.h" - #include "SYSMalloc.h"
- #define FIFO_INIT_STATUS_ID 0x354789d //用於標示是否初始化
- //初始化緩衝區
- bool FIFO_Init(FIFO_HANDLE *pHandle,u16 OneSize, u16 MaxCnt, void (*FullCallBack)(void *pData), bool isExtSRAM)
- {
- if(pHandle == NULL) return FALSE;
- if(isExtSRAM == TRUE) //是否使用外部緩衝區
- {
- pHandle->pFifoBuff = (u8 *)mymalloc(SRAMEX, OneSize*MaxCnt); //緩衝區指標,申請記憶體
- pHandle->pByteCntBuff = (u16 *)mymalloc(SRAMEX, sizeof(u16)*MaxCnt); //資料大小記錄緩衝區,申請記憶體
- }
- else
- {
- pHandle->pFifoBuff = (u8 *)mymalloc(SRAMIN, OneSize*MaxCnt); //緩衝區指標,申請記憶體
- pHandle->pByteCntBuff = (u16 *)mymalloc(SRAMIN, sizeof(u16)*MaxCnt); //資料大小記錄緩衝區,申請記憶體
- }
- //uart_printf("pHandle->pFifoBuff=0x%X\r\n", (u32)pHandle->pFifoBuff);
- //uart_printf("pHandle->pByteCntBuff=0x%X\r\n", (u32)pHandle->pByteCntBuff);
- if(pHandle->pFifoBuff==NULL)
- {
- DEBUG("pHandle->pFifoBuff申請記憶體出錯\r\n");
- }
- if(pHandle->pByteCntBuff==NULL)
- {
- DEBUG("pHandle->pByteCntBuff申請記憶體出錯\r\n");
- }
- pHandle->InitStatus = 0; //初始化成功狀態無效
- if((pHandle->pFifoBuff==NULL)||(pHandle->pByteCntBuff==NULL)) return FALSE;
- pHandle->OneSize = OneSize; //單條資料大小
- pHandle->Cnt = MaxCnt; //緩衝區總資料容量(條數)
- pHandle->ReadCnt = 0; //讀取位置
- pHandle->WriteCnt = 0; //寫位置
- pHandle->NotReadCnt = 0; //未讀取數量
- pHandle->FullCallBack = FullCallBack; //溢位回撥函式
- pHandle->InitStatus = FIFO_INIT_STATUS_ID; //初始化成功狀態有效
- return TRUE;
- }
- //寫入一條資料
- //當緩衝區滿了後,快取最新的資料,丟掉最早的資料
- bool FIFO_Write(FIFO_HANDLE *pHandle,u8 *pBuff, u16 ByteCnt)
- {
- u16 cnt;
- #ifdef _UCOS_II_
- OS_CPU_SR cpu_sr;
- #endif
- if(pHandle == NULL) return FALSE;
- if(pHandle->InitStatus != FIFO_INIT_STATUS_ID) return FALSE; //沒有初始化
- if (pHandle->NotReadCnt >= pHandle->Cnt) //傳送溢位
- {
- cnt = pHandle->WriteCnt; //先將寫指標後移,佔位,防止多執行緒寫衝突
- if(pHandle->FullCallBack!=NULL) pHandle->FullCallBack(&pHandle->pFifoBuff[cnt * pHandle->OneSize]);
- if (ByteCnt > pHandle->OneSize) ByteCnt = pHandle->OneSize; //限制單條資料大小
- pHandle->WriteCnt++;
- if (pHandle->WriteCnt >= pHandle->Cnt) pHandle->WriteCnt = 0; //環形FIFO
- pHandle->ReadCnt++; //讀取數量增加
- if (pHandle->ReadCnt >= pHandle->Cnt) pHandle->ReadCnt = 0; //環形FIFO,把讀寫指標都增加,但是剩餘資料數量不變
- pHandle->pByteCntBuff[cnt] = ByteCnt; //記錄資料大小
- memcpy(&pHandle->pFifoBuff[cnt * pHandle->OneSize], pBuff, ByteCnt); //拷貝資料到緩衝區
- return FALSE; //資料已經滿了
- }
- else
- {
- if (ByteCnt > pHandle->OneSize) ByteCnt = pHandle->OneSize; //限制單條資料大小
- //先將寫指標後移,佔位,防止多執行緒寫衝突
- cnt = pHandle->WriteCnt;
- pHandle->WriteCnt++;
- if (pHandle->WriteCnt >= pHandle->Cnt) pHandle->WriteCnt = 0; //環形FIFO
- pHandle->pByteCntBuff[cnt] = ByteCnt; //記錄資料大小
- memcpy(&pHandle->pFifoBuff[cnt * pHandle->OneSize], pBuff, ByteCnt); //拷貝資料到緩衝區
- /*{
- u16 i;
- printf("\r\n寫入的資料測試[讀%d/寫:%d]:\r\n",pHandle->ReadCnt,pHandle->WriteCnt);
- for(i = 0;i < ByteCnt;i ++)
- {
- pHandle->pFifoBuff[cnt * pHandle->OneSize+i] = pBuff[i];
- printf("%02X\t",pBuff[i]);
- if(pHandle->pFifoBuff[cnt * pHandle->OneSize+i] != pBuff[i])
- {
- printf("拷貝檢測錯誤,資料丟失了\r\n");
- }
- }
- printf("\r\n檢測寫入的資料測試:\r\n");
- for(i = 0;i < ByteCnt;i ++)
- {
- printf("%02X\t",pHandle->pFifoBuff[cnt * pHandle->OneSize+i]);
- }
- printf("\r\n");
- }*/
- #ifdef _UCOS_II_
- OS_ENTER_CRITICAL(); //關閉系統中斷
- #endif
- pHandle->NotReadCnt ++; //沒有讀取的數量增加
- #ifdef _UCOS_II_
- OS_EXIT_CRITICAL(); //開啟系統中斷
- #endif
- return TRUE;
- }
- }
- //讀取一條資料,返回指標,無需複製資料
- bool FIFO_ReadNotCopy(FIFO_HANDLE *pHandle,u8 **pBuff, u16 *pByteCnt)
- {
- u16 cnt;
- printf("\r\n讀取資料[讀%d/寫:%d]:\r\n",pHandle->ReadCnt,pHandle->WriteCnt);
- if(pHandle == NULL) return FALSE;
- if(pHandle->InitStatus != FIFO_INIT_STATUS_ID) return FALSE; //沒有初始化
- if (pHandle->NotReadCnt == 0) return FALSE; //資料為空
- cnt = pHandle->pByteCntBuff[pHandle->ReadCnt]; //獲取資料大小
- if (cnt > pHandle->OneSize) cnt = pHandle->OneSize; //限制單條資料大小
- *pBuff = &pHandle->pFifoBuff[pHandle->ReadCnt * pHandle->OneSize]; //資料緩衝區指標
- *pByteCnt = cnt;
- return TRUE;
- }
- //未讀取資料減少一次,用於讀取資料返回指標後呼叫
- u16 FIFO_ReduceOne(FIFO_HANDLE *pHandle)
- {
- #ifdef _UCOS_II_
- OS_CPU_SR cpu_sr;
- #endif
- if(pHandle == NULL) return FALSE;
- if(pHandle->InitStatus != FIFO_INIT_STATUS_ID) return FALSE; //沒有初始化
- if (pHandle->NotReadCnt == 0) return FALSE;
- pHandle->ReadCnt++; //讀取數量增加
- if (pHandle->ReadCnt >= pHandle->Cnt) pHandle->ReadCnt = 0; //環形FIFO
- #ifdef _UCOS_II_
- OS_ENTER_CRITICAL(); //關閉系統中斷
- #endif
- pHandle->NotReadCnt--; //沒有讀取的數量減少
- #ifdef _UCOS_II_
- OS_EXIT_CRITICAL(); //開啟系統中斷
- #endif
- return pHandle->NotReadCnt; //返回沒有讀取的資料數量
- }
- //清除FIFO
- bool FIFO_Clear(FIFO_HANDLE *pHandle)
- {
- if(pHandle == NULL) return FALSE;
- if(pHandle->InitStatus != FIFO_INIT_STATUS_ID) return FALSE; //沒有初始化
- pHandle->ReadCnt = 0; //FIFO讀取位置
- pHandle->WriteCnt = 0; //FIFO寫入位置
- pHandle->NotReadCnt = 0; //FIFO內沒有讀取的資料數量為0
- return TRUE;
- }
- //獲取FIFO中資料數量
- u16 FIFO_GetDataNumber(FIFO_HANDLE *pHandle)
- {
- if(pHandle == NULL) return 0;
- if(pHandle->InitStatus != FIFO_INIT_STATUS_ID) return 0; //沒有初始化
- return pHandle->NotReadCnt; //FIFO內沒有讀取的資料數量
- }
- /*************************************************************************************************************
- * 檔名: SendDataFIFO.h
- * 功能: 實時資料傳送緩衝區
- * 作者: [email protected]
- * 建立時間: 2015-08-09
- * 最後修改時間: 2017-08-26
- * 詳細: 用於資料傳送緩衝區
- 2017-08-26:增加溢位回撥函式,可以對溢位的資料進行處理
- *************************************************************************************************************/
- #ifndef __SEND_DATA_FIFO_H__
- #define __SEND_DATA_FIFO_H__
- #include "system.h"
- typedef struct
- {
- u8 *pFifoBuff; //緩衝區指標
- u16 *pByteCntBuff; //記錄資料大小的緩衝區
- u16 OneSize; //單條資料大小
- u16 Cnt; //緩衝區總資料容量(條數)
- u16 ReadCnt; //讀取位置
- u16 WriteCnt; //寫位置
- u16 NotReadCnt; //未讀取數量
- u32 InitStatus; //初始化狀態
- void (*FullCallBack)(void *pData); //緩衝區滿回撥函式
- }FIFO_HANDLE;
- bool FIFO_Init(FIFO_HANDLE *pHandle,u16 OneSize, u16 MaxCnt, void (*FullCallBack)(void *pData), bool isExtSRAM); //初始化緩衝區
- bool FIFO_Write(FIFO_HANDLE *pHandle,u8 *pBuff, u16 ByteCnt); //寫入一條資料
- bool FIFO_ReadNotCopy(FIFO_HANDLE *pHandle,u8 **pBuff, u16 *pByteCnt); //讀取一條資料,返回指標,無需複製資料
- u16 FIFO_ReduceOne(FIFO_HANDLE *pHandle); //未讀取資料減少一次,用於讀取資料返回指標後呼叫
- bool FIFO_Clear(FIFO_HANDLE *pHandle); //清除FIFO
- u16 FIFO_GetDataNumber(FIFO_HANDLE *pHandle); //獲取FIFO中資料數量
- #endif //__SEND_DATA_FIFO_H__
示例,比如定時傳送資料,將資料定時拷貝到FIFO中,另一個執行緒定時啟動,傳送資料:
- //拷貝實時資料到傳送緩衝區中,進行立即傳送資料(注意功能碼必須為8位)
- void CopyTempDataToFIFO(u8 Fun)
- {
- u8 i;
- //寫入需要傳送的資料的功能碼
- g_TempRealData.Fun = Fun; //功能碼
- g_TempRealData.SerialNumber = 0; //流水號設定為0,自動分配
- g_TempRealData.Time[0] = timer.w_year-2000; //拷貝實時時間
- g_TempRealData.Time[1] = timer.w_month; //拷貝實時時間
- g_TempRealData.Time[2] = timer.w_date; //拷貝實時時間
- g_TempRealData.Time[3] = timer.hour; //拷貝實時時間
- g_TempRealData.Time[4] = timer.min; //拷貝實時時間
- g_TempRealData.Time[5] = 0; //拷貝實時時間
- //迴圈將資料寫入到4箇中心站的傳送FIFO中(如果中心站埠為0,則認為中心站無效,不進行傳送)
- for(i=0;i<4;i++)
- {
- //伺服器配置有效才寫入資料到緩衝區
- if(g_SYS_Config.ServerPort[i] > 0)
- {
- FIFO_Write(&g_SendFifoBuff[i], (u8 *)&g_TempRealData, sizeof(REAL_DATA)); //寫入資料到傳送緩衝區
- }
- else
- {
- FIFO_Clear(&g_SendFifoBuff[i]); //不用傳送的站點,清除緩衝區
- FIFO_Clear(&g_SendCacheFifoBuff[i]); //不用傳送的站點,清除Cache緩衝區
- }
- }
- }
傳送資料,從FIFO中讀取
- isFifoStatus = FIFO_ReadNotCopy(pFifoHandle, (u8 **)&pTempRealData, &ByteLen);
- if(isFifoStatus==TRUE) //有資料要傳送 //實時緩衝區中沒有資料,檢查Cache中是否有資料
- {....../*傳送資料邏輯*/ FIFO_ReduceOne(pFifoHandle);//傳送結束後,清除當前讀取過的資料
- }