日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

freeRtos学习笔(4)消息队列

發布時間:2025/4/16 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 freeRtos学习笔(4)消息队列 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

freeRtos學習筆記

freeRtos消息隊列

為什么要用消息隊列

消息隊列可以在任務與任務間,中斷與任務間傳遞信息。為什么不用全局數組?全局數組也可以傳遞信息,但是和消息隊列相比,消息隊列有一下優勢:

  • 全局數組需要解決多任務訪問沖突,需要加臨界區保護
  • 消息隊列可以實現超時機制
  • 消息隊列可以實現FIFO和LIFO機制

消息隊列創建

QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, /* 消息個數 */UbaseType_t uxItemSize); /* 消息大小 單位字節 */

函數 xQueueCreate 用于創建消息隊列。

  • 第 1 個參數是消息隊列支持的消息個數。
  • 第 2 個參數是每個消息的大小, 單位字節。
  • 返回值,如果創建成功會返回消息隊列的句柄,如果由于 FreeRTOSConfig.h 文件中 heap 大小不足,
    無法為此消息隊列提供所需的空間會返回 NULL。
    需要注意,消息隊列傳遞消息是消息本身被copy到消息隊列中,而不是傳遞指針,因此消息盡量不要太大,否則可能會影響實時性。

消息隊列刪除

void vQueueDelete(QueueHandle_t xQueue);

消息隊列刪除函數

  • 第 1 個參數是消息隊列
  • 注意,消息隊列刪除后,會釋放消息隊列的內存空間,但是如果刪除消息隊列時,有任務正在等待消息, 則不應
    該進行刪除操作

消息隊列發送

BaseType_t xQueueSend(QueueHandle_t xQueue, /* 消息隊列 */const void* pvItemToQueue, /* 要發送消息地址 */TickType_t xTicksToWait); /* 如果消息隊列已滿,等待超時時間 *//* 和xQueueSend函數作用相同,將消息添加在消息隊列尾部 */ BaseType_t xQueueSendToBack(QueueHandle xQueue, const void* pvItemToQueue,TickType_t xTicksToWait);/* 將消息添加在消息隊列頭部 */ BaseType_t xQueueSendToFront(QueueHandle_t xQueue,const void* pvItemToQueue,TickType_t xTicksToWait);/* 在中斷中發送消息,為了實時性,中斷中不應該存在堵塞或者延時,因此這里沒有發送超時參數 */ BaseType_t xQueueSendFromISR(QueueHandle_t xQueue, /* 消息隊列 */const void* pvItemToQueue, /* 要發送消息地址 */BaseType_t* pxHigherPriorityTaskWoken); /* 消息發送后,是否有更高級別的任務就緒 */BaseType_t xQueueSendToBackFromISR(QueueHandle_t xQueue, /* 消息隊列 */const void* pvItemToQueue, /* 要發送消息地址 */BaseType_t* pxHigherPriorityTaskWoken); /* 消息發送后,是否有更高級別的任務就緒 */BaseType_t xQueueSendToFrontFromISR(QueueHandle_t xQueue, /* 消息隊列 */const void* pvItemToQueue, /* 要發送消息地址 */BaseType_t* pxHigherPriorityTaskWoken); /* 消息發送后,是否有更高級別的任務就緒 */

消息隊列發送函數

  • 第 1 個參數是消息隊列句柄。
  • 第 2 個參數要傳遞數據地址,每次發送都是將消息隊列創建函數 xQueueCreate 所指定的單個消息大
    小復制到消息隊列空間中。
  • 在任務中 第 3 個參數是當消息隊列已經滿時,等待消息隊列有空間時的最大等待時間,單位系統時鐘節拍。
  • 在中斷中 第 3 個參數是消息發送后,是否有更高級別的任務就緒,如果有更高級別任務就緒(優先級更高的任務堵塞在消息接收上,這里發送了消息,導致任務從堵塞態轉變為就緒態),則pxHigherPriorityTaskWoken變為pdTRUE,然后在中斷結束處調用taskYIELD()進行任務調度。
  • 返回值, 如果消息成功發送返回 pdTRUE,否則返回 pdFALSE
    使用消息隊列函數要注意以下問題:
  • FreeRTOS 的消息傳遞是數據的復制,而不是傳遞的數據地址。
  • 用于任務代碼中調用的和在中斷服務程序中調用的函數不同,需要注意區分, 中斷服務程序中使用的是FromISR結尾的。
  • 任務代碼中,如果消息隊列已經滿且第三個參數為 0, 那么此函數會立即返回。
  • 任務代碼中,如果用戶將第三個參數配置為 portMAX_DELAY, 那么此發送函數會永久等待直到消息隊列有空間可以使用。
  • 消息隊列發送函數 xQueueSendToBack 和 xQueueSend是一樣的,實現的是 FIFO 方式的存取,函數 xQueueSendToFront 實現的是 LIFO 方式的讀寫。
  • 消息隊列接收

    BaseType_t xQueueReceive(QueueHandle_t xQueue, /* 消息隊列 */void* pvBuffer, /* 接收消息緩沖區 */TickType_t xTicksToWait); /* 如果消息隊列為空,等待超時時間 */BaseType_t xQueueReceiveFromISR(QueueHandle_t xQueue, /* 消息隊列 */void* pvBuffer, /* 接收消息緩沖區 */BaseType_t pxHigherPriorityTaskWoken); /* 消息接收后,是否有更高級別的任務就緒 */

    消息隊列接收函數

    • 第 1 個參數是消息隊列句柄。
    • 第 2 個參數消息接收地址,每次接收都是將消息隊列創建函數 xQueueCreate 所指定的單個消息大
      小復制到消息接收地址中。
    • 在任務中 第 3 個參數是當消息隊列為空時,等待消息隊列有消息的最大等待時間,單位系統時鐘節拍。
    • 在中斷中 第 3 個參數是消息接收后,是否有更高級別的任務就緒,如果有更高級別任務就緒(消息隊列已滿,且有優先級更高的任務堵塞在消息發送上,這里接收了消息,導致該任務從堵塞態轉變為就緒態),則pxHigherPriorityTaskWoken變為pdTRUE,然后在中斷結束處調用taskYIELD()進行任務調度。
    • 返回值, 如果接到到消息返回 pdTRUE,否則返回 pdFALSE。
      使用消息隊列函數要注意以下問題:
  • FreeRTOS 的消息傳遞是數據的復制,而不是傳遞的數據地址。
  • 用于任務代碼中調用的和在中斷服務程序中調用的函數不同,需要注意區分, 中斷服務程序中使用的是FromISR結尾的。
  • 任務代碼中,如果消息隊列已經滿且第三個參數為 0, 那么此函數會立即返回。
  • 任務代碼中,如果用戶將第三個參數配置為 portMAX_DELAY, 那么此接收函數會永久等待直到消息隊列有消息可以使用。
  • 消息隊列覆蓋式發送

    BaseType_t xQueueOverWrite(QueueHandle_t xQueue, /* 消息隊列 */const void* pvItemToQueue); /* 要發送消息地址 */BaseType_t xQueueOverWriteFromISR(QueueHandle_t xQueue, /* 消息隊列 */const void* pvItemToQueue, /* 要發送消息地址 */BaseType_t *pxHigherPriorityTaskWoken); /* 消息發送后,是否有更高級別的任務就緒 */

    消息隊列覆蓋式發送函數

    • 第 1 個參數是消息隊列句柄。
    • 第 2 個參數要傳遞數據地址,每次發送都是將消息隊列創建函數 xQueueCreate 所指定的單個消息大
      小復制到消息隊列空間中。
    • 在中斷中 第 3 個參數是消息發送后,是否有更高級別的任務就緒,如果有更高級別任務就緒(優先級更高的任務堵塞在消息接收上,這里發送了消息,導致任務從堵塞態轉變為就緒態),則pxHigherPriorityTaskWoken變為pdTRUE,然后在中斷結束處調用taskYIELD()進行任務調度。
    • 返回值, 只返回 pdTRUE
      使用消息隊列函數要注意以下問題:
  • FreeRTOS 的消息傳遞是數據的復制,而不是傳遞的數據地址。
  • 用于任務代碼中調用的和在中斷服務程序中調用的函數不同,需要注意區分, 中斷服務程序中使用的是FromISR結尾的。
  • 和普通的消息隊列發送函數相比,覆蓋式發送函數需要在消息隊列在創建時,消息個數一定要是1.在寫入的時候會直接寫入覆蓋當前數據,不會檢查消息隊列是否已滿。
  • 消息隊列消息預讀取

    BaseType_t xQueuePeek(QueueHandle_t xQueue,void *pvBuffer,TickType_t xTicksToWait);BaseType_t xQueuePeekFromISR(QueueHandle_t xQueue,void *pvBuffer);

    消息隊列預讀取函數

    • 第 1 個參數是消息隊列句柄。
    • 第 2 個參數消息接收地址,每次接收都是將消息隊列創建函數 xQueueCreate 所指定的單個消息大
      小復制到消息接收地址中。
    • 在任務中 第 3 個參數是當消息隊列為空時,等待消息隊列有消息的最大等待時間,單位系統時鐘節拍。
    • 返回值, 如果接到到消息返回 pdTRUE,否則返回 pdFALSE。
      使用消息隊列預讀取函數要注意以下問題:
  • FreeRTOS 的消息傳遞是數據的復制,而不是傳遞的數據地址。
  • 用于任務代碼中調用的和在中斷服務程序中調用的函數不同,需要注意區分, 中斷服務程序中使用的是FromISR結尾的。
  • 任務代碼中,如果消息隊列已經滿且第三個參數為 0, 那么此函數會立即返回。
  • 任務代碼中,如果用戶將第三個參數配置為 portMAX_DELAY, 那么此接收函數會永久等待直到消息隊列有消息可以使用。
  • 和消息隊列接收函數 xQueueReceive 相比,消息隊列預讀取函數只會將消息復制到消息接收緩沖區,并不會刪除消息隊列中的消息。
  • 獲取消息隊列消息個數

    /* 獲取消息隊列中可用消息個數 */ UBaseType_t uxQueueMessagesWaiting(const QueueHandle_t xQueue); UBaseType_t uxQueueMessagesWaitingFromISR(const QueueHandle_t xQueue);/* 獲取消息隊列剩余空間 */ UBaseType_t uxQueueSpacesAvailable( const QueueHandle_t xQueue );/* 獲取消息隊列是否為空 */ BaseType_t xQueueIsQueueEmptyFromISR( const QueueHandle_t pxQueue );/* 獲取消息隊列是否已滿 */ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t pxQueue );

    消息隊列集

    隊列集提供了一種機制,允許RTOS任務同時阻止(掛起)來自多個RTOS隊列或信號量的讀取操作。

    /* 創建消息隊列集 參數:uxEventQueueLength 隊列設置存儲在集合中包含的隊列和信號量上的事件。 uxEventQueueLength指定一次可以排隊的最大事件數。為了絕對確定事件沒有丟失,必須將uxEventQueueLength設置為添加到集合的隊列長度的總和,其中二進制信號量和互斥量的長度為1,計數信號量的長度由其最大計數值設置。例如:如果隊列集要保存長度為5的隊列,另一個長度為12的隊列和一個二進制信號量,則uxEventQueueLength應設置為(5 + 12 + 1)。如果隊列集要保存三個二進制信號量,則uxEventQueueLength應設置為(1 + 1 + 1)。如果隊列集要保存最大計數為5的計數信號量,以及最大計數為3的計數信號量,則uxEventQueueLength應設置為(5 + 3)。 返回:如果成功創建了隊列集,則返回創建的隊列集的句柄。否則返回NULL。*/ QueueSetHandle_t xQueueCreateSet( const UBaseType_t uxEventQueueLength );/* 將消息隊列或者信號量添加到消息隊列集中 */ BaseType_t xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore,QueueSetHandle_t xQueueSet );/* 獲取消息隊列集中哪一個IPC接收到了信號 */ QueueSetMemberHandle_t xQueueSelectFromSet( QueueSetHandle_t xQueueSet,const TickType_t xTicksToWait );QueueSetMemberHandle_t xQueueSelectFromSetFromISR( QueueSetHandle_t xQueueSet );

    先使用xQueueCreateSet()創建隊列集,然后使用xQueueAddToSet()將標準FreeRTOS隊列和信號量添加到集合中。最后使用xQueueSelectFromSet()來確定集合中包含的隊列或信號量中的哪一個(如果有)處于隊列讀取或信號量獲取操作成功的狀態。

    注意:
    將隊列和信號量添加到隊列集時,它們必須為空。
    添加到隊列集的每個隊列中的每個空間都需要額外的4個字節的RAM。因此,不應將最大計數值較高的計數信號量添加到隊列集。

    /* 下面是一個使用例子 *//* 消息隊列長度. */ #define QUEUE_LENGTH_1 10 #define QUEUE_LENGTH_2 10/* 二值信號量長度. */ #define BINARY_SEMAPHORE_LENGTH 1/* 消息隊列數據類型 */ #define ITEM_SIZE_QUEUE_1 sizeof( uint32_t ) #define ITEM_SIZE_QUEUE_2 sizeof( something_else_t )/* 消息隊列集長度. */ #define COMBINED_LENGTH ( QUEUE_LENGTH_1 + QUEUE_LENGTH_2 + BINARY_SEMAPHORE_LENGTH )void vAFunction( void ) {static QueueSetHandle_t xQueueSet;QueueHandle_t xQueue1, xQueue2, xSemaphore;QueueSetMemberHandle_t xActivatedMember;uint32_t xReceivedFromQueue1;something_else_t xReceivedFromQueue2;/* 創建消息隊列集 */xQueueSet = xQueueCreateSet( COMBINED_LENGTH );/* 創建消息隊列 */xQueue1 = xQueueCreate( QUEUE_LENGTH_1, ITEM_SIZE_QUEUE_1 );xQueue2 = xQueueCreate( QUEUE_LENGTH_2, ITEM_SIZE_QUEUE_2 );/* 創建二值信號量. */xSemaphore = xSemaphoreCreateBinary();/* 將消息隊列和二值信號量添加到隊列集中. */xQueueAddToSet( xQueue1, xQueueSet );xQueueAddToSet( xQueue2, xQueueSet );xQueueAddToSet( xSemaphore, xQueueSet );for( ;; ){/* 等待隊列集中有可以信號 隊列集中任意一消息隊列或者二值信號量有消息即可 堵塞時間200ms */xActivatedMember = xQueueSelectFromSet( xQueueSet, pdMS_TO_TICKS( 200 ) );/* 根據隊列集返回信息,分別對隊列集中不同IPC接收到消息進行處理 */if( xActivatedMember == xQueue1 ){xQueueReceive( xActivatedMember, &xReceivedFromQueue1, 0 );vProcessValueFromQueue1( xReceivedFromQueue1 );}else if( xActivatedQueue == xQueue2 ){xQueueReceive( xActivatedMember, &xReceivedFromQueue2, 0 );vProcessValueFromQueue2( &xReceivedFromQueue2 );}else if( xActivatedQueue == xSemaphore ){xSemaphoreTake( xActivatedMember, 0 );vProcessEventNotifiedBySemaphore();break;}else{/* 200ms堵塞處理. */}} }

    本文參考 freertos官方文檔 https://freertos.org/a00110.html
    《安富萊 STM32-V6 開發板 FreeRTOS 教程》

    總結

    以上是生活随笔為你收集整理的freeRtos学习笔(4)消息队列的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。