14 - FreeRTOS隊列

FreeRTOS隊列

  • 隊列是主要的任務間通訊方式。可以在任務與任務間、中斷和任務間傳送信息。大多數情況下,隊列用於具有線程保護的FIFO(先進先出)緩衝區:新數據放在隊列的後面。當然,數據也可以放在隊列的前面,在下一篇講隊列API函數時,會涉及到數據的存放位置。

使用模型:最簡單、最靈活

  • 通常情況下,魚和熊掌是不可兼得的,但FreeRTOS的隊列用戶模型管理卻兼顧簡單和靈活。發送到隊列的消息是通過拷貝實現的,這意味着隊列存儲的數據是原數據,而不是原數據的引用。FreeRTOS隊列具有以下特性:
  1. C變量(整形、簡單結構體等等)中的簡單信息可以直接傳送到隊列。這樣就不需要爲信息分配緩存也不需要再進行什麼拷貝工作。同樣的,信息可以直接從隊列讀取到C變量中。用直接拷貝的方法入隊,可以允許任務立即覆寫已經入隊的變量或者緩存,實際上隊列中已經保存了這些變量或緩衝區攜帶的信息。因爲變量中的數據內容是以拷貝的方式入隊的,所以變量自身是允許重複使用的。發送信息的任務和接收信息的任務並不需要就哪個任務擁有信息、哪個任務釋放信息(當信息不再使用時)而達成一致。
  2. 隊列是通過拷貝傳遞數據的,但這並不妨礙隊列通過引用來傳遞數據。當信息的大小到達一個臨界點後,逐字節拷貝整個信息是不實際的,可以定義一個指針隊列,只拷貝指向消息的指針來代替整個信息拷貝。FreeRTOS+UDP IP棧例程正是使用這種方法向FreeRTOS協議棧傳遞大量網絡數據的。
  3. 隊列內存區域分配由內核完成。
  4. 變長消息可以通過定義保存一個結構體變量的隊列實現,結構體一個成員指向要入隊的緩存,另一個成員保存緩存數據的大小。
  5. 單個隊列可以接收不同類型信息,並且信息可以來自不同的位置。通過定義保存一個結構體變量的隊列來實現,結構體的一個成員保存信息類型,另一個成員保存信息數據(或者指向信息數據的指針)。數據如何解讀取決於信息類型。管理FreeRTOS+UDP IP棧的任務正是使用單個隊列接收ARP定時器時間通知、以太網硬件傳送來的數據包、從應用層傳送來的數據包、網絡關閉事件等等。
  6. 天生適用於那些內存保護(MPU)場合。一個具有內存區域保護的任務可以向另一個具有內存區域保護的任務傳遞數據,因爲調用隊列發送函數會引起RTOS提升微控制器特權級別。只有RTOS(具有所有特權)纔可以訪問隊列存儲區域。
  7. 在中斷函數中使用獨立的API。將RTOS任務API和中斷服務例程API分來實現意味着可以避免執行時的上下文調用檢查開銷,還意味着在大多數情況下,與其它RTOS產品相比,用戶創建中斷服務例程會更簡單。
  8. API函數很簡單。

隊列阻塞

  • API函數允許指定阻塞時間。

  • 每當任務企圖從一個空的隊列讀取數據時,任務會進入阻塞狀態(這樣任務不會消耗任何CPU時間並且另一個任務可以運行)直到隊列中出現有效數據或者阻塞時間到期。

  • 每當任務企圖向一個滿的隊列寫數據時,任務會進入阻塞狀態,直到隊列中出現有效空間或者阻塞時間到期。

  • 如果多個任務阻塞在一個隊列上,那麼最高優先級別的任務會第一個解除阻塞。

    注:中斷程序中絕不可以使用不帶“FromISR”結尾的API函數!
    
  • 總結一下隊列的基本用法:

  1. 定義一個隊列句柄變量,用於保存創建的隊列:xQueueHandle xQueue1;
  2. 使用API函數xQueueCreate()創建一個隊列。
  3. 如果希望使用先進先出隊列,使用API函數xQueueSend()或xQueueSendToBack()向隊列投遞隊列項。如果希望使用後進先出隊列,使用API函數xQueueSendToFront()向隊列投遞隊列項。如果在中斷服務程序中,切記使用它們的帶中斷保護版本。
  4. 使用API函數xQueueReceive()從隊列讀取隊列項,如果在中斷服務程序中,切記使用它們的帶中斷保護版本。
  • 以上使用的API函數將在下一篇文章中介紹。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章