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

十六、FreeRTOS之FreeRTOS队列集

本节需要掌握以下内容:

1,队列集简介(了解)

2,队列集相关API函数介绍(熟悉)

3,队列集操作实验(掌握)

一、队列集简介(了解)

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

作用:用于对多个队列或信号量进行“监听”,其中不管哪一个消息到来,都可以让任务退出阻塞状态。这个监听,就是监听有没有收到数据。

假设:有个接收任务,使用到队列接收和信号量的获取,如下:

如果没有使用队列集的情况,按下图实现:

 这样的话,如果等待不到接收队列,任务就会阻塞,队列有个接收阻塞的时间,获取信号量也是一样,如果其它任务一直没释放,那么它也会阻塞,等待获取信号量。

假设其它任务释放了信号量,但是接收队列阻塞,那么它一样获取不到信号量。

或者说接收队列正常接收,但是获取不到信号量,这个任务依然被阻塞。

这种情况就可以使用队列集,不管哪一个消息到来,都可以让任务退出阻塞状态。

队列集如下图方式实现:一个接收任务,里面就是一个等待队列集消息,首先判断以下句柄是队列还是信号量,如果句柄是队列,那么就执行队列的接收函数,如果是信号量,那么就执行信号量的获取函数,这样就可以解除接收任务的阻塞状态了。

这就是队列集的一个使用场景。

,队列集相关API函数介绍(熟悉)

函数

描述

xQueueCreateSet()

创建队列集

xQueueAddToSet()

队列添加到队列集中

xQueueRemoveFromSet()

从队列集中移除队列

xQueueSelectFromSet()

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

xQueueSelectFromSetFromISR()

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

 我们可以使用创建队列集函数xQueueCreateSet()创建一个队列集,再使用队列创建函数xQueueCreate()创建两个队列,使用队列集添加队列函数xQueueAddToSet()将刚刚创建的两个队列添加至队列集中。

2.1 创建队列集函数

QueueSetHandle_t     xQueueCreateSet( const  UBaseType_t   uxEventQueueLength );

此函数用于创建队列集。

形参

描述

uxEventQueueLength

队列集可容纳的队列数量

返回值

描述

NULL

队列集创建失败

其他值

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

 2.2 队列添加到队列集中

BaseType_t xQueueAddToSet( QueueSetMemberHandle_t     xQueueOrSemaphore ,

        QueueSetHandle_t     xQueueSet    );

此函数用于往队列集中添加队列,要注意的时,队列在被添加到队列集之前,队列中不能有有效的消息

形参

描述

xQueueOrSemaphore

待添加的队列句柄

xQueueSet

队列集

返回值

描述

pdPASS

队列集添加队列成功

pdFAIL

队列集添加队列失败

2.3 队列集中移除队列

BaseType_t   xQueueRemoveFromSet( QueueSetMemberHandle_t    xQueueOrSemaphore ,
           
QueueSetHandle_t     xQueueSet );

此函数用于往队列集中添加队列,到注意的是,队列在被添加到队列集之前,队列中不能有效的消息

形参

描述

xQueueOrSemaphore

待移除的队列句柄

xQueueSet

队列集

返回值

描述

pdPASS

队列集移除队列成功

pdFAIL

队列集移除队列失败

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

QueueSetMemberHandle_t     xQueueSelectFromSet( QueueSetHandle_t   xQueueSet,

                                                        TickType_t const   xTicksToWait )

 此函数用于在任务中获取队列集中有效消息的队列

形参

描述

xQueueSet

队列集

xTicksToWait

阻塞超时时间

返回值

描述

NULL

获取消息失败

其他值

获取到消息的队列句柄

 假设:多个队列,是队列1发送的数据,通过调用此函数获取队列集中有效消息的队列,那么返回的是队列1的句柄。

三、 队列集使用流程

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

2、创建队列集

3、创建队列或信号量

4、往队列集中添加队列或信号量

5、往队列发送信息或释放信号量

6、获取队列集的消息

四、队列集操作实验(掌握)

4.1、实验目的:

学习 FreeRTOS 的队列集相关API的使用。

4.2、实验设计:

将设计三个任务:start_task、task1、task2

三个任务的功能如下:

  • start_task:用来创建其它任务,并创建队列集,队列/信号量,将队列/信号量添加到队列集中
  • task1:用于扫描按键,当KEY0按下,往队列写入数据,当KEY1按下,释放二值信号量
  • task2:读取队列集中的消息,并打印

4.3 实验代码

demo.c

/******************************************************************************************************/
/*FreeRTOS配置*/

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define START_TASK_PRIO         1
#define START_TASK_STACK_SIZE   128
TaskHandle_t    start_task_handler;
void start_task( void * pvParameters );

/* TASK1 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#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 );

/******************************************************************************************************/
QueueSetHandle_t queueset_handle;
QueueHandle_t    queue_handle;
QueueHandle_t    semphr_handle;
/**
 * @brief       FreeRTOS例程入口函数
 * @param       无
 * @retval      无
 */
void freertos_demo(void)
{    
    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();                               /* 进入临界区 */
    queueset_handle = xQueueCreateSet( 2 );             /* 创建队列集,可以存放2个队列 */
    if(queueset_handle != NULL)
    {
        printf("队列集创建成功!!\r\n");
    }
    
    queue_handle = xQueueCreate( 1, sizeof(uint8_t) );  /* 创建队列 */ 
	if(queue_handle != NULL)
    {
        printf("队列创建成功!!\r\n");
    }
    semphr_handle = xSemaphoreCreateBinary();           /* 创建二值信号量 */
	if(semphr_handle != NULL)
    {
        printf("二值信号量创建成功!!\r\n");
    }
	
    /* 往队列里面添加队列或信号量 */
    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 * pvParameters )
{
    uint8_t key = 0;
    BaseType_t err = 0;
    while(1) 
    {
        key = key_scan(0);
        if(key == KEY0_PRES)
        {
            err = xQueueSend( queue_handle, &key, portMAX_DELAY );
            if(err == pdPASS)
            {
                printf("往队列queue_handle写入数据成功!!\r\n");
            }
        }else if(key == KEY1_PRES)
        {
            err = xSemaphoreGive(semphr_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( queueset_handle,portMAX_DELAY);
        if(member_handle == queue_handle)
        {
            xQueueReceive( member_handle,&key,portMAX_DELAY);
            printf("获取到的队列数据为:%d\r\n",key);
        }else if(member_handle == semphr_handle)
        {
            xSemaphoreTake( member_handle, portMAX_DELAY );
            printf("获取信号量成功!!\r\n");
        }
    }
}

注意!!!

首先打印的是队列集创建成功、队列创建成功,二值信号量创建成功,

由于任务2的优先级最高,那么首先运行任务2,但是此时队列中没有数据,获取不到数据,那么任务2会进入阻塞状态。

当按下KEY0,任务2解除阻塞,执行队列的接收函数,打印获取到的数据为1,接着又从队列集中获取消息,获取不到消息,就又开始死等,被阻塞。

阻塞之后来到任务1,从被打断的地方继续执行,打印往队列中写入数据成功。

这是按下KEY0的情况,按下KEY1,同理,首先打印获取信号量成功,接下来是释放信号量成功。


http://www.kler.cn/news/163244.html

相关文章:

  • 数据中心:保障企业运营安全可靠的关键
  • 深入浅出之中央空调体系架构及楼宇自控系统
  • 找重复的数据(一维数组)
  • NLP项目实战01之电影评论分类
  • 目标检测YOLO实战应用案例100讲-交通场景中基于深度学习的目标检测和深度估计
  • FolkMQ 内存型消息中间件,v1.0.18 发布
  • 腾讯云CentOS8 jenkins war安装jenkins步骤文档
  • android快速网络请求之android-networking
  • 【Vue3+Ts项目】硅谷甄选 — 路由配置+登录模块+layout组件+路由鉴权
  • 计算机的存储规则
  • webpack该如何打包
  • 左值、右值 、左值引用、右值引用的总结
  • 【数据结构】顺序表的定义和运算
  • 苹果手机video标签播放视频问题(播放mp4视频遇到的坑)
  • WPS论文写作——公式和公式序号格式化
  • 文本转图像 学习笔记
  • web前端开发html/css练习
  • 第75讲:MySQL数据库MVCC多版本并发控制核心概念以及底层原理
  • 无人机高空巡查+智能视频监控技术,打造森林防火智慧方案
  • 结构化布线系统
  • 树莓派 5 - Raspberry Pi 5 入门教程
  • C/C++——内存管理
  • 微软NativeApi-NtQuerySystemInformation
  • 【WPF.NET开发】WPF中的对话框
  • 拆分降采样与归一化(LN和BN)
  • websocket vue操作
  • 快速学会绘制Pyqt5中的所有图(下)
  • Kafka安全性探究:构建可信赖的分布式消息系统
  • 二叉树的非递归遍历(详解)
  • 一款可无限扩展的软件定时器开源框架项目代码