第十一章 CMSIS-RTOS2消息隊列

描述

消息 傳遞是線程之間的另一種基本通信模型。在消息傳遞模型中,一個線程顯式發送數據,而另一個線程接收數據。該操作更像是某種I / O,而不是直接訪問要共享的信息。在CMSIS-RTOS中,此機制稱爲s 消息 隊列。數據以類似FIFO的操作從一個線程傳遞到另一個線程。使用消息隊列功能,您可以控制,發送,接收或等待消息。要傳遞的數據可以是整數或指針類型:

CMSIS-RTOS消息隊列

與內存池相比,消息隊列通常效率較低,但是可以解決更廣泛的問題。有時,線程沒有公共的地址空間,或者共享內存的使用引發了諸如互斥之類的問題。

注意:

可以從中斷服務例程中調用函數osMessageQueuePut,osMessageQueueGet,osMessageQueueGetCapacity,osMessageQueueGetMsgSize,osMessageQueueGetCount,osMessageQueueGetSpace。

有關RTX5配置選項, 請參閱消息隊列配置。


數據結構

/// /消息隊列結構體.
typedef struct {
  const char                *name;      ///< 消息隊列的名稱
  uint32_t                   attr_bits; ///< 屬性位
  void                      *cb_mem;    ///< 控制塊內存
  uint32_t                   cb_size;   ///< 爲控制塊提供的內存大小
  void                      *mq_mem;    ///< 用於數據存儲的內存
  uint32_t                   mq_size;   ///< 爲數據存儲提供的內存大小
} osMessageQueueAttr_t;    
資料欄位
const char * 名稱 消息隊列的名稱

指向具有消息隊列對象的可讀名稱(在調試過程中顯示)的常量字符串。

默認值:NULL未指定名稱。

uint32_t attr_bits 屬性位

保留以備將來使用(必須將其設置爲“ 0”,以便將來兼容)。

void * cb_mem 控制塊存儲器

指向消息隊列控制塊對象的內存的指針。

默認值:NULL,以將自動動態分配用於消息隊列控制塊。

uint32_t cb_size 控制塊提供的內存大小

cb_mem傳遞的內存塊的大小(以字節爲單位)。對於RTX,最小值由osRtxMessageQueueCbSize定義(允許更高的值)。

默認值:0,因爲默認值是cb_mem不提供內存。

 

void * mq_mem 數據存儲存儲器

指向消息隊列數據的內存的指針。

默認值:NULL,以對內存池數據使用自動動態分配。

uint32_t mq_size 提供的用於數據存儲的內存大小

通過mq_mem傳遞的內存塊的大小(以字節爲單位)。最小內存塊大小爲msg_count * msg_size(osMessageQueueNew函數的參數)。所述msg_size被向上舍入到雙偶數,確保存儲塊的32位對齊。

默認值:0,因爲默認值是mq_mem不提供內存。

 


主要函數API解析

1.創建並初始化消息隊列對象。

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

參數:

[in] msg_count 隊列中的最大消息數。
[in] msg_size 最大消息大小(以字節爲單位)。
[in] attr 消息隊列屬性;NULL:默認值。

返回值:

消息隊列ID以供其他功能參考,如果出錯,則爲NULL。

函數osMessageQueueNew創建並初始化消息隊列對象。如果發生錯誤,該函數將返回消息隊列對象標識符或NULL。

在內核使用osKernelInitialize初始化之後,可以調用該函數。在使用osKernelStart啓動RTOS內核之前,可以創建消息隊列對象。

消息隊列數據所需的內存總量至少爲msg_count * msg_size。所述msg_size被向上舍入到雙偶數,確保存儲塊的32位對齊。

從消息隊列分配的內存塊具有使用參數定義的固定大小msg_size。

注意:

不能從中斷服務程序中調用此函數。

代碼示例:

請參考 osMessageQueuePut();


2.獲取消息隊列對象的名稱。

const char * osMessageQueueGetName(osMessageQueueId_t mq_id)

參數:

mq_id 爲 osMessageQueueNew()獲得的消息隊列ID 。

返回值:

名稱爲以null終止的字符串。

出現錯誤時,函數osMessageQueueGetName返回指向由參數mq_idNULL標識的消息隊列的名稱字符串的指針。

注意:

不能從中斷服務程序中調用此函數。


3.消息放入隊列

osStatus_t osMessageQueuePut(
                                osMessageQueueId_t 	mq_id,
                                const void *     	msg_ptr,
                                uint8_t 	        msg_prio,
                                uint32_t 	        timeout 
                            )	

參數:

[in] mq_id osMessageQueueNew獲得的消息隊列ID 。
[in] msg_ptr 指向要放入隊列的消息的緩衝區的指針。
[in] msg_prio 消息優先級。
[in] timeout 超時值;如果沒有超時,則爲 0。

返回值:

狀態代碼,指示功能的執行狀態。

阻塞函數osMessageQueuePut將msg_ptr指向的消息放入參數mq_id指定的消息隊列中。參數msg_prio用於根據插入時消息的優先級(數字越高表示優先級越高)對消息進行排序。

參數timeout指定系統等待將消息放入隊列的時間。在系統等待時,正在調用此函數的線程進入BLOCKED狀態。

參數超時可以具有以下值:

  • timeout0時,該函數立即返回(即嘗試語義)。
  • 超時設置爲osWaitForever時,該函數將等待無限的時間,直到消息被傳遞爲止(即,等待語義)。
  • 所有其他值在內核滴答中指定一個超時時間(即,定時等待語義)。

可能的osStatus_t返回值:

  • osOK:消息已放入隊列。
  • osErrorTimeout:無法在給定的時間內將消息放入隊列(等待定時的語義)。
  • osErrorResource:隊列中沒有足夠的空間(嘗試語義)。
  • osErrorParameter:參數mq_idNULL或ISR中指定的無效非零超時。

注意:

如果參數超時設置爲0,則可以從中斷服務例程中調用。

代碼示例:

#include "cmsis_os2.h"                          // CMSIS RTOS header file

/*----------------------------------------------------------------------------
 *      Message Queue creation & usage
 *---------------------------------------------------------------------------*/

#define MSGQUEUE_OBJECTS 16                     // number of Message Queue Objects

typedef struct                                  // object data type
{
    uint8_t Buf[32];
    uint8_t Idx;
} MSGQUEUE_OBJ_t;

osMessageQueueId_t mid_MsgQueue;                // message queue id

osThreadId_t tid_Thread_MsgQueue1;              // thread id 1
osThreadId_t tid_Thread_MsgQueue2;              // thread id 2

void Thread_MsgQueue1(void *argument);          // thread function 1
void Thread_MsgQueue2(void *argument);          // thread function 2

int Init_MsgQueue(void)
{

    mid_MsgQueue = osMessageQueueNew(MSGQUEUE_OBJECTS, sizeof(MSGQUEUE_OBJ_t), NULL);
    if (mid_MsgQueue == NULL)
    {
        ; // Message Queue object not created, handle failure
    }

    tid_Thread_MsgQueue1 = osThreadNew(Thread_MsgQueue1, NULL, NULL);
    if (tid_Thread_MsgQueue1 == NULL)
    {
        return (-1);
    }
    tid_Thread_MsgQueue2 = osThreadNew(Thread_MsgQueue2, NULL, NULL);
    if (tid_Thread_MsgQueue2 == NULL)
    {
        return (-1);
    }

    return (0);
}

void Thread_MsgQueue1(void *argument)
{
    MSGQUEUE_OBJ_t msg;

    while (1)
    {
        ; // Insert thread code here...
        msg.Buf[0] = 0x55U;                                         // do some work...
        msg.Idx    = 0U;
        osMessageQueuePut(mid_MsgQueue, &msg, 0U, 0U);
        osThreadYield();                                            // suspend thread
    }
}

void Thread_MsgQueue2(void *argument)
{
    MSGQUEUE_OBJ_t msg;
    osStatus_t status;

    while (1)
    {
        ; // Insert thread code here...
        status = osMessageQueueGet(mid_MsgQueue, &msg, NULL, 0U);   // wait for message
        if (status == osOK)
        {
            ; // process data
        }
    }
}

4.從隊列中獲取消息

osStatus_t osMessageQueueGet(
                                osMessageQueueId_t    	mq_id,
                                void                   *msg_ptr,
                                uint8_t                *msg_prio,
                                uint32_t                timeout
                            )

參數:

[in] mq_id osMessageQueueNew獲得的消息隊列ID 。
[out] msg_ptr 指向從隊列中獲取消息的緩衝區的指針。
[out] msg_prio 指向消息優先級或NULL的緩衝區的指針。
[in] timeout 超時值;如果沒有超時,則爲 0。

返回值:

狀態代碼,指示功能的執行狀態。

函數osMessageQueueGet從參數mq_id指定的消息隊列中檢索一條消息,並將其保存到參數msg_ptr指向的緩衝區中。如果不是令牌{NULL},則消息優先級存儲到參數msg_prio

參數timeout指定系統等待從隊列中檢索消息的時間。在系統等待時,正在調用此函數的線程進入BLOCKED狀態。

參數超時可以具有以下值:

  • timeout0時,該函數立即返回(即嘗試語義)。
  • 超時設置爲osWaitForever時,該函數將等待無限的時間,直到檢索到消息爲止(即,等待語義)。
  • 所有其他值在內核滴答中指定一個超時時間(即,定時等待語義)。

可能的osStatus_t返回值:

  • osOK:已從隊列中檢索到消息。
  • osErrorTimeout:在給定的時間內無法從隊列中檢索消息(定時等待語義)。
  • osErrorResource:從隊列中什麼也得不到(嘗試語義)。
  • osErrorParameter:參數mq_idNULL或ISR中指定的無效非零超時。

注意:

如果參數超時設置爲0,則可以從中斷服務例程中調用。

代碼示例:

請參考osMessageQueuePut


5.獲取消息隊列中的最大消息數

uint32_t osMessageQueueGetCapacity(osMessageQueueId_t 	mq_id)

參數:

[in] mq_id osMessageQueueNew獲得的消息隊列ID 。

返回值:

最大消息數。

函數osMessageQueueGetCapacity返回錯誤消息中由參數mq_id指定的消息隊列對象中的最大消息數或0

注意:

可以從中斷服務程序中調用此函數。


6.獲取內存池中的最大消息大小

uint32_t osMessageQueueGetMsgSize(osMessageQueueId_t 	mq_id)

參數:

[in] mq_id osMessageQueueNew獲得的消息隊列ID 。

返回值:

最大消息大小(以字節爲單位)。

函數osMessageQueueGetMsgSize返回錯誤消息中由參數mq_id指定的消息隊列對象的最大消息大小(以字節爲單位)0

注意:

可以從中斷服務程序中調用此函數。


7.獲取消息隊列中排隊的消息數

uint32_t osMessageQueueGetCount	(osMessageQueueId_t 	mq_id)	

參數:

[in] mq_id osMessageQueueNew獲得的消息隊列ID 。

返回值:

排隊的消息數。

該函數osMessageQueueGetCount返回排隊的消息在由參數指定的消息隊列對象的數目mq_id0中的錯誤的情況下。

注意:

可以從中斷服務程序中調用此函數


8.獲取消息隊列中消息的可用插槽數

uint32_t osMessageQueueGetSpace(osMessageQueueId_t mq_id)

參數:

[in] mq_id osMessageQueueNew獲得的消息隊列ID 。

返回值:

消息的可用插槽數。

該函數osMessageQueueGetSpace返回數字可用時隙用於在由參數指定的消息隊列對象消息mq_id0中的錯誤的情況下。

注意

可以從中斷服務程序中調用此函數。


9.將消息隊列重置爲初始空狀態

osStatus_t osMessageQueueReset(osMessageQueueId_t 	mq_id)	

參數:

[in] mq_id osMessageQueueNew獲得的消息隊列ID 。

返回值:

狀態代碼,指示功能的執行狀態。

函數osMessageQueueReset重置由參數mq_id指定的消息隊列。

可能的osStatus_t返回值:

  • osOK:消息隊列已停止。
  • osErrorParameter:參數mq_idNULL或無效。
  • osErrorResource:消息隊列處於無效狀態。
  • osErrorISR: 不能從中斷服務例程中調用osMessageQueueReset

注意

不能從中斷服務程序中調用此函數。


10.刪除消息隊列對象

osStatus_t osMessageQueueDelete	(osMessageQueueId_t 	mq_id)

參數:

[in] mq_id osMessageQueueNew獲得的消息隊列ID 。

返回值:

狀態代碼,指示功能的執行狀態。

函數osMessageQueueDelete刪除由參數mq_id指定的消息隊列對象。它釋放爲消息隊列處理而獲得的內部存儲器。調用之後,mq_id不再有效,無法使用。可以使用osMessageQueueNew函數再次創建消息隊列。

可能的osStatus_t返回值:

  • osOK:消息隊列對象已被刪除。
  • osErrorParameter:參數mq_idNULL或無效。
  • osErrorResource:消息隊列處於無效狀態。
  • osErrorISR: 不能從中斷服務例程中調用osMessageQueueDelete

注意

不能從中斷服務程序中調用此函數。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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