在數(shù)據(jù)結(jié)構(gòu)中有一種很重要的數(shù)據(jù)結(jié)構(gòu)叫做隊(duì)列,其特點(diǎn)是數(shù)據(jù)先進(jìn)先出。在FreeRTOS中也有一類隊(duì)列,我們利用這類隊(duì)列在FreeRTOS中實(shí)現(xiàn)任務(wù)與任務(wù)間的消息傳遞,所以也可以稱之為消息隊(duì)列。
隊(duì)列是任務(wù)間通信的主要形式。它們可以用于在任務(wù)之間以及中斷和任務(wù)之間發(fā)送消息。在大多數(shù)情況下,它們作為線程安全的 FIFO(先進(jìn)先出)緩沖區(qū)使用,新數(shù)據(jù)被發(fā)送到隊(duì)列的后面, 盡管數(shù)據(jù)也可以發(fā)送到前面。(拷貝自FreeRTOS開發(fā)者文檔)
隊(duì)列通過這樣子的結(jié)構(gòu)在任務(wù)間單方向傳遞消息。
在FreeRTOS的API引用文檔中我們可以看到隊(duì)列的控制函數(shù)。
我們在文檔中找到隊(duì)列創(chuàng)建函數(shù)(動(dòng)態(tài))
首先我們需要在程序中包含入queue.h文件才能使用隊(duì)列。
其次和之前幾期的操作一樣,我們需要在FreeRTOSConfig.h文件中需要配置相對應(yīng)的宏以激活該創(chuàng)建隊(duì)列的構(gòu)造函數(shù)。
xQueueCreate的參數(shù)有兩個(gè),首先是uxQueueLength隊(duì)列可同時(shí)容納的最大項(xiàng)目數(shù)簡而言之也就是:這個(gè)隊(duì)列有多長。
其次是uxItemSize,顧名思義是每一個(gè)項(xiàng)目(每個(gè)小塊塊)能存儲(chǔ)多少數(shù)據(jù)(字節(jié))
最后要強(qiáng)調(diào)的是,這個(gè)函數(shù)的返回值是QueueHandle_t,即以句柄的形式返回,因此我們創(chuàng)建任務(wù)的時(shí)候也需要以句柄變量接收其返回值。
我們在啟動(dòng)函數(shù)中加入我們創(chuàng)建隊(duì)列的函數(shù),其長度為1,每個(gè)項(xiàng)目的大小為一個(gè)字節(jié)。
我們接著在API引用文檔中找到關(guān)于隊(duì)列發(fā)送的函數(shù)(如上)。
發(fā)送的函數(shù)平平無奇,但是有幾點(diǎn)需要注意;
首先是發(fā)布項(xiàng)目按副本排隊(duì)而不是引用指針,指的是我們傳入的數(shù)據(jù)是先拷貝的臨時(shí)變量傳入,而并非我們傳入數(shù)據(jù)的地址,我想這樣子是為了避免在接收端時(shí)對數(shù)據(jù)進(jìn)行修改導(dǎo)致錯(cuò)誤。
其次是該函數(shù)不能在中斷函數(shù)中調(diào)用(有專門的函數(shù)是在中斷中發(fā)布項(xiàng)目的)
函數(shù)參數(shù)中的第三項(xiàng)xTicksWait簡單的理解就是可等待的最大時(shí)間,我們?nèi)绻覀兊年?duì)列已滿則嘗試等待,超過一定周期認(rèn)為超時(shí)則項(xiàng)目發(fā)布失敗。
我們在按鈕檢測任務(wù)中編寫:按下按鈕2時(shí)向隊(duì)列中放入字符p(p初始值為‘a(chǎn)’),每按下這個(gè)按鈕,p的值遞增。
還有一個(gè)按鈕3,按下按鈕3則在隊(duì)列中讀取一則消息,并打印出來。
void Get_info(void * pvParameters)
{
unsigned char p = 'a';
unsigned char r;
while(1)
{
unsigned char key = KEY_Scan(0);
BaseType_t err;
if(key==1)
{
memset(informationbuff,0,400);
vTaskGetRunTimeStats(informationbuff);
printf("%srn",informationbuff);
}
if(key==2)
{
printf("Key_2 Pressrn");
if(KeyNumberHandler!=NULL)//隊(duì)列句柄有效
{
err = xQueueSend(KeyNumberHandler,&p,10);
p++;
if(err!=pdTRUE)
{
printf("Send Fail rn");
}
else
{
printf("Send %c Successrn",p);
}
}
}
if(key==3)
{
printf("Key 3 Pressrn");
if(KeyNumberHandler!=NULL)//隊(duì)列句柄有效
{
xQueueReceive(KeyNumberHandler,&r,10);
printf("Queue Receive:%c rn",r);
r = '?';//清空
}
}
vTaskDelay(10);
}
}
我們在按鈕檢測任務(wù)中加入按鈕2和按鈕3的情況,并且定義了一個(gè)變量err來檢測我們的隊(duì)列是否添加成功,我們觀察串口并看看打印情況。
可以看到,我們按下按鈕2,成功將 ‘b’ 消息送入隊(duì)列(我們是先p++再送入隊(duì)列的)
我們再繼續(xù)按下按鈕2,由于隊(duì)列的長度為1,且隊(duì)列的項(xiàng)目并沒有出隊(duì)列,因此串口會(huì)提示送入隊(duì)列失敗。
此時(shí)p等于 ' c ',我們按下按鈕3,讓數(shù)據(jù)出隊(duì)列,并且再按下一次按鈕3讀取是否有數(shù)據(jù)。
可以看到,讀取隊(duì)列之后隊(duì)列的內(nèi)容將被釋放,后續(xù)的內(nèi)容將前進(jìn)。之后我們再按下按鈕2 ,此時(shí)就可以向隊(duì)列中送入數(shù)據(jù)(我多按了一下)。
除此之外,F(xiàn)reeRTOS中還有一個(gè)函數(shù)為xQueueOverwrite,傳入?yún)?shù)除了沒有阻塞時(shí)間之外和xQueueSend一樣,它的作用為將消息送入隊(duì)列,如果沒有空間則覆蓋最后一個(gè)空間,我們將按鈕2中的函數(shù)換為該函數(shù)再試試。
我們每次送入隊(duì)列都成功,因?yàn)樗鼤?huì)把隊(duì)列的最后一個(gè)項(xiàng)目覆蓋掉。
關(guān)于隊(duì)列的介紹就到此啦,具體的API可以上FreeRTOS的官網(wǎng)查看參考文檔。
-
fifo
+關(guān)注
關(guān)注
3文章
384瀏覽量
43461 -
FreeRTOS
+關(guān)注
關(guān)注
12文章
483瀏覽量
61849 -
數(shù)據(jù)結(jié)構(gòu)
+關(guān)注
關(guān)注
3文章
569瀏覽量
40063 -
隊(duì)列
+關(guān)注
關(guān)注
1文章
46瀏覽量
10877 -
STM32F407
+關(guān)注
關(guān)注
15文章
187瀏覽量
29288
發(fā)布評論請先 登錄
相關(guān)推薦
評論