FreeRTOS
任务之间的通信 - 消息队列
消息队列的概念
首先要明确消息队列的概念,本质是一个队列,因此要遵循先进先出的规则(FIFO),而队列其实可以看做是一个数组,但是只能去操作数组的首元素,每次添加新数据只能默认添加到数组末尾,这个数组中存储的元素就是消息(字符串或者单个数字之类的),具体概念可以询问AI或视频如何简单理解消息队列?这里不过多赘述
消息队列的使用
FreeRTOS底层已经帮我们做好了消息队列的具体实现,我们只需要使用即可,需要包含头文件include "queue.h"
具体流程:
- 创建消息队列
- 准备数据
- 发送方将数据投递到消息队列中
- 接收方从消息队列中拿数据
创建队列需要使用到队列的句柄,关于句柄,前面一节已经提到过,这里不再赘述
使用到的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);
}
}
}