跳转至

FreeRTOS

任务之间的通信 - 消息队列

消息队列的概念

首先要明确消息队列的概念,本质是一个队列,因此要遵循先进先出的规则(FIFO),而队列其实可以看做是一个数组,但是只能去操作数组的首元素,每次添加新数据只能默认添加到数组末尾,这个数组中存储的元素就是消息(字符串或者单个数字之类的),具体概念可以询问AI或视频如何简单理解消息队列?这里不过多赘述

消息队列的使用

FreeRTOS底层已经帮我们做好了消息队列的具体实现,我们只需要使用即可,需要包含头文件include "queue.h"

具体流程:

  1. 创建消息队列
  2. 准备数据
  3. 发送方将数据投递到消息队列中
  4. 接收方从消息队列中拿数据

创建队列需要使用到队列的句柄,关于句柄,前面一节已经提到过,这里不再赘述

使用到的API

具体API解读详见FreeRTOS官网

  • 队列创建:xQueueCreate(队列容量,队列中每个元素所占内存大小)
  • 发送数据到消息队列:xQueueSend(要投放的消息队列句柄,要投放的数据地址,如果队列已满则等待的最大时间)
  • 从消息队列中接收数据:xQueueReceive(要获取消息的队列句柄,存储获取到消息的缓冲区地址,如果队列为空则等待的最大时间)

简单示例:

  • 任务1:获取按键键值,如果按键1按下,则投放一个uint8_t类型的数据到第一个队列中;如果按键2按下,则投放一个字符串到第二个队列中
  • 任务2:监听第一个消息队列,如果获取到数据就通过串口打印输出
  • 任务3:监听第二个消息队列,如果获取到数据就通过串口打印输出

freeRTOS_demo.c源文件内容:

#include "stm32f10x.h"                  // Device header

#include "free_demo.h"

#include "myusart.h"
#include "Led.h"
#include "Key.h"

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
//初始任务句柄
TaskHandle_t start_task_Handler;
//业务逻辑任务句柄
TaskHandle_t task1_Handler;
TaskHandle_t task2_Handler;
TaskHandle_t task3_Handler;
//消息队列句柄
QueueHandle_t queue1_Handler;
QueueHandle_t queue2_Handler;
//任务声明
void start_Task(void *param);
void Task1(void *param);
void Task2(void *param);
void Task3(void *param);

void freeRTOS_Start(void)
{
    BaseType_t res = xTaskCreate(start_Task ,"create_allTasks" ,256 ,NULL ,2 ,&start_task_Handler);

    if(res == pdPASS)
    {
        Usart1_printf("startTask_create success \r\n");
    }

    vTaskStartScheduler();
}

void start_Task(void *param)
{
    //进入代码临界区
    taskENTER_CRITICAL();
    //创建消息队列
    queue1_Handler = xQueueCreate(5 ,sizeof(uint8_t));
    queue2_Handler = xQueueCreate(1 ,sizeof(char *));

    if((queue1_Handler != NULL)&&(queue2_Handler != NULL))
    {
        Usart1_printf("queue1 and queue2 create success \r\n");
    }
    //创建各个业务逻辑任务
    xTaskCreate(Task1 ,"myTask1" ,256 ,NULL ,2 ,&task1_Handler);
    xTaskCreate(Task2 ,"myTask2" ,256 ,NULL ,2 ,&task2_Handler);
    xTaskCreate(Task3 ,"myTask3" ,256 ,NULL ,2 ,&task3_Handler);
    //删除初始任务
    vTaskDelete(NULL);
    //退出代码临界区
    taskEXIT_CRITICAL();
}

void Task1(void *param)
{
    uint8_t key_num = 0;
    uint8_t num = 0;
    char *str = "this is freeRTOS \r\n";

    while(1)
    {
        key_num = get_KeyNum();
        if(key_num == 1)
        {
            //向消息队列1中投放数据
            num ++;
            BaseType_t res = xQueueSend(queue1_Handler ,&num ,portMAX_DELAY);
            if(res == pdTRUE)
            {
                Usart1_printf("%d put in queue1 success \r\n" ,num);
            }
        }
        else if(key_num == 2)
        {
            //向消息队列2中投放数据
            BaseType_t res = xQueueSend(queue2_Handler ,&str ,portMAX_DELAY);
            if(res == pdTRUE)
            {
                Usart1_printf("%s put in queue2 success \r\n" ,str);
            }
        }
    }
}

void Task2(void *param)
{
    uint8_t resNum = 0;
    while(1)
    {
        //如果从队列1中获取到数据就打印输出
        if(xQueueReceive(queue1_Handler ,&resNum ,portMAX_DELAY) == pdPASS)
        {
            Usart1_printf("data in queue1 : %d \r\n" ,resNum);
        }
    }
}

void Task3(void *param)
{
    char *buf;
    while(1)
    {
        //如果从队列2中获取到数据就打印输出
        if(xQueueReceive(queue2_Handler ,&buf ,portMAX_DELAY) == pdPASS)
        {
            Usart1_printf("data in queue2 : %s \r\n" ,buf);
        }
    }
}