1,队列集简介(了解)
一个队列只允许任务间传递的消息为同一种数据类型,如果需要在任务间传递不同数据类型的消息时,那么就可以使用队列集 !
作用:用于对多个队列或信号量进行“监听”,其中不管哪一个消息到来,都可让任务退出阻塞状态
假设:有个接收任务,使用到队列接收和信号量的获取,如下:
如果此时释放了信号量该任务本能获取信号量,但是如果接收队列时该队列中没有值,当前该任务会被放入阻塞状态。那本应获取到的信号量也获取不到。
2,队列集相关API函数介绍(熟悉)
用于创建队列集
QueueSetHandle_t xQueueCreateSet( const UBaseType_t uxEventQueueLength );
往队列集中添加队列
BaseType_t xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore ,
QueueSetHandle_t xQueueSet );
此函数用于往队列集中添加队列,要注意的时,队列在被添加到队列集之前,队列中不能有有效的消息 (也就是说我们创建好的队列和信号量里面不能有值,才能将该队列放入到队列集中。)
用于从队列集中移除队列
BaseType_t xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore , QueueSetHandle_t xQueueSet );
用于在任务中获取队列集中有有效消息的队列
QueueSetMemberHandle_t xQueueSelectFromSet( QueueSetHandle_t xQueueSet,
TickType_t const xTicksToWait )
此函数用于在任务中获取队列集中有有效消息的队列
3,队列集操作实验(掌握)
1、实验目的:学习 FreeRTOS 的队列集相关API的使用。
2、实验设计:将设计三个任务:start_task、task1、task2
三个任务的功能如下:
start_task:用来创建其它任务,并创建队列集,队列/信号量,将队列/信号量添加到队列集中
task1:用于扫描按键,当KEY0按下,往队列写入数据,当KEY1按下,释放二值信号量
task2:读取队列集中的消息,并打印
队列集使用流程
1、启用队列集功能需要将宏configUSE_QUEUE_SETS 配置为 1
2、创建队列集
3、创建队列或信号量
4、往队列集中添加队列或信号量
5、往队列发送信息或释放信号量
6、获取队列集的消息
#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
#include "./MALLOC/malloc.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/******************************************************************************************************/
/*FreeRTOS配置*/
/* START_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
/* TASK1 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define START_TASK_PRIO 1
#define START_TASK_STACK_SIZE 128
TaskHandle_t start_task_handler;
void start_task( void * pvParameters );
#define TASK1_PRIO 2
#define TASK1_STACK_SIZE 128
TaskHandle_t task1_handler;
void task1( void * pvParameters );
/* TASK2 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK2_PRIO 3
#define TASK2_STACK_SIZE 128
TaskHandle_t task2_handler;
void task2( void * pvParameters );
#define QUEUE_NUM 2
/******************************************************************************************************/
QueueSetHandle_t g_queueset_handle;/*声明队列集*/
QueueHandle_t g_queue_handle; /*声明队列*/
QueueHandle_t g_bin_semphore_handle;/*声明二值信号量*/
/**
* @brief FreeRTOS例程入口函数
* @param 无
* @retval 无
*/
void freertos_demo(void)
{
BaseType_t err;
/*********************************创建队列集*********************************************************************/
g_queueset_handle= xQueueCreateSet(QUEUE_NUM);/* 创建队列集 */
if(g_queueset_handle!=NULL)
{
printf("创建队列集成功!!!!\r\n");
}
else
{
printf("创建队列集失败!!!!\r\n");
}
g_queue_handle=xQueueCreate(1,sizeof(uint8_t)); /* 创建队列*/
if(g_queue_handle!=NULL)
{
printf("创建队列成功!!!!\r\n");
}
else
{
printf("创建队列失败!!!!\r\n");
}
g_bin_semphore_handle=xSemaphoreCreateBinary(); /* 创建二值信号量 */
if(g_bin_semphore_handle!=NULL)
{
printf("创建二值信号量成功!!!!\r\n");
}
else
{
printf("创建二值信号量失败请检查错误!!!!\r\n");
}
err=xQueueAddToSet( g_queue_handle,g_queueset_handle);
if(err==pdTRUE)
{
printf("队列添加到队列集成功!\r\n");
}
else
{
printf("队列添加到队列集失败!\r\n");
}
err=xQueueAddToSet( g_bin_semphore_handle,g_queueset_handle);
if(err==pdTRUE)
{
printf("信号量添加到队列集成功!\r\n");
}
else
{
printf("信号量添加到队列集失败!\r\n");
}
xTaskCreate((TaskFunction_t) start_task,
(char *) "start_task",
(configSTACK_DEPTH_TYPE) START_TASK_STACK_SIZE,
(void *) NULL,
(UBaseType_t) START_TASK_PRIO,
(TaskHandle_t *)&start_task_handler
);
//开启任务调度
vTaskStartScheduler();
}
void start_task( void * pvParameters )
{
taskENTER_CRITICAL(); /* 进入临界区 任何任务和中断都不能打断当前程序运行*/
xTaskCreate((TaskFunction_t) task1,
(char *) "task1",
(configSTACK_DEPTH_TYPE) TASK1_STACK_SIZE,
(void *) NULL,
(UBaseType_t) TASK1_PRIO,
(TaskHandle_t *)&task1_handler );
xTaskCreate((TaskFunction_t) task2,
(char *) "task2",
(configSTACK_DEPTH_TYPE) TASK2_STACK_SIZE,
(void *) NULL,
(UBaseType_t) TASK2_PRIO,
(TaskHandle_t *)&task2_handler );
vTaskDelete(NULL);//删除当前任务也就是开始任务
taskEXIT_CRITICAL();
}
/* 任务一,用于扫描按键,当KEY0按下,往队列写入数据,当KEY1按下,释放二值信号量 */
void task1( void * pvParameters )
{
BaseType_t err;
uint8_t key;
while(1)
{
key=key_scan(0);
if(key==KEY0_PRES)
{
/*往队列写入数据*/
err=xQueueSend(g_queue_handle,&key,portMAX_DELAY);
if(err==pdPASS)
{
printf("往队列写入queue_handle写入数据成功");
}
}
else if(key==KEY1_PRES)
{
/*释放二值信号量*/
err = xSemaphoreGive(g_bin_semphore_handle);
if(err==pdPASS)
{
printf("释放信号量成功!!\r\n");
}
}
vTaskDelay(10);
}
}
/* 任务二,读取队列集中的消息并打印*/
void task2( void * pvParameters )
{
QueueSetMemberHandle_t member_handle;
uint8_t key;
while(1)
{
//监听当队列消息来时返回相应队列句柄,监听不到进行阻塞
member_handle=xQueueSelectFromSet( g_queueset_handle,portMAX_DELAY);
if(member_handle==g_queue_handle)
{
xQueueReceive(member_handle,&key,portMAX_DELAY);
printf("获取到的数据队列为:%d\r\n",key);
}
else if(member_handle==g_bin_semphore_handle)
{
xSemaphoreTake(member_handle,portMAX_DELAY);
printf("获取信号量成功!!\r\n");
}
}