目录

1.消息队列

1.1什么是消息队列

1.2 传输数据的两种方法

1.3 队列的阻塞访问

1.4 读取队列的两种方式

2 示例程序

2.1 以拷贝值的方式传递数据

2.1.1 例程功能

2.1.2 步骤

2.1.3 实验结果

2.1.4 函数讲解

2.1.5 程序源码

2.2 以拷贝地址的方式传递数据

2.2.1 例程功能

2.2.2 步骤

2.2.3 实验结果

2.2.4 函数讲解

2.2.5 程序源码



1.消息队列

1.1什么是消息队列

消息队列类似于数据结构中的“队列”,都是一个线性的存储表。可以往队列里面写入数据,也可从队列里面读取数据。队列的简化操作如下图所示,从此图可知:

  • 队列可以包含若干个数据:队列中有若干项,这被称为"长度"(length)
  • 每个数据大小固定
  • 创建队列时就要指定长度、数据大小
  • 数据的操作采用先进先出的方法(FIFO,First In First Out):写数据时放到尾部,读数据时从头部读
  • 也可以强制写队列头部:覆盖头部数据

1.2 传输数据的两种方法

  • 拷贝:把数据或变量的值复制进队列里
  • 引用:把数据或变量的地址复制进队列里

1.3 队列的阻塞访问

只要知道队列的句柄,谁都可以读、写该队列。

任务读写队列时,简单地说:如果读写不成功,则阻塞;可以指定超时时间。口语化地说,就是可以定个闹钟:如果能读写了就马上进入就绪态,否则就阻塞直到超时。

跟读队列类似,一个任务要写队列时,如果队列满了,该任务也可以进入阻塞状态:还可以指定阻塞的时间。如果队列有空间了,则该阻塞的任务会变为就绪态。如果一直都没有空间,则时间到之后它也会进入就绪态。

1.4 读取队列的两种方式

  • Get(获取):使用函数osMessageGet()读队列的时候,读到一个数据,队列中的改数据会被移除
  • Peek(偷窥):使用函数osMessagePeek()读队列的时候,此函数会从队列中复制出数据,但是不移除 数据

2 示例程序

使用队列传递数据的两种方法:

  • 拷贝:把数据或变量的值复制进队列里
  • 引用:把数据或变量的地址复制进队列里

2.1 以拷贝值的方式传递数据

2.1.1 例程功能

创建一个按键任务用来向队列里写数据,创建两个任务以PEEK和GET的方式从队列里面读取数据并打印出来。

2.1.2 步骤

配置按键的IO口

配置串口1,波特率115200、数据位8、停止位1、奇偶校验none

 创建3个动态任务

 创建一个队列,队列长度16(能存放16个数据),每个数据占32位

创建按键任务,按键按下即往消息队列里面发送数据

/* USER CODE END Header_StartTask_KEY */
void StartTask_KEY(void const * argument)
{
  /* USER CODE BEGIN StartTask_KEY */
  /* Infinite loop */
  uint32_t ProducerValue=0;
  for(;;)
  {
    if(HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin)==0)
    {
        if(osMessagePut(myQueue01Handle,ProducerValue,100)!=osOK)
        {
             osThreadSuspendAll();
             printf("发送失败\n");  //要添加头文件 stdio.h
             osThreadResumeAll();
         }
    else
    {
        ++ProducerValue;
         osThreadSuspendAll();
         printf("发送成功\n");  //要添加头文件 stdio.h
         osThreadResumeAll();
    }
    while(HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin)==0)
    {
         osDelay(10);
    }
    }
    osDelay(1);
   }
  /* USER CODE END StartTask_KEY */
}

以PEEK的方式读取消息队列中的数据,并将读取的数据打印出来

/* USER CODE END Header_StartTask01 */
void StartTask01(void const * argument)
{
  /* USER CODE BEGIN StartTask01 */
  /* Infinite loop */
  osEvent event;
  for(;;)
  {
      event=osMessagePeek(myQueue01Handle,osWaitForever);
      if(event.status==osEventMessage) //判断是否是消息队列
      {
          printf("任务1数据: %d\n",event.value.v);
      }
  osDelay(1);
  }
  /* USER CODE END StartTask01 */
}

以GET的方式读取消息队列中的数据,并将读取的数据打印出来

/* USER CODE END Header_StartTask02 */
void StartTask02(void const * argument)
{
  /* USER CODE BEGIN StartTask02 */
  /* Infinite loop */
  osEvent event;
  for(;;)
  {
      event=osMessageGet(myQueue01Handle,osWaitForever);
      if(event.status==osEventMessage) //判断是否是消息队列
      {
          printf("任务2数据: %d\n",event.value.v);
      }
      osDelay(1);
  }
  /* USER CODE END StartTask02 */
}

2.1.3 实验结果

按键按下,任务Task_01和任务Task_02接受到队列中的数据并打印出来

2.1.4 函数讲解

1 osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec)

/*
@brief Put a Message to a Queue.
@param  queue_id  message queue ID obtained with \ref osMessageCreate.
@param  info      message information.
@param  millisec  timeout value or 0 in case of no time-out.
@retval status code that indicates the execution status of the function.
@note   MUST REMAIN UNCHANGED: \b osMessagePut shall be consistent in every CMSIS-RTOS.
*/
osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec)
  • 函数功能:往队列中发送消息
  • 传入参数:1.queue_id(要写入队列的句柄)2.info(要写入的消息)3.millisec(等待时间)

 2 osEvent osMessagePeek (osMessageQId queue_id, uint32_t millisec)

/*
@brief  Receive an item from a queue without removing the item from the queue.
@param  queue_id  message queue ID obtained with \ref osMessageCreate.
@param  millisec  timeout value or 0 in case of no time-out.
@retval event information that includes status code.
*/
osEvent osMessagePeek (osMessageQId queue_id, uint32_t millisec)
  • 函数功能:获取队列中的消息(得到消息后不会将其删除)
  • 传入参数:1.queue_id(要获取队列的句柄)2.millisec(等待时间)

3 osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec)

/*
@brief Get a Message or Wait for a Message from a Queue.
@param  queue_id  message queue ID obtained with \ref osMessageCreate.
@param  millisec  timeout value or 0 in case of no time-out.
@retval event information that includes status code.
@note   MUST REMAIN UNCHANGED: \b osMessageGet shall be consistent in every CMSIS-RTOS.
*/
osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec)
  • 函数功能:获取队列中的消息(得到消息后会将消息从队列中删除)
  • 传入参数:1.queue_id(要获取队列的句柄)2.millisec(等待时间)

2.1.5 程序源码

github链接:HaoJosephWen/FreeRtos_personal (github.com)

2.2 以拷贝地址的方式传递数据

2.2.1 例程功能

        创建一个按键任务用来向队列里写结构体地址,创建两个任务以PEEK和GET的方式从队列里面读取结构体的地址并将结构体里的数据打印出来

2.2.2 步骤

 配置按键的IO口

 配置串口1,波特率115200、数据位8、停止位1、奇偶校验none

 创建3个动态任务

 创建一个队列,队列长度16(能存放16个数据),每个数据占32位

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
typedef struct
{
    uint32_t var1;
    uint32_t var2;
    uint32_t var3;
}DataGroup;
/* USER CODE END PTD */

定义一个结构体,结构体里面存放3个数据变量

/* USER CODE END Header_StartTask_KEY */
void StartTask_KEY(void const * argument)
{
  /* USER CODE BEGIN StartTask_KEY */
  /* Infinite loop */
  uint32_t ProducerValue=0;
  DataGroup myDataGroup_t={10,20,30};
  ProducerValue=(uint32_t)&myDataGroup_t;
  for(;;)
  {
        if(HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin)==0)
        {
            osDelay(10);
            if(HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin)==0)
            {
                if(osMessagePut(myQueue01Handle,ProducerValue,0)!=osOK)
                {
            osThreadSuspendAll();
            printf("发送失败\n");  //要添加头文件 stdio.h
            osThreadResumeAll();
                }
                else
                {
            osThreadSuspendAll();
            printf("发送成功\n");  //要添加头文件 stdio.h
            osThreadResumeAll();
                }
                while(HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin)==0)
                {
             osDelay(10);
                }
            }
        }
        osDelay(1);
  }
  /* USER CODE END StartTask_KEY */
}

创建按键任务,按键按下即往队列里面发送结构体地址

/* USER CODE END Header_StartTask01 */
void StartTask01(void const * argument)
{
  /* USER CODE BEGIN StartTask01 */
  /* Infinite loop */
  osEvent event;
  DataGroup *myDataGroup_r;
  for(;;)
  {
      event=osMessagePeek(myQueue01Handle,osWaitForever);
      if(event.status==osEventMessage) //判断是否是消息队列
      {
          myDataGroup_r=event.value.p;
          osThreadSuspendAll();
          printf("任务1接受的数据: %d\n",myDataGroup_r->var1);
          printf("任务1接受的数据: %d\n",myDataGroup_r->var2);
          printf("任务1接受的数据: %d\n",myDataGroup_r->var3);
          osThreadResumeAll();
      }
    osDelay(1);
  }
  /* USER CODE END StartTask01 */
}

以PEEK的方式读取消息队列中的结构体的地址,自定义结构体指针指向队列传输的结构体的地址,并将结构体中的数据打印出来

/* USER CODE END Header_StartTask02 */
void StartTask02(void const * argument)
{
  /* USER CODE BEGIN StartTask02 */
  /* Infinite loop */
  osEvent event;
  DataGroup *myDataGroup_r;
  for(;;)
  {
      event=osMessageGet(myQueue01Handle,osWaitForever);
      if(event.status==osEventMessage) //判断是否是消息队列
      {
          myDataGroup_r=event.value.p;
          osThreadSuspendAll();
          printf("任务2接受的数据: %d\n",myDataGroup_r->var1);
          printf("任务2接受的数据: %d\n",myDataGroup_r->var2);
          printf("任务2接受的数据: %d\n",myDataGroup_r->var3);
          osThreadResumeAll();
      }
    osDelay(1);
  }
  /* USER CODE END StartTask02 */
}

以GET的方式读取消息队列中的结构体的地址,自定义结构体指针指向队列传输的结构体的地址,并将结构体中的数据打印出来

2.2.3 实验结果

2.2.4 函数讲解

同上。

这里补充一个结构体:

/// Event structure contains detailed information about an event.
/// \note MUST REMAIN UNCHANGED: \b os_event shall be consistent in every CMSIS-RTOS.
///       However the struct may be extended at the end.
typedef struct  {
  osStatus                 status;     ///< status code: event or error information
  union  {
    uint32_t                    v;     ///< message as 32-bit value
    void                       *p;     ///< message or mail as void pointer
    int32_t               signals;     ///< signal flags
  } value;                             ///< event value
  union  {
    osMailQId             mail_id;     ///< mail id obtained by \ref osMailCreate
    osMessageQId       message_id;     ///< message id obtained by \ref osMessageCreate
  } def;                               ///< event definition
} osEvent;

2.2.5 程序源码

github链接:HaoJosephWen/FreeRtos_personal (github.com)

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐