FreeRTOS 隊列

FreeRTOS 隊列

Queue 簡介

數據存儲

FreeRTOS的Queue是個FIFO先入先出的緩衝區。隊列長度在隊列創建時被指定。
在這裏插入圖片描述
上圖展示了隊列的使用方法。

在FreeRTOS的Queue實現中,採用的是複製而不是引用。這樣的好處是:

  • 數據可以直接發送到隊列中保存,而不用擔心原數據會被覆蓋或修改
  • 不用事先開闢緩衝區存儲,直接複製到隊列即可
  • 發送和接收是獨立的
  • 也可以直接將指針作爲元素髮送,可以看做是引用
  • FreeRTOS負責給數據分配存儲空間
  • 某些內存保護系統中,RAM的訪問是被限制的。發送和接收任務不一定都可以訪問RAM

多任務訪問

隊列可以被任何任務或者中斷服務函數訪問。任一任務都可以寫入隊列和讀取隊列。

讀取等待

當任務企圖讀取隊列時,可以指定一個阻塞時間等待數據。在這段時間中,任務會被阻塞。當隊列中有新數據或者超時,被阻塞的任務會自動進入就緒態。一個隊列會有很多受衆,但是在這種情況下,只有一個任務會解除阻塞態,這個任務是所有等待任務中優先級最高的那個。如果任務優先級相同,則選取已經等待時間較長的那個任務解除阻塞。

寫入等待

當隊列已滿,可以指定一個阻塞時間等待寫入。同樣,有可能存在多個任務等待寫入隊列。這時,只有一個任務可以解除阻塞。這個任務通常是優先級最高的任務,如果優先極相同,則選取等待時間最長的任務解除阻塞。

多隊列阻塞

隊列可以組成集合,一個任務可以等待一個隊列集中所有的隊列數據同時就緒。

APl

xQueueCreate() 創建隊列

隊列可以用句柄表示,數據類型是QueueHandle_t
在這裏插入圖片描述
在FreeRTOS V9.0 中,xQueueCreateStatic()可以用來創建一個靜態隊列,他的大小在編譯就被指定。

xQueueSendToBack() and xQueueSendToFront() 插入元素

這兩個API指定數據位置,插入隊首還是隊尾
xQueueSend()等同於xQueueSendToBack()
注意,這兩個函數不能在中斷中調用!!,如需中斷中調用,須使用xQueueSendToFrontFromISR() 和 xQueueSendToBackFromISR()
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

xQueueReceive() 接收數據

注意,不能在中斷中使用! 中斷中須使用,xQueueReceiveFromISR()
在這裏插入圖片描述
在這裏插入圖片描述

uxQueueMessagesWaiting() 查詢隊列元素數

不能在中斷使用!!,替代:uxQueueMessagesWaitingFromISR()
在這裏插入圖片描述
在這裏插入圖片描述

示例

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
圖解
在這裏插入圖片描述

  • Receiver優先級最高首先搶佔CPU,由於隊列爲空,Receiver隨即進入阻塞態
  • Sender2發送數據到隊列
  • Receiver檢測到隊列中有數據,開始讀數。隊列隨即變空,Receiver又進入阻塞態
  • Sender1發送數據到隊列
  • Receiver檢測到隊列中有數據,開始讀數。隊列隨即變空,Receiver又進入阻塞態

從多個數據源接收數據 Receiving Data From Multiple Sources

由於一個隊列可能接收來源不同的數據,如果我們想要知道每個數據的身份信息,一個較爲簡單的方式就是將結構體作爲隊列的元素,如下圖所示
在這裏插入圖片描述

  • eDataID代表數據身份信息
  • IDataValue則是數據值

示例

定義數據元素結構體:
在這裏插入圖片描述
創建發送任務:
在這裏插入圖片描述
創建接收任務:
在這裏插入圖片描述
只有隊列滿時,纔會處理
在這裏插入圖片描述
圖解
在這裏插入圖片描述

  • t2時刻隊列已滿,此時Receiver從隊列中取出一個數據
  • t4時刻隊列出現一個空位,由於Sender1/2優先級相同,調度器將控制權交給等待時間最長的任務Sender1
  • t5時刻,Sender1將隊列填滿,Receiver開始取數據

處理大量的或者不同長度的數據 Working with Large or Variable Sized Data

處理大量數據

Queuing Pointers 隊列指針

如果數據量很大,那麼我們一般選擇傳遞指針而不是複製數據。傳遞指針對於處理時間和內存消耗都是高效的。但是,需要確保兩點:

  • 指針指向的存儲空間地址是有定義的
    指針指向的地址,一般來說,只要相應發送和接收任務纔可以寫入和讀取,而且需要是有效、連續的!
  • 指針指向的地址仍然有效
    任何時候不要把任務堆棧的地址作爲指針傳遞,因爲任務堆棧會在任務修改時自動釋放

示例

在這裏插入圖片描述
在這裏插入圖片描述

處理類型或長度不同的數據 Using a Queue to Send Different Types and Lengths of Data

將結構體和指針相結合,隊列可以傳遞不同類型的數據

示例 FreeRTOS+TCP/IP

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

從多個隊列中接收 Receiving From Multiple Queues

隊列集 Queue Sets

隊列集允許任務從多個隊列中接收數據而不用知道哪個有數據。隊列集並不比使用單一隊列傳遞結構體更加高效,所以隊列集一般只在必要的時候使用。

xQueueCreateSet() 創建隊列集

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

xQueueAddToSet() 添加到隊列集

將一個隊列或者信號量添加到隊列集
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

xQueueSelectFromSet() 從一個隊列集中讀取隊列句柄

在讀取數據前,我們需要先調用這個函數獲取集合中某個隊列或信號量的句柄,然後才能繼續讀取數據!!
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

示例 1

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

示例 2

隊列集中包含了二值信號量,uint32_t變量,指針
在這裏插入圖片描述

利用隊列創建郵箱 Using a Queue to Create a Mailbox

本文中,郵箱指的是長度爲1的隊列,之所以叫郵箱,是因爲他們作用相似

  • 發送-接收模式
  • 郵件可以被任一個任務或ISR讀取
    在這裏插入圖片描述

API

xQueueOverwrite() 隊列覆寫

用來發送數據到隊列,與xQueueSendToBack()的區別在於 可以覆寫
這個函數應該僅被用於隊列長度爲1的情況
注意!不能在中斷中使用!!
加粗樣式
在這裏插入圖片描述
示例
在這裏插入圖片描述

xQueuePeek() 不取出元素查看

在這裏插入圖片描述
示例
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章