当前位置: 首页 > article >正文

FreeRTOS从入门到精通 第十四章(队列集)

参考教程:【正点原子】手把手教你学FreeRTOS实时系统_哔哩哔哩_bilibili

一、队列集简介

1、队列集概述

(1)一个队列只允许任务间传递的消息为同一种数据类型,如果需要在任务间传递不同数据类型的消息时,那么就可以使用队列集。

(2)队列集可用于对多个队列或信号量进行“监听”,其中不管哪一个消息到来,都可让任务退出阻塞状态。

(3)队列集大致使用流程:

①启用队列集功能需要将宏configUSE_QUEUE_SETS配置为1。

②创建队列集。

③创建队列或信号量。

④往队列集中添加队列或信号量。

⑤往队列发送信息或释放信号量。

⑥获取队列集的消息。

2、队列集相关API函数介绍

(1)队列集相关API函数概览:

函数

描述

xQueueCreateSet()

创建队列集

xQueueAddToSet()

队列添加到队列集中【队列在被添加到队列集之前,队列中不能有有效的消息】

xQueueRemoveFromSet()

从队列集中移除队列【队列在从队列集移除之前,必须没有有效的消息】

xQueueSelectFromSet()

获取队列集中有有效消息的队列

xQueueSelectFromSetFromISR()

在中断中获取队列集中有有效消息的队列

(2)xQueueCreateSet函数:

①函数定义:

QueueSetHandle_t xQueueCreateSet
(
    const  UBaseType_t   uxEventQueueLength
); 

②函数参数:

形参

描述

uxEventQueueLength 

队列集可容纳的队列数量

③返回值:

返回值

描述

NULL 

队列集创建失败

其它值 

队列集创建成功,返回队列集句柄

(3)xQueueAddToSet函数:

①函数定义:

BaseType_t xQueueAddToSet
(
    QueueSetMemberHandle_t   	xQueueOrSemaphore ,
    QueueSetHandle_t   		    xQueueSet
); 

②函数参数:

形参

描述

xQueueOrSemaphore 

待添加的队列句柄

xQueueSet 

队列集

③返回值:

返回值

描述

pdPASS 

队列集添加队列成功

pdFAIL 

队列集添加队列失败

(4)xQueueRemoveFromSet函数:

①函数定义:

BaseType_t xQueueRemoveFromSet
(
    QueueSetMemberHandle_t  	xQueueOrSemaphore ,
	QueueSetHandle_t   		xQueueSet
); 

②函数参数:

形参

描述

xQueueOrSemaphore 

待移除的队列句柄

xQueueSet 

队列集

③返回值:

返回值

描述

pdPASS 

队列集添加队列成功

pdFAIL 

队列集添加队列失败

(5)xQueueSelectFromSet函数:

①函数定义:

QueueSetMemberHandle_t xQueueSelectFromSet
(
    QueueSetHandle_t 	xQueueSet,
    TickType_t const 		xTicksToWait
)

②函数参数:

形参

描述

xQueueSet 

队列集

xTicksToWait 

阻塞超时时间

③返回值:

返回值

描述

NULL 

获取消息失败

其他值 

获取到消息的队列句柄

二、队列集操作实验

1、原理图与实验目标

(1)原理图(串口外设的接法与列表项的插入和删除实验相同,下图未示出):

(2)实验目标:

①设计3个任务——start_task、task1、task2:

[1]start_task:用于创建其它任务,并创建队列集,队列/信号量,将队列/信号量添加到队列集中。

[2]task1:用于扫描按键,当按键1按下,往队列写入数据,当按键2按下,释放二值信号量。

[3]task2:读取队列集中的消息,并打印。

②预期实验现象:

[1]程序下载到板子上后,板子上无任何明显现象。

[2]串口助手中输出相关调试信息。

2、实验步骤

(1)将“列表项的插入和删除实验”的工程文件夹复制一份,在拷贝版中进行实验。

(2)在FreeRTOSConfig.h文件中将宏configUSE_QUEUE_SETS配置为1。

#define configUSE_QUEUE_SETS    1

(3)更改FreeRTOS_experiment.c文件的内容,如下所示。

#include "FreeRTOS.h"
#include "task.h"
#include "LED.h"
#include "Key.h"
#include "Serial.h"
#include "queue.h"
#include "semphr.h"

//宏定义
#define START_TASK_STACK_SIZE 128   //start_task任务的堆栈大小
#define START_TASK_PRIO        1     //start_task任务的优先级
#define TASK1_STACK_SIZE       128   //task1任务的堆栈大小
#define TASK1_PRIO              2     //task1任务的优先级
#define TASK2_STACK_SIZE       128   //task2任务的堆栈大小
#define TASK2_PRIO              3     //task2任务的优先级

//任务函数声明
void start_task(void);
void task1(void);
void task2(void);

//任务句柄
TaskHandle_t start_task_handler;     //start_task任务的句柄
TaskHandle_t task1_handler;         //task1任务的句柄
TaskHandle_t task2_handler;         //task2任务的句柄

QueueSetHandle_t queueset_handle;
QueueHandle_t    queue_handle;
QueueHandle_t    semphr_handle;

void FreeRTOS_Test(void)
{
	//创建任务start_task
	xTaskCreate((TaskFunction_t)start_task,            //指向任务函数的指针
				"start_task",                       //任务名字
				START_TASK_STACK_SIZE,       //任务堆栈大小,单位为字
				NULL,                          //传递给任务函数的参数
				START_TASK_PRIO,              //任务优先级
				(TaskHandle_t *) &start_task_handler  //任务句柄,就是任务的任务控制块
				);
	
	//开启任务调度器
	vTaskStartScheduler();
}

void start_task(void)
{
	taskENTER_CRITICAL();                        //进入临界区
    queueset_handle = xQueueCreateSet(2);             //创建队列集,可以存放2个队列
    if(queueset_handle != NULL)
    {
        Serial_Printf("队列集创建成功!!\r\n");
    }
    
    queue_handle = xQueueCreate(1, sizeof(uint8_t));       //创建队列 
    semphr_handle = xSemaphoreCreateBinary();           //创建二值信号量
    
    xQueueAddToSet(queue_handle,queueset_handle);
    xQueueAddToSet(semphr_handle,queueset_handle);
    
    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();
}

void task1(void)
{
    uint8_t key = 0;
    BaseType_t err = 0;
    while(1) 
    {
        key = Key_GetNum();
        if(key == 1)
        {
            err = xQueueSend(queue_handle, &key, portMAX_DELAY );
            if(err == pdPASS)
            {
                Serial_Printf("往队列queue_handle写入数据成功!!\r\n");
            }
        }
        else if(key == 2)
        {
            err = xSemaphoreGive(semphr_handle);
            if(err == pdPASS)
            {
                Serial_Printf("释放信号量成功!!\r\n");
            }
        }
        vTaskDelay(10);
    }
}

void task2(void)
{
    QueueSetMemberHandle_t member_handle;
    uint8_t key;
    while(1)
    {
        member_handle = xQueueSelectFromSet(queueset_handle,portMAX_DELAY);
        if(member_handle == queue_handle)
        {
            xQueueReceive(member_handle,&key,portMAX_DELAY);
            Serial_Printf("获取到的队列数据为:%d\r\n",key);
        }
        else if(member_handle == semphr_handle)
        {
            xSemaphoreTake(member_handle, portMAX_DELAY);
            Serial_Printf("获取信号量成功!!\r\n");
        }
    }
}

(4)程序完善好后点击“编译”,然后将程序下载到开发板上,打开串口助手分析信息。

3、程序执行流程

(1)main函数全流程:

①初始化串口模块。

②调用FreeRTOS_Test函数。

(2)测试函数全流程:

①创建任务start_task。

②开启任务调度器。

(3)多任务调度执行阶段较为简单,这里不再赘述。


http://www.kler.cn/a/524626.html

相关文章:

  • 21.2-工程中添加FreeRTOS(掌握) 用STM32CubeMX添加FreeRTOS
  • 未来无线技术的发展方向
  • 知识库管理驱动企业知识流动与工作协同创新模式
  • Ubuntu二进制部署K8S 1.29.2
  • Fullcalendar @fullcalendar/react 样式错乱丢失问题和导致页面卡顿崩溃问题
  • macbook安装go语言
  • [NOI1995] 石子合并
  • Antd React Form使用Radio嵌套多个Select和Input的处理
  • 架构技能(六):软件设计(下)
  • 用户创建命令的详细使用与参数说明
  • 深度学习每周学习总结R5(LSTM-实现糖尿病探索与预测-模型优化)
  • Origami Agents:通过AI驱动的研究工具提升B2B销售效率
  • 网络工程师 (8)存储管理
  • docker运行Open-Webui 界面化展示 deepseek-r1大模型
  • 【新春特辑】2025年春节技术展望:蛇年里的科技创新与趋势预测
  • CUDA学习-内存访问
  • 飞鸟小目标检测数据集VOC+YOLO格式1657张2类别
  • 解锁豆瓣高清海报:深度爬虫与requests进阶之路
  • Kubernetes 环境中的自动化运维实战指南
  • 【灵蛇献瑞】| 2024 中国开源年度报告正式发布!
  • leetcode hot 100 搜索二维矩阵II
  • 详解:网站地图对快速收录的重要性
  • Ansys Maxwell:初始电压和击穿电压计算
  • P11468 有向树
  • ProfibusDP主机与从机交互
  • AI提示词(Prompt)入门详解