在串口,IIC或SPI以及CAN等通訊中,往往需要一次性發送一幀完整的資料,由於硬體發送的速度問題,硬體不能及時發送出去,就會導致資料丟失等一系列問題。通常採用建立緩衝區解決。隊列可以有效利用緩衝區空間,並且保證資料在發送和接收過程中的時序問題。現在網上有公開的隊列源碼,其一般由入隊,出隊,查詢隊列成員數量,建立隊列,銷毀隊列等組成,相對比較完善,但是在串口等環境中使用存在過多的調用函數等問題。所以就以上的情況做出了改善,編寫了一個精簡的緩衝隊列,經過測試可以保證資料轉送的完整性。 一、建立結構體
結構體主要由 緩衝區,隊列頭指標,隊列尾指標,以及隊列發送完成標誌位組成。
/*******資料發送緩衝區 結構體*****/typedef struct { u8 TxBuff[BUFFSIZE]; //緩衝區 u16 font; //頭指標 u16 rear; //尾指標 u8 finished; //發送完成,0代表未發送完,1代表發送完成,發送終止 }TxBuffer; 二 入隊函數
將發送的資料存入緩衝數組,並且移動相應長度的尾指標,檢查發送標誌位,判斷是否需要啟動硬體發送。主要有兩個函數,一個為單位元組發送個,另一個為多位元組發送。
/* *函數名:UsartSendData *描述:串口發送資料,發送單位元組 *輸入:tx:發送介面 *輸出:無 *調用:外部調用 */void UsartSendData(ConnIFName tx,u8 data,USART_TypeDef* u){ TxBuffer* buff = GetTxBuffer(tx); //佔用1位元組用於判斷是否到達緩衝區尾部 if(buff->rear == BUFFSIZE) buff->rear=0; buff->TxBuff[buff->rear++]=data; if(buff->finished == 1) { buff->finished=0; if(buff->font == BUFFSIZE) buff->font=0; USART_SendData(u,buff->TxBuff[buff->font]); buff->TxBuff[buff->font] = 0xFF; buff->font++; }}/* *函數名:MultitySend() *描述:串口發送資料,多位元組發送 *輸入:tx->發送介面 ;sendData[] 發送的數組;u->調用發送的硬體串口;len->發送的長度 *輸出:無 *調用:外部調用 */void MultitySend(ConnIFName tx,u8 data[],USART_TypeDef* u,u8 len){ u8 i=0; TxBuffer* buff = GetTxBuffer(tx); if(len<BUFFSIZE-buff->rear+buff->font) { for(i=0;i<len;i++) { if(buff->rear == BUFFSIZE) buff->rear=0; buff->TxBuff[buff->rear++] = data[i]; } if(buff->finished !=0) { if(buff->font == BUFFSIZE) buff->font=0; USART_SendData(u,buff->TxBuff[buff->font++]); buff->finished =0; } }} 三 出隊函數
讀取隊列中的資料並交由硬體發送,同時移動頭指標到相應位置,根據情況操作標誌位。這個函數一般由發送中斷調用。
/* *函數名:TxBuffIRQ *描述:串口發送 *輸入:tx:發送介面 *輸出:無 *調用:中斷調用 */void TxBuffIRQ(ConnIFName tx,USART_TypeDef* u){ //取得該通訊介面緩衝區指標 TxBuffer* buff = GetTxBuffer(tx); //判斷緩衝區為NULL,則發送完成,停止發送 if(buff->font == buff->rear ) { buff->finished=1; //發送完成置位(緩衝區為空白) }else { //判斷是否到達隊列尾部,如果到達則從頭開始 /**防止由於時間差的問題導致中斷重複發送緩衝區資料*****/ if(buff->font == BUFFSIZE ) buff->font=0; USART_SendData(u,buff->TxBuff[buff->font]); //0xff填充緩衝區 buff->TxBuff[buff->font] = 0xff; buff->font++; }} 四 擷取隊列函數
當多個隊列共存時,需要由該函數傳遞對應隊列的指標,以便操作隊列。
/* *函數名:GetTxBuffer *描述:取得發送緩衝區指標 *輸入:tx:取得哪個值 *輸出:無 *調用:內部調用 */TxBuffer* GetTxBuffer(ConnIFName tx){ switch (tx) { case DGUSIF: return &DgusTxBuff; case WKIF: return &WKTxBuff; case CK1IF: return &CKTxBuff; default: break; } return 0;}