說在前面
碼代碼的應該學數據結構都學過隊列。環形隊列是隊列的一種特殊形式,應用挺廣泛的。因為有太多文章關于這方面的內容,理論知識可以看別人的,下面寫得挺好的:STM32進階之串口環形緩沖區實現
代碼實現
環形隊列數據結構
typedef?struct?ringBuff{
????unsigned?int?in;???????????????//寫入的位置
????unsigned?int?out;??????????????//讀出的位置
????unsigned?char?buffer[RING_BUFF_SIZE];?????//數據域
}stRingBuff;
寫一字節數據到隊列
/** ?-?@brief:?????????寫一字節的數據到環形隊列 ?-?@param[in]:?????None ?-?@retval[out]:???None ?-?@note:???????????? ?-?@author:???????AresXu ?-?@version:??????v1.0.0 */ char?WriteOneByteToRingBuffer(stRingBuff?*ringBuf,char?data) { ?if?(ringBuf?==?NULL) ????{ ????????printf("pointer?is?null "); ????????return; ????} ???? ????if(IsRingBufferFull(ringBuf))???//寫之前先判斷隊列是否寫滿 ????{ ????????return?FALSE; ????} ????ringBuf->buffer[ringBuf->in]?=?data; ????ringBuf->in?=?(++ringBuf->in)?%?RING_BUFF_SIZE;????//防止越界 ?return?TRUE; }
寫入數據時要判斷隊列是否滿,滿了肯定就不能寫入。
判斷隊列是否寫滿
/**
?-?@brief:?????????判斷環形隊列是否滿
?-?@param[in]:?????None
?-?@retval[out]:???None
?-?@note:????????????
?-?@author:???????AresXu
?-?@version:??????v1.0.0
*/
bool?IsRingBufferFull(stRingBuff?*ringBuf)
{
??if?(ringBuf?==?NULL)
????{
????????printf("pointer?is?null
");
????????return;
????}
????
????if(((ringBuf->in+1)?%?RING_BUFF_SIZE)?==?ringBuf->out)
????{
//??printf("Ring?buffer?is?Full
");
????????return?TRUE;
????}
????return?FALSE;
}
當寫滿時,讀寫位置也是相等,無法判斷是否寫滿。這種情況有兩種辦法解決:
數據結構增加一個變量來計數寫入數據的個數
像這種((ringBuf->in+1) % RING_BUFF_SIZE) == ringBuf->out,空出一個字節來不寫數據

讀一字節的數據
/** ?-?@brief:?????????從環形隊列中讀一字節數據 ?-?@param[in]:?????None ?-?@retval[out]:???None ?-?@note:???????????? ?-?@author:???????AresXu ?-?@version:??????v1.0.0 */ char?ReadOneByteFromRingBuffer(stRingBuff?*ringBuf,char?*data) { ?if?(ringBuf?==?NULL) ????{ ????????printf("pointer?is?null "); ????????return; ????} ???? ????if(IsRingBufferEmpty(ringBuf))????//讀之前判斷隊列是否為空 ????{ ????????return?FALSE; ????} ????*data?=?ringBuf->buffer[ringBuf->out]; ????ringBuf->out?=?(++ringBuf->out)?%?RING_BUFF_SIZE;????//防止越界 ????return?TRUE; }?
判斷隊列是否為空寫入位置和讀出位置相等時為空
/**
?-?@brief:????????判斷環形隊列是否空
?-?@param[in]:?????None
?-?@retval[out]:???None
?-?@author:???????AresXu
?-?@version:??????v1.0.0
*/
bool?IsRingBufferEmpty(stRingBuff?*ringBuf)
{?
?if?(ringBuf?==?NULL)
????{
????????printf("pointer?is?null
");
????????return;
????}
????
????if(ringBuf->in?==?ringBuf->out)???//寫入位置和讀出位置相等時為空
????{
//??printf("Ring?buffer?is?Empty
");
????????return?TRUE;
????}
????return?FALSE;
}
寫多個字節到隊列
/**
?*?@brief:?????????寫len個字節數據到環形隊列
?*?@param[in]:?????None
?*?@retval[out]:???None
?*?@note:????????????
?*?@author:????????AresXu
?*?@version:???????v1.0.0
*/
void?WriteRingBuffer(stRingBuff?*ringBuf,char?*writeBuf,unsigned?int?len)
{
????unsigned?int?i;
?
?if?(ringBuf?==?NULL)
????{
????????printf("pointer?is?null
");
????????return;
????}
????
????for(i?=?0;?i?
從隊列中讀出多個字節
/**
?*?@brief:?????????從環形隊列讀出len個字節的數據
?*?@param[in]:?????None
?*?@retval[out]:???None
?*?@note:????????????
?*?@author:???????AresXu
?*?@version:??????v1.0.0
*/
void?ReadRingBuffer(stRingBuff?*ringBuf,char?*readBuf,unsigned?int?len)
{
????unsigned?int?i;
????
?if?(ringBuf?==?NULL)
????{
????????printf("pointer?is?null
");
????????return;
????}
????
????for(i?=?0;?i?
獲取已經寫入隊列的數據長度有這個方便知道接收完了要從隊列中讀出多少個數據。
/**
??*?@brief:?????????獲取已經寫入的長度
??*?@param[in]:?????None
??*?@retval[out]:???None
??*?@note:????????????
??*?@author:????????AresXu
??*?@version:???????v1.0.0
*/
int?GetRingBufferLength(stRingBuff?*ringBuf)
{
????if?(ringBuf?==?NULL)
????{
????????printf("pointer?is?null
");
????????return;
????}
????return?(ringBuf->in?-?ringBuf->out?+?RING_BUFF_SIZE)?%?RING_BUFF_SIZE;
}
畫個圖,畫畫就可以知道為什么這樣可以判斷寫入的長度。
到STM32上測試
串口接收部分:
static?stRingBuff?g_stRingBuffer?=?{0,0,0};
static?u8?g_recvFinshFlag?=?0;
stRingBuff?*GetRingBufferStruct(void)
{
?return?&g_stRingBuffer;
}
u8?*IsUsart1RecvFinsh(void)
{
?return?&g_recvFinshFlag;
}
void?USART1_IRQHandler(void)?????????????????//串口1中斷服務程序
{
?u8?res;
?if(USART_GetITStatus(USART1,?USART_IT_RXNE)?!=?RESET)??//接收中斷(接收到的數據必須是0x0d?0x0a結尾)
?{
??res?=?USART_ReceiveData(USART1);?//讀取接收到的數據
??WriteOneByteToRingBuffer(GetRingBufferStruct(),res);?
????}
?if(USART_GetITStatus(USART1,?USART_IT_IDLE)?!=?RESET)????????//空閑中斷
?{
??USART_ReceiveData(USART1);???????????//清除空閑中斷
??g_recvFinshFlag?=?1;??????????????????//接收完成
?}
}?
主函數:
int?main(void)
{??
?char?readBuffer[100];
?u16?t;??
?u16?len;?
?u16?times?=?0;
?delay_init();???????//延時函數初始化???
?NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);?//設置NVIC中斷分組2:2位搶占優先級,2位響應優先級
?uart_init(115200);??//串口初始化為115200
?LED_Init();????????//LED端口初始化
?KEY_Init();??????????//初始化與按鍵連接的硬件接口
?
?while(1)
?{
??times++;
??if(*IsUsart1RecvFinsh())
??{
???ReadRingBuffer(GetRingBufferStruct(),readBuffer,GetRingBufferLength(GetRingBufferStruct()));
???printf("%s",readBuffer);
???memset(readBuffer,0,100);
???*IsUsart1RecvFinsh()?=?0;
??}
??if(times%500==0)
???LED0=!LED0;
??delay_ms(1);???
?}??
}
串口收發測試

編輯:黃飛
電子發燒友App




















評論