首页 > 技术文章 > μC/OS-II系统中消息队列的使用

wenhao-Web 原文

以下内容主要注重应用,对源码不做分析,对源码有兴趣的可参考官方具体文档,相关链接: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

推荐阅读