1. 程式人生 > 實用技巧 >μC/OS-II系統中訊息佇列的使用

μC/OS-II系統中訊息佇列的使用

以下內容主要注重應用,對原始碼不做分析,對原始碼有興趣的可參考官方具體文件,相關連結:https://doc.micrium.com/display/ucos/

開發環境:TrueSTUDIO

微控制器:STM32F103VET6(HAL庫)

一、建立一個訊息佇列,OSQCreate()

  在使用訊息佇列之前,需要先建立訊息佇列(或簡單地說一個佇列)。建立佇列是通過呼叫OSQCreate()並向它傳遞兩個引數來完成的:一個指向一個數組的指標,這個陣列將儲存訊息和這個陣列的大小。這個陣列必須宣告為一個指向void的指標陣列,如下所示:

  void * MyArrayOfMsg(大小);

  你需要將MyArrayOfMsg[]的地址以及這個陣列的大小傳遞給OSQCreate()。如果訊息佇列最初為空則它不包含任何訊息

。函式原型為:

  1、OS_EVENT *OSQCreate (void**start, INT16U size)。

  • start是指向一個數組的指標,這個陣列將儲存訊息;
  • size是指向陣列的大小;
  • 返回與佇列相關聯的指向事件控制塊的指標。

二、傳送一個訊息到訊息佇列(FIFO 先進先出原則),OSQPost()

  將一個訊息存到訊息佇列,函式原型為:

  1、INT8U OSQPost (OS_EVENT *pevent,void*msg)。

  • pevent是訊息佇列相關聯的指向事件控制塊的指標;
  • msg是指向您希望存入訊息佇列的訊息的指標(傳送的不能是空指標,由於佇列傳送的訊息是地址,被髮送的訊息最好是全域性變數
    );
  • 返回值是錯誤型別。

三、傳送一個訊息到訊息佇列(LIFO 後進先出原則),OSQPostFront()

  將一個訊息存到訊息佇列,函式原型為:

  1、INT8U OSQPostFront (OS_EVENT *pevent,void*msg)

  • pevent是訊息佇列相關聯的指向事件控制塊的指標;
  • msg是指向您希望存入訊息佇列的訊息的指標(傳送的不能是空指標,由於佇列傳送的訊息是地址,被髮送的訊息最好是全域性變數);
  • 返回值是錯誤型別。

四、從一個訊息佇列中等待一個訊息,OSQPend()

  等待一個訊息到達訊息佇列,函式原型為:

  1、void*OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)

  • pevent是訊息佇列相關聯的指向事件控制塊的指標;
  • timeout等待時長(如果是0將一直等下去,直到訊息佇列中有訊息);
  • err錯誤型別;
  • 返回值是訊息佇列中收到的訊息指標。

五、示例程式碼(非中斷方式)

  1、定義一個訊息佇列事件指標和訊息佇列的儲存單元(儲存單元儲存的是資料的指標):

/* 定義一個訊息佇列事件指標 */
OS_EVENT *MessageQ;
/* 定義訊息佇列的空間大小 */
void *MessageStorage[10];

  2、建立訊息佇列:

/* 建立訊息佇列, 含10個儲存單元(儲存的內容是指標不是資料) */
MessageQ = OSQCreate(&MessageStorage[0], 10);

  3、在一個任務中傳送兩種不同的值的地址到訊息郵箱:

static void AppTask1(void *p_arg)
{
    INT16U value1 = 1, value2 = 2;

    (void)p_arg;

    while(1)
    {
        if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET)
        {
            /* 傳送訊息到訊息佇列 */
            OSQPost(MessageQ, (void *)&value1);
        }

        if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET)
        {
            /* 傳送訊息到訊息佇列 */
            OSQPost(MessageQ, (void *)&value2);
        }

        OSTimeDlyHMSM(0, 0, 0, 100);
    }
}

  4、在一個任務中接收訊息佇列中的訊息:

static void AppTask2(void *p_arg)
{
    INT8U err;
    INT16U r_value;

    (void)p_arg;

    while(1)
    {
        /* 等待訊息佇列獲取到訊息 */
        r_value = *(INT16U *)OSQPend(MessageQ, 0, &err);
        if(err == OS_ERR_NONE)
        {
            if(r_value == 1)
            {
                HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
            }
            else if(r_value ==2)
            {
                HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);
            }
        }
    }
}

六、示例程式碼(中斷方式)

  1、定義訊息佇列事件指標和訊息佇列的儲存單元(儲存單元儲存的是資料的指標):

/* 定義兩個訊息佇列事件溼疹 */
OS_EVENT *MessageQ1;
OS_EVENT *MessageQ2;
/* 定義訊息佇列的儲存單元 */
void *MessageStorage1[10];
void *MessageStorage2[10];

  2、建立訊息佇列:

/* 建立訊息佇列,含10個儲存單元 */
MessageQ1 = OSQCreate(&MessageStorage1[0], 10);
MessageQ2 = OSQCreate(&MessageStorage2[0], 10);

  3、中斷函式中進行鍼對μC/OS系統的處理:

/**
  * @brief This function handles EXTI line0 interrupt.
  */
void EXTI0_IRQHandler(void)
{
#if uCOS_EN == 1

#if OS_CRITICAL_METHOD == 3u                 /* Allocate storage for CPU status register               */
    OS_CPU_SR   cpu_sr = 0u;
#endif

    OS_ENTER_CRITICAL();
    OSIntEnter();
    OS_EXIT_CRITICAL();
#endif

    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);

#if uCOS_EN == 1
    OSIntExit();
#endif

}

/**
  * @brief This function handles EXTI line[15:10] interrupts.
  */
void EXTI15_10_IRQHandler(void)
{
#if uCOS_EN == 1

#if OS_CRITICAL_METHOD == 3u                 /* Allocate storage for CPU status register               */
    OS_CPU_SR   cpu_sr = 0u;
#endif

    OS_ENTER_CRITICAL();
    OSIntEnter();
    OS_EXIT_CRITICAL();
#endif

    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);

#if uCOS_EN == 1
    OSIntExit();
#endif
}

  4、在中斷的回撥函式中傳送訊息,針對不同埠引腳被觸發傳送不同的訊息:

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if(GPIO_Pin == GPIO_PIN_0)
    {
        OSQPost(MessageQ1, (void *)&value_u8);
    }

    if(GPIO_Pin == GPIO_PIN_13)
    {
        OSQPost(MessageQ2, (void *)&value_u16);
    }
}

  5、建立兩個任務分別去接收中斷髮出的郵箱訊息:

static void AppTaskLed1(void *p_arg)
{
    INT8U err;
    INT8U r_value;

    (void)p_arg;

    while(1)
    {
        /* 從訊息佇列中獲取訊息 */
        r_value = *(INT8U *)OSQPend(MessageQ1, 0, &err);
        if(err == OS_ERR_NONE)
        {
            if(r_value == 1)
            {
                HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);
            }
        }
    }
}

static void AppTaskLed2(void *p_arg)
{
    INT8U err;
    INT16U r_value;

    (void)p_arg;

    while(1)
    {
        /* 從訊息佇列中獲取訊息 */
        r_value = *(INT16U *)OSQPend(MessageQ2, 0, &err);
        if(err == OS_ERR_NONE)
        {
            if(r_value == 2)
            {
                HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
            }
        }
    }
}

#endif