淺析Free RTOS中Queue的應用

目錄

概述

1 認識Queue

1.1 Queue定義

1.2?FreeRTOS中的Queue

1.3 Queue狀態

1.4?Queue內容

1.5 發送和接收Message

1.5.1 發送message

1.5.2 接收Message

2?Queue的特性

2.1 數據存儲

2.2?可被多任務存取

2.3?讀Queue時阻塞

2.4 寫Queue時阻塞

3?使用Queue

3.1?xQueueCreate() 函數

3.2?xQueueSendToBack() 與 xQueueSendToFront()函數

3.3 xQueueReceive()與 xQueuePeek() 函數

3.4?uxQueueMessagesWaiting() API 函數

4 一個案例

4.1 功能描述

4.2 定義Queue的變量

?4.3 創建Queue

4.4 應用Queue發送或者接收message

4.4.1 發送Message

4.4.2 接收Message

4.5 測試

5 結論


源代碼下載地址:

stm32-freeRTOS-queue資源-CSDN文庫

概述

本文主要介紹Queue的相關知識,包括Queue的定義,發送和接收消息的方式等內容。重點使用Free RTOS中Queue的接口,實現數據在不同task之間的發送和接收的案例,并在板卡上驗證該功能。

1 認識Queue

1.1 Queue定義

消息隊列是一個類似于緩沖區的對象。通過它,任務和ISR發送和接收消息,實現到數據的同學和同步。消息隊列小一個管道。它暫時保存來自發送者的消息,直到有意的接受者準備讀這些消息。這個臨時緩沖區把發送任務和接收任務隔開,即它必須同時釋放發送和接收消息的任務。

創建一個隊列,其應該具備這些要素:

1)分配一個相關的隊列控制塊(QCB)

2)? 一個消息隊列名

3)一個唯一的ID

4) 存儲器緩沖區

5)隊列長度

6)最大消息長度

7)一個或者多個任務等待列表

1.2?FreeRTOS中的Queue

FreeRTOS 的應用程序由一組獨立的任務構成——每個任務都是具有獨立權限的小程序。這些獨立的任務之間很可能會通過相互通信以提供有用的系統功能。FreeRTOS 中所有的通信與同步機制都是基于隊列實現的

1.3 Queue狀態

發送消息狀態:

step -1: 當一個任務發送消息給一個消息隊列,消息會直接發送給阻塞的任務

step -2: 阻塞任務進入就緒態或者運行態,此時消息隊列為空,發送消息成功

step -3: 如果另外的消息送到相同的隊列,而且沒有任務在消息隊列的任務等待列表中等候,此時消息隊列的狀態為非空

step -4: 當消息數據達到隊列總數是,隊列為滿,此時隊列無法接收任何消息。

1.4?Queue內容

消息隊列可以用來接收和發送多種數據,有些消息的數據可能相當長,這種情況下,可使用發送數據指針的方式。

1.5 發送和接收Message

1.5.1 發送message

方式一: 先進先出FIFO次序Queue

方式一: 先進后出LIFO次序Queue

1.5.2 接收Message

方式一: 任務等待類表-先進先出FIFO次序Queue

方式二: 任務等待類表-先進后出LIFO次序Queue

2?Queue的特性

2.1 數據存儲

隊列可以保存有限個具有確定長度的數據單元。隊列可以保存的最大單元數目被稱為隊列的“深度”。在隊列創建時需要設定其深度和每個單元的大小。通常情況下,隊列被作為 FIFO(先進先出)使用,即數據由隊列尾寫入,從隊列首讀出。當然,由隊列首寫入也是可能的。往隊列寫入數據是通過字節拷貝把數據復制存儲到隊列中;從隊列讀出數據使得把隊列中的數據拷貝刪除。

2.2?可被多任務存取

隊列是具有自己獨立權限的內核對象,并不屬于或賦予任何任務。所有任務都可以向同一隊列寫入和讀出。一個隊列由多方寫入是經常的事,但由多方讀出倒是很少遇到。

2.3?讀Queue時阻塞

當某個任務試圖讀一個隊列時,其可以指定一個阻塞超時時間。在這段時間中,如果隊列為空,該任務將保持阻塞狀態以等待隊列數據有效。當其它任務或中斷服務例程往其等待的隊列中寫入了數據,該任務將自動由阻塞態轉移為就緒態。當等待的時間超過了指定的阻塞時間,即使隊列中尚無有效數據,任務也會自動從阻塞態轉移為就緒態。

由于隊列可以被多個任務讀取,所以對單個隊列而言,也可能有多個任務處于阻塞狀態以等待隊列數據有效。這種情況下,一旦隊列數據有效,只會有一個任務會被解除阻塞,這個任務就是所有等待任務中優先級最高的任務。而如果所有等待任務的優先級相同,那么被解除阻塞的任務將是等待最久的任務。

2.4 寫Queue時阻塞

同讀隊列一樣,任務也可以在寫隊列時指定一個阻塞超時時間。這個時間是當被寫隊列已滿時,任務進入阻塞態以等待隊列空間有效的最長時間。

由于隊列可以被多個任務寫入,所以對單個隊列而言,也可能有多個任務處于阻塞狀態以等待隊列空間有效。這種情況下,一旦隊列空間有效,只會有一個任務會被解除阻塞,這個任務就是所有等待任務中優先級最高的任務。而如果所有等待任務的優先級相同,那么被解除阻塞的任務將是等待最久的任務。

3?使用Queue

3.1?xQueueCreate() 函數

隊列在使用前必須先被創建。隊列由聲明為 xQueueHandle 的變量進行引用。 xQueueCreate()用于創建一個隊列,并返回一個 xQueueHandle 句柄以便于對其創建的隊列進行引用。當創建隊列時, FreeRTOS 從堆空間中分配內存空間。分配的空間用于存儲隊列數據結構本身以及隊列中包含的數據單元。如果內存堆中沒有足夠的空間來創建隊列,xQueueCreate()將返回 NULL。第五章會有關于內存堆管理的更多信息。

xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength,
unsigned portBASE_TYPE uxItemSize );
參數名稱描述
uxQueueLength隊列能夠存儲的最大單元數目,即隊列深度
uxItemSize隊列中數據單元的長度,以字節為單位
返回值描述
NULL表示沒有足夠的堆空間分配給隊列而導致創建失敗
非 NULL表示隊列創建成功。此返回值應當保存下來,以作為 操作此隊列的句柄

3.2?xQueueSendToBack() 與 xQueueSendToFront()函數

1) xQueueSendToBack()用于將數據發送到隊列尾;

2) xQueueSendToFront()用于將數據發送到隊列首。

3) xQueueSend()完全等同于 xQueueSendToBack()。

但 切 記 不 要 在 中 斷 服 務 例 程 中 調 用 xQueueSendToFront() 或xQueueSendToBack()。

中斷模式使用的發送消息函數:

1)xQueueSendToFrontFromISR()

2)xQueueSendToBackFromISR()

portBASE_TYPE xQueueSendToFront( xQueueHandle xQueue,
const void * pvItemToQueue,
portTickType xTicksToWait );
portBASE_TYPE xQueueSendToBack( xQueueHandle xQueue,
const void * pvItemToQueue,
portTickType xTicksToWait );
參數值描述
xQueue目標隊列的句柄。這個句柄即是調用 xQueueCreate()創建該隊 列時的返回值。
pvItemToQueue發送數據的指針。其指向將要復制到目標隊列中的數據單元。 由于在創建隊列時設置了隊列中數據單元的長度,所以會從該指 針指向的空間復制對應長度的數據到隊列的存儲區域。
xTicksToWait阻塞超時時間。如果在發送時隊列已滿,這個時間即是任務處于 阻塞態等待隊列空間有效的最長等待時間。如 果 xTicksToWait 設 為 0 , 并 且 隊 列 已 滿 , 則xQueueSendToFront()與 xQueueSendToBack()均會立即返回。阻塞時間是以系統心跳周期為單位的,所以絕對時間取決于系統心跳頻率。常量 portTICK_RATE_MS 可以用來把心跳時間單位轉換為毫秒時間單位。如 果 把 xTicksToWait 設 置 為 portMAX_DELAY , 并 且 在FreeRTOSConig.h 中設定 INCLUDE_vTaskSuspend 為 1,那么阻塞等待將沒有超時限制。

返回值介紹

返回值描述
pdPASS返回 pdPASS 只會有一種情況,那就是數據被成功發送到隊列<中。如果設定了阻塞超時時間(xTicksToWait 非 0),在函數返回之前任務將被轉移到阻塞態以等待隊列空間有效—在超時到來前能夠將數據成功寫入到隊列,函數則會返回 pdPASS。
errQUEUE_FULL如 果 由 于 隊 列 已 滿 而 無 法 將 數 據 寫 入 , 則 將 返 errQUEUE_FULL。如果設定了阻塞超時時間( xTicksToWait 非 0),在函數返回之前任務將被轉移到阻塞態以等待隊列空間有效。但直到超時也沒有其它任務或是中斷服務例程讀取隊列而騰出空間,函數則會返回 errQUEUE_FULL。

3.3 xQueueReceive()與 xQueuePeek() 函數

xQueueReceive():?用于從隊列中接收(讀取)數據單元。接收到的單元同時會從隊列中刪除xQueuePeek():也是從從隊列中接收數據單元,不同的是并不從隊列中刪出接收到的單元。?其從隊列首接收到數據后,不會修改隊列中的數據,也不會改變數據在隊列中的存儲序順。

注意:

切記不要在中斷服務例程中調用 xQueueRceive()和 xQueuePeek()。

中斷模式下使用的接收函數:?xQueueReceiveFromISR()

參數介紹

參數值描述
xQueue目標隊列的句柄。這個句柄即是調用 xQueueCreate()創建該隊 列時的返回值。
pvBuffer接收緩存指針。其指向一段內存區域,用于接收從隊列中拷貝來 的數據。數據單元的長度在創建隊列時就已經被設定,所以該指針指向的 內存區域大小應當足夠保存一個數據單元。
xTicksToWait阻塞超時時間。如果在發送時隊列已滿,這個時間即是任務處于 阻塞態等待隊列空間有效的最長等待時間。如 果 xTicksToWait 設 為 0 , 并 且 隊 列 已 滿 , 則xQueueSendToFront()與 xQueueSendToBack()均會立即返回。阻塞時間是以系統心跳周期為單位的,所以絕對時間取決于系統心跳頻率。常量 portTICK_RATE_MS 可以用來把心跳時間單位轉換為毫秒時間單位。如 果 把 xTicksToWait 設 置 為 portMAX_DELAY , 并 且 在FreeRTOSConig.h 中設定 INCLUDE_vTaskSuspend 為 1,那么阻塞等待將沒有超時限制。

?返回值

返回值描述
pdPASS返回 pdPASS 只會有一種情況,那就是數據被成功發送到隊列<中。如果設定了阻塞超時時間(xTicksToWait 非 0),在函數返回之前任務將被轉移到阻塞態以等待隊列空間有效—在超時到來前能夠將數據成功寫入到隊列,函數則會返回 pdPASS。
errQUEUE_FULL如 果 由 于 隊 列 已 滿 而 無 法 將 數 據 寫 入 , 則 將 返 errQUEUE_FULL。如果設定了阻塞超時時間( xTicksToWait 非 0),在函數返回之前任務將被轉移到阻塞態以等待隊列空間有效。但直到超時也沒有其它任務或是中斷服務例程讀取隊列而騰出空間,函數則會返回 errQUEUE_FULL。

3.4?uxQueueMessagesWaiting() API 函數

uxQueueMessagesWaiting(): 用于查詢隊列中當前有效數據單元個數。

注意:不要在中斷服務例程中調用 uxQueueMessagesWaiting()。

中斷模式下使用的函數: uxQueueMessagesWaitingFromISR()。

unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle xQueue );
參數值描述
xQueue被查詢隊列的句柄。這個句柄即是調用 xQueueCreate()創建該隊列時 的返回值。

返回值:

返回值描述
非0當前隊列中保存的數據單元個數
0表明隊列為空


4 一個案例

4.1 功能描述

使用STM32H7平臺,基于Free RTOS平臺,創建3個Task, 2個Task發送Message, 一個Task接收Message。

4.2 定義Queue的變量

代碼第6行: 定義Queue的屬性

代碼第7行: 創建Queue ID 變量

代碼第9~12行: 定義消息體數據結構

代碼第14~17行: 消息體內容

詳細代碼:

#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"const osMessageQueueAttr_t QueueInputSignalAttribute = {.name = "QueueTest"};
osMessageQueueId_t QueueTest;typedef struct {int id;int32_t value;
}Qdata_stru;Qdata_stru queList[2] = {{1, 100},{2, 50},
};

?4.3 創建Queue

使用osMessageQueueNew創建一個Queue,?osMessageQueueNew函數在cmsis_os2.c中定義。其函數原型為:

osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr)

參數介紹:

參數名稱描述
msg_count整個消息隊列的長度
msg_size消息的字節大小
attr屬性

創建方法如下:

?詳細代碼:

void initTask( void )
{int ucQuequeLength= sizeof(Qdata_stru);QueueTest = osMessageQueueNew (10, ucQuequeLength, &QueueInputSignalAttribute);
}

注意:

創建Queue才能實現發送或者接收message

4.4 應用Queue發送或者接收message

4.4.1 發送Message

定義兩個Task,在該Task中實現消息發送功能

代碼第32行:發送message

代碼第33行:? 判斷message 是否發送成功

代碼第47行:發送message

代碼第48行:? 判斷message 是否發送成功

詳細代碼:

 void mainTask(void *argument)
{  osStatus_t status;	for(;;){status = osMessageQueuePut(QueueTest, &queList[0], NULL,100);if( status != osOK){printf("mainTask osStatus_t = %d \r\n",status);}osDelay(300);}
}void monitorTask(void *argument)
{osStatus_t status;	for(;;){status = osMessageQueuePut(QueueTest, &queList[1], NULL,100);if( status != osOK){printf(" monitorTask osStatus_t = %d \r\n",status);}osDelay(200);}
}

4.4.2 接收Message

定義一個Task,在該Task中僅僅實現接收其他Task發送的消息。

代碼第62行: 接收queue消息

代碼第64~69行: 根據 message ID解析消息

?詳細代碼:

void stateTask(void *argument)
{Qdata_stru recv_que;static int cnt = 0;for(;;){if( osOK == osMessageQueueGet(QueueTest, &recv_que, NULL, 100)){if( recv_que.id == 1){printf(" que 1: %d \r\n",recv_que.value);}else if( recv_que.id == 2) {printf(" que 2: %d \r\n",recv_que.value);}}cnt++;if( (cnt %10) == 0){HAL_GPIO_TogglePin(R_STATUS_GPIO_Port, R_STATUS_Pin);}osDelay(1);}
}

4.5 測試

編譯代碼,下載到板卡中,通過終端查看發送和接收消息的情況。打開串口終端,代碼運行后,log信息如下:

5 結論

消息隊列可以不同Task之間的通信,一個消息隊列可接收多個Task發送的消息,對于數據長度大于消息隊列數據長度的情況,可采用傳送指針的方式實現。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/12499.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/12499.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/12499.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

怎么把圖片上的字去掉

將圖片上的字去掉通常需要使用圖像編輯軟件或在線工具。以下是一些常用的方法和步驟&#xff1a; 使用Adobe Photoshop&#xff1a; 打開Photoshop&#xff0c;導入需要編輯的圖片。 選擇“橡皮擦工具”或“克隆圖章工具”。 如果使用“橡皮擦工具”&#xff0c;調整橡皮擦的…

YOLOv9改進策略 | 低照度圖像篇 | 2024最新改進CPA-Enhancer鏈式思考網絡(適用低照度、圖像去霧、雨天、雪天)

一、本文介紹 本文給大家帶來的2024.3月份最新改進機制&#xff0c;由CPA-Enhancer: Chain-of-Thought Prompted Adaptive Enhancer for Object Detection under Unknown Degradations論文提出的CPA-Enhancer鏈式思考網絡&#xff0c;CPA-Enhancer通過引入鏈式思考提示機制&am…

【提示學習論文】TCP:Textual-based Class-aware Prompt tuning for Visual-Language Model

TCP:Textual-based Class-aware Prompt tuning for Visual-Language Model&#xff08;CVPR2024&#xff09; 基于文本的類感知提示調優的VLMKgCoOp為baseline&#xff0c;進行改進&#xff0c;把 w c l i p w_{clip} wclip?進行投影&#xff0c;然后與Learnable prompts進行…

樹莓派|角速度和加速度傳感器

角速度傳感器和加速度傳感器是常見的慣性傳感器&#xff0c;常用于測量物體的旋轉和線性運動。 角速度傳感器&#xff08;Gyroscope&#xff09;用于測量物體繞三個軸&#xff08;X、Y、Z&#xff09;的旋轉速度或角速度。它可以提供關于物體在空間中的旋轉方向和角度變化的信…

時光知識付費系統,如何制定適合自己的課程?該如何做?

在線教育平臺的網課非常多&#xff0c;而且課程之間的相似度非常高&#xff0c;不同是教的老師不同。很多人在制定課程的時候&#xff0c;通常都是被廣告吸引的&#xff0c;之后發現課程不是自己想要的&#xff0c;并不適合自己。 想要制定適合自己的課程&#xff0c;首先要清楚…

計算機視覺與深度學習實戰:以Python為工具,基于特征匹配的英文印刷字符識別

注意:本文的下載教程,與以下文章的思路有相同點,也有不同點,最終目標只是讓讀者從多維度去熟練掌握本知識點。 下載教程:計算機視覺與深度學習實戰-以MATLAB和Python為工具_基于特征匹配的英文印刷字符識別_項目開發案例教程.pdf 一、引言 隨著人工智能技術的飛速發展,計…

用爬蟲解決問題

使用爬蟲解決問題是一個常見的技術手段&#xff0c;特別是在需要自動化獲取和處理大量網頁數據的情況下。以下是一個詳細的步驟說明&#xff0c;包括如何使用 Python 和常用的爬蟲庫&#xff08;如 requests 和 BeautifulSoup&#xff09;來構建一個簡單的爬蟲&#xff0c;解決…

matlab二次插值函數 interp2

在MATLAB中&#xff0c;interp2函數用于執行二維插值操作。該函數可以接受多種不同的插值方法&#xff0c;其中包括linear&#xff08;線性插值&#xff09;和nearest&#xff08;最臨近插值&#xff09;。這兩種插值方法的插值結果存在明顯的差異。 linear&#xff08;線性插值…

引用存儲復制屬性

當執行 this.tableDataSim.push(this.simForm) 時&#xff0c;將 this.simForm 對象添加到 this.tableDataSim 數組中。如果 this.simForm 是一個對象&#xff0c;并且 this.tableDataSim 數組中之前的對象是通過引用方式存儲的&#xff0c;那么之前的對象會被改變&#xff0c;…

使用 Python 和機器學習預測股票漲跌幅

使用 Tushare API 獲取深圳股市歷史數據 引言 這篇文章將會演示如何使用 Tushare Pro API 獲取深圳股市的歷史交易數據&#xff0c;并將數據保存到CSV文件中。Tushare 是一款提供實時和歷史金融市場的數據服務&#xff0c;支持多種語言&#xff0c;具有豐富的數據源和強大的功…

PXI/PXIe規格1553B總線測試模塊

面向GJB5186測試專門開發的1553B總線適配卡&#xff0c;支持4Mbps和1Mbps總線速率。該產品提供2個雙冗余1553B通道、1個測試專用通道、2個線纜測試通道。新一代的TM53x板卡除了支持耦合方式可編程、總線信號幅值可編程、共模電壓注入、總線信號波形采集等功能外&#xff0c;又新…

Python專題:十三、日期和時間(2)

datetime 模塊 today()函數 date類型 year month day

二分法的時間復雜度是logN

對數函數&#xff1a; &#xff08;a>0, a≠1&#xff0c; x>0&#xff09; 當αe時&#xff0c;記為yln x 當α10時&#xff0c;記為ylg x 當α2時&#xff0c;記為ylog x 其中x是自變量&#xff0c;函數的定義域是&#xff08;0&#xff0c;∞&#xff09;&#xff0c;…

【Flask框架】

6.Flask輕量型框架 6.1Flask簡介 python提供的框架中已經寫好了一個內置的服務器&#xff0c;服務器中的回應response行和頭已經寫好&#xff0c;我們只需要自己寫顯示在客戶端&#xff0c;的主體body部分。 ---------------------------------------------------------- Fla…

Blob數據類型

Blob&#xff08;Binary Large Object&#xff09;是一種二進制大對象的數據類型&#xff0c;用于存儲大量的二進制數據&#xff0c;比如圖片、視頻、音頻等。Blob對象通常用于處理從網絡上獲取的數據或者在瀏覽器中生成的數據&#xff0c;例如通過用戶上傳的文件、從服務器下載…

Android Studio無法使用Google翻譯問題記錄

背景 其實關于Google翻譯不能用的問題已經出現很久了&#xff0c;之前Google關掉了很多國內的一些Google服務&#xff0c;但是Google翻譯還是能用的&#xff0c;直到不知什么時候起&#xff0c;Google翻譯也不能用呢。 每次換電腦安裝完AS后第一件事就是下載插件 Settings-Pl…

探索智慧生活:百度Comate引領人工智能助手新潮流

文章目錄 百度Comate介紹1. 什么是百度Comate&#xff1f;主要特點 2. Comate的核心功能智能問答功能語音識別功能語音助手功能個性化服務 3. Comate 支持哪些語言&#xff1f; 使用教程(以vscode為例)1. 下載和安裝Comate3. 常用操作快捷鍵(windows) 使用體驗自然語言生成代碼…

Gitlab、Redis、Nacos、Apache Shiro、Gitlab、weblogic相關漏洞

文章目錄 一、Gitlab遠程代碼執行&#xff08;CVE-2021-22205&#xff09;二、Redis主從復制遠程命令執行三、Nacos認證繞過漏洞&#xff08;CVE-2021-29441&#xff09;四、Apache Shiro認證繞過漏洞&#xff08;CVE-2020-1957&#xff09;五、Gitlab任意文件讀取漏洞&#xf…

3.TCP的三次握手和四次揮手

一、前置知識 TCP是一種面向連接的、可靠的、基于字節流的傳輸層通信協議。在傳輸數據前通信雙方必須建立連接&#xff08;所謂連接&#xff0c;是指客戶端和服務端各自保存一份關于對方的信息&#xff0c;比如ip地址&#xff0c;端口號等&#xff09;。TCP通過三次握手建立一個…

從零開始:C++ String類的模擬實現

文章目錄 引言1.類的基本結構2.構造函數和析構函數3.基本成員函數總結 引言 在C編程中&#xff0c;字符串操作是非常常見且重要的任務。標準庫中的std::string類提供了豐富且強大的功能&#xff0c;使得字符串處理變得相對簡單。然而&#xff0c;對于學習C的開發者來說&#x…