zoukankan      html  css  js  c++  java
  • μ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

  • 相关阅读:
    2312--1.3.4 Prime Cryptarithm 牛式
    Slava and tanks 877C
    World Cup 996B(排队模拟)
    css内边距 边框
    iframs刷新的两种方法
    JS DOM节点
    JS对话框
    JS事件常用事件
    JS数组
    JS第一天
  • 原文地址:https://www.cnblogs.com/wenhao-Web/p/13797924.html
Copyright © 2011-2022 走看看