先說串口,這個應該都知道吧(不知道的童鞋,先把基本功學好),大部分單片機或者處理器都會帶一個或者多個串口,方便進行數據的通信。
那么,串口的循環隊列是什么?這里以STM32的串口為例,進行解釋說明。
假設串口一次只發一個數據,這倒是簡單了,每次只對這一個數據進行判斷,然后處理相關指令。但現實不會一直都這么美好,很多時候你收到的可能是一大串數據,你要先小心翼翼的把它們存好,然后再依次判斷這里面有哪些指令要處理。
假設你定義了一個30個元素的數組a[30],每次串口收到數據都往里面存,存的時候地址加一。這個操作很簡單吧,應該是都會的。
但是取的時候怎么取?你收到的指令可能是2個數據,也可能是3個數據,幾種長度不一樣的指令混在一起。
一次從數組里讀出幾個數據?怎么快速騰出已讀數據的位置?還是一次都讀完,然后整個數組清零?
先說一次讀完,然后清零的這個方法為什么不行。
1、讀的時候,里面的數據不一定是完整的。有可能某組數據剛接收到一半兒。
2、讀完以后,清零之前,如果進來新的數據怎么辦?
所以,比較穩妥的方法是,一次只讀一個數據,讀一次,清除該數據所占的位置。所以這需要一個變量,來記錄數據頭在這個數組中的位置。
第二,當有新數據來的時候,要知道它能放在哪,所以要有一個變量,來記錄數據尾在哪。
第三,如果有必要,你可以定義一個變量來記錄數據長度,存入的時候加一,取出的時候減一。
第四,也是比較重要的,如果數據尾已經是a[29]了,下一個數據放哪?整個數組都清掉?NO,假設此時a[0]~a[10]已經被取出了,數據頭變成了a[11]。那么新的數據尾變成a[0],即當數據尾大于等于30的時候,變成0.
如此一來,相當于把這個數組的頭和尾連了起來,成了一個封閉的環,這種處理方式,就叫做串口的循環隊列。只要確保數組夠大,處理速度夠快,那么頭和尾就不會撞上。當然,程序上也要對這種意外情況做一個處理。以下圖片來自網絡:
下面是代碼,核心的部分都在這,復制粘貼一下,基本就可以了。
首先是定義一個結構體,關于數據頭、數據尾、數組的:
typedef struct
{
u16 Head;
u16 Tail;
u16 Length;
u8 Rsv_DAT[50];
}ringbuff_t;
ringbuff_t Ringbuff;
然后是結構體初始化:
void ringbuff_init(void)
{
Ringbuff.Head = 0;
Ringbuff.Tail = 0;
Ringbuff.Length = 0;
}
然后是存入數據的操作,把這個函數放進串口接收中斷就行:
u8 write_ringbuff(u8 data)
{
if(Ringbuff.Length >= 50)
{
return FALSE;
}
else
{
Ringbuff.Rsv_DAT[Ringbuff.Tail] = data;
Ringbuff.Tail = (Ringbuff.Tail + 1)% 50;//防止越界
Ringbuff.Length++;
return TRUE;
}
}
然后是取出數據的操作:
u8 read_ringbuff(u8 *rdata)
{
if(Ringbuff.Length == 0)
{
return FALSE;
}
else
{
*rdata = Ringbuff.Rsv_DAT[Ringbuff.Head];
Ringbuff.Rsv_DAT[Ringbuff.Head] = 0;
Ringbuff.Head = (Ringbuff.Head + 1)%50;
Ringbuff.Length--;
return TRUE;
}
}
然后就能用了,這是寫操作:
write_ringbuff(USART_ReceiveData(USART1));
這是讀操作:
read_ringbuff(&uart_buf[0]);
讀操作的函數里,還可以增加一個操作,就是讀出以后,把該位置數據清零,這個看個人需要。
以上,就是串口循環隊列的一個簡介,如果有寫的不好的,歡迎留言指正。當然,方法千千萬,不一定只能用這種。最后,借用流浪地球的一句經典臺詞作為結尾:
方法千萬條,穩定第一條。
代碼不規范,碼農兩行淚。
-
STM32
+關注
關注
2270文章
10906瀏覽量
356530 -
串口
+關注
關注
14文章
1555瀏覽量
76647 -
代碼
+關注
關注
30文章
4799瀏覽量
68728
原文標題:基于STM32的串口循環隊列
文章出處:【微信號:gh_c472c2199c88,微信公眾號:嵌入式微處理器】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論