先說串口,這個應(yīng)該都知道吧(不知道的童鞋,先把基本功學好),大部分單片機或者處理器都會帶一個或者多個串口,方便進行數(shù)據(jù)的通信。
那么,串口的循環(huán)隊列是什么?這里以STM32的串口為例,進行解釋說明。
假設(shè)串口一次只發(fā)一個數(shù)據(jù),這倒是簡單了,每次只對這一個數(shù)據(jù)進行判斷,然后處理相關(guān)指令。但現(xiàn)實不會一直都這么美好,很多時候你收到的可能是一大串數(shù)據(jù),你要先小心翼翼的把它們存好,然后再依次判斷這里面有哪些指令要處理。
假設(shè)你定義了一個30個元素的數(shù)組a[30],每次串口收到數(shù)據(jù)都往里面存,存的時候地址加一。這個操作很簡單吧,應(yīng)該是都會的。
但是取的時候怎么???你收到的指令可能是2個數(shù)據(jù),也可能是3個數(shù)據(jù),幾種長度不一樣的指令混在一起。
一次從數(shù)組里讀出幾個數(shù)據(jù)?怎么快速騰出已讀數(shù)據(jù)的位置?還是一次都讀完,然后整個數(shù)組清零?
先說一次讀完,然后清零的這個方法為什么不行。
1、讀的時候,里面的數(shù)據(jù)不一定是完整的。有可能某組數(shù)據(jù)剛接收到一半兒。
2、讀完以后,清零之前,如果進來新的數(shù)據(jù)怎么辦?
所以,比較穩(wěn)妥的方法是,一次只讀一個數(shù)據(jù),讀一次,清除該數(shù)據(jù)所占的位置。所以這需要一個變量,來記錄數(shù)據(jù)頭在這個數(shù)組中的位置。
第二,當有新數(shù)據(jù)來的時候,要知道它能放在哪,所以要有一個變量,來記錄數(shù)據(jù)尾在哪。
第三,如果有必要,你可以定義一個變量來記錄數(shù)據(jù)長度,存入的時候加一,取出的時候減一。
第四,也是比較重要的,如果數(shù)據(jù)尾已經(jīng)是a[29]了,下一個數(shù)據(jù)放哪?整個數(shù)組都清掉?NO,假設(shè)此時a[0]~a[10]已經(jīng)被取出了,數(shù)據(jù)頭變成了a[11]。那么新的數(shù)據(jù)尾變成a[0],即當數(shù)據(jù)尾大于等于30的時候,變成0.
如此一來,相當于把這個數(shù)組的頭和尾連了起來,成了一個封閉的環(huán),這種處理方式,就叫做串口的循環(huán)隊列。只要確保數(shù)組夠大,處理速度夠快,那么頭和尾就不會撞上。當然,程序上也要對這種意外情況做一個處理。以下圖片來自網(wǎng)絡(luò):

下面是代碼,核心的部分都在這,復(fù)制粘貼一下,基本就可以了。
首先是定義一個結(jié)構(gòu)體,關(guān)于數(shù)據(jù)頭、數(shù)據(jù)尾、數(shù)組的:
typedef struct
{
u16 Head;
u16 Tail;
u16 Length;
u8 Rsv_DAT[50];
}ringbuff_t;
ringbuff_t Ringbuff;
然后是結(jié)構(gòu)體初始化:
void ringbuff_init(void)
{
Ringbuff.Head = 0;
Ringbuff.Tail = 0;
Ringbuff.Length = 0;
}
然后是存入數(shù)據(jù)的操作,把這個函數(shù)放進串口接收中斷就行:
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;
}
}
然后是取出數(shù)據(jù)的操作:
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]);
讀操作的函數(shù)里,還可以增加一個操作,就是讀出以后,把該位置數(shù)據(jù)清零,這個看個人需要。
以上,就是串口循環(huán)隊列的一個簡介,如果有寫的不好的,歡迎留言指正。當然,方法千千萬,不一定只能用這種。最后,借用流浪地球的一句經(jīng)典臺詞作為結(jié)尾:
方法千萬條,穩(wěn)定第一條。
代碼不規(guī)范,碼農(nóng)兩行淚。
-
STM32
+關(guān)注
關(guān)注
2310文章
11172瀏覽量
373797 -
串口
+關(guān)注
關(guān)注
15文章
1623瀏覽量
82990 -
代碼
+關(guān)注
關(guān)注
30文章
4972瀏覽量
74095
原文標題:基于STM32的串口循環(huán)隊列
文章出處:【微信號:gh_c472c2199c88,微信公眾號:嵌入式微處理器】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
RDMA設(shè)計43:隊列刪除及連接斷開功能測試
RDMA設(shè)計25:隊列管理模塊之發(fā)送模塊詳細設(shè)計分析
RDMA設(shè)計26:隊列管理模塊設(shè)計之接收隊列模塊詳細分析
RDMA設(shè)計24:隊列管理模塊設(shè)計
RDMA設(shè)計17:隊列管理模塊設(shè)計2
C語言的循環(huán)隊列
NVMe高速傳輸之擺脫XDMA設(shè)計54:如何測試隊列管理功能2
【瑞薩RA6E2地奇星開發(fā)板試用】+ 4.使用循環(huán)隊列將串口接收到的數(shù)據(jù)一個不丟的發(fā)送出去
NVMe高速傳輸之擺脫XDMA設(shè)計53:如何測試隊列管理功能
優(yōu)先級隊列介紹
基于環(huán)形隊列的UART收發(fā)回顯實驗
串口的循環(huán)隊列是什么?
評論