【学习FreeRTOS】第13章——FreeRTOS队列

news2024/11/19 22:34:52

1.队列简介

队列是任务到任务、任务到中断、中断到任务数据交流的一种机制(消息传递)
FreeRTOS基于队列, 实现了多种功能,其中包括队列集、互斥信号量、计数型信号量、二值信号量、 递归互斥信号量,因此很有必要深入了解 FreeRTOS 的队列 。

1.1.队列与全局变量的区别

在这里插入图片描述
在这里插入图片描述

  • 全局变量的弊端:数据无保护,导致数据不安全,当多个任务同时对该变量操作时,数据易受损
  • 队列的优点:读写队列做好了保护,防止多任务同时访问冲突,我们只需要直接调用API函数即可,简单易用

1.2.队列的特点

  • 数据入队出队方式:队列通常采用**“先进先出”(FIFO)的数据存储缓冲机制,即先入队的数据会先从队列中被读取,FreeRTOS中也可以配置为“后进先出”LIFO**方式;
  • 数据传递方式:FreeRTOS中队列采用实际值传递,即将数据拷贝到队列中进行传递, FreeRTOS采用拷贝数据传递,也可以传递指针,所以在传递较大的数据的时候采用指针传递
  • 多任务访问:队列不属于某个任务,任何任务和中断都可以向队列发送/读取消息
  • 出队、入队阻塞:当任务向一个队列发送消息时,可以指定一个阻塞时间,假设此时当队列已满无法入队
    若阻塞时间为0 :直接返回不会等待;
    若阻塞时间为0~port_MAX_DELAY :等待设定的阻塞时间,若在该时间内还无法入队,超时后直接返回不再等待;
    若阻塞时间为port_MAX_DELAY :死等,一直等到可以入队为止。出队阻塞与入队阻塞类似;

1.3.队列的属性

在队列中可以存储数量有限、大小固定的数据。队列中的每一个数据叫做“队列项目”,队列能够存储“队列项目”的最大数量称为队列的长度 。在创建队列时,就要指定队列长度以及队列项目的大小。

在这里插入图片描述
在这里插入图片描述

当多个任务写入消息给一个“满队列”时,这些任务都会进入阻塞状态,也就是说有多个任务 在等待同一 个队列的空间。当队列中有空间时,哪个任务会进入就绪态?
1、优先级最高的任务
2、如果大家的优先级相同,那等待时间最久的任务会进入就绪态

2.队列结构体介绍

typedef struct QueueDefinition 
{
    int8_t * 				pcHead							/* 存储区域的起始地址 */
    int8_t * 				pcWriteTo;        				/* 下一个写入的位置 */
    union
    {
        QueuePointers_t     xQueue; 
		SemaphoreData_t  	xSemaphore; 
    } u ;
    List_t 					xTasksWaitingToSend; 			/* 等待发送列表 */
    List_t 					xTasksWaitingToReceive;			/* 等待接收列表 */
    volatile 				UBaseType_t uxMessagesWaiting; 	/* 非空闲队列项目的数量 */
    UBaseType_t 			uxLength;						/* 队列长度 */
    UBaseType_t 			uxItemSize;                		/* 队列项目的大小 */
    volatile int8_t 		cRxLock; 						/* 读取上锁计数器 */
    volatile int8_t 		cTxLock;						/* 写入上锁计数器 */
   /* 其他的一些条件编译 */
} xQUEUE;

//当用于队列使用时:
typedef struct QueuePointers
{
     int8_t * 				pcTail; 						/* 存储区的结束地址 */
     int8_t * 				pcReadFrom;						/* 最后一个读取队列的地址 */
} QueuePointers_t;
//当用于互斥信号量和递归互斥信号量时 :
typedef struct SemaphoreData
{
    TaskHandle_t 			xMutexHolder;					/* 互斥信号量持有者 */
    UBaseType_t 			uxRecursiveCallCount;			/* 递归互斥信号量的获取计数器 */
} SemaphoreData_t;

在这里插入图片描述

3.队列相关API函数介绍

使用队列的主要流程:创建队列——写队列——读队列。

3.1.创建队列

  • 动态方式创建队列:xQueueCreate()【本文重点讲解】

  • 静态方式创建队列:xQueueCreateStatic()

区别:队列所需的内存空间由 FreeRTOS 从 FreeRTOS 管理的堆中分配,而静态创建需要用户自行分配内存。

#define xQueueCreate(uxQueueLength, uxItemSize)	
		xQueueGenericCreate((uxQueueLength), (uxItemSize),(queueQUEUE_TYPE_BASE ))
#define queueQUEUE_TYPE_BASE                  	( ( uint8_t ) 0U )	/* 队列 */
#define queueQUEUE_TYPE_SET                  	( ( uint8_t ) 0U )	/* 队列集 */
#define queueQUEUE_TYPE_MUTEX                 	( ( uint8_t ) 1U )	/* 互斥信号量 */
#define queueQUEUE_TYPE_COUNTING_SEMAPHORE    	( ( uint8_t ) 2U )	/* 计数型信号量 */
#define queueQUEUE_TYPE_BINARY_SEMAPHORE     	( ( uint8_t ) 3U )	/* 二值信号量 */
#define queueQUEUE_TYPE_RECURSIVE_MUTEX       	( ( uint8_t ) 4U )	/* 递归互斥信号量 */	
  • 形参uxQueueLength:队列长度
  • 形参uxItemSize:队列项目的大小
  • queueQUEUE_TYPE_BASE:宏定义,创建队列的类型,本文是队列
  • 返回值:NULL ,队列创建失败;其他值, 队列创建成功,返回队列句柄【句柄也即是队列的首地址】

3.2.写队列

  • xQueueSend() :往队列的尾部写入消息
  • xQueueSendToBack(): 同 xQueueSend()
  • xQueueSendToFront(): 往队列的头部写入消息
  • xQueueOverwrite(): 覆写队列消息(只用于队列长度为 1 的情况)
  • xQueueSendFromISR(): 在中断中往队列的尾部写入消息
  • xQueueSendToBackFromISR(): 同 xQueueSendFromISR()
  • xQueueSendToFrontFromISR(): 在中断中往队列的头部写入消息
  • xQueueOverwriteFromISR(): 在中断中覆写队列消息(只用于队列长度为 1 的情况)

头部写入与尾部写入的区别:头部写入从队列项1开始往后写(可循环),尾部写入从队列n开始写(可循环)

本文重点讲前四个,这几个写入函数调用的是同一个函数xQueueGenericSend( ),只是指定了不同的写入位置

#define queueSEND_TO_BACK                     ( ( BaseType_t ) 0 )		/* 写入队列尾部 */
#define queueSEND_TO_FRONT                    ( ( BaseType_t ) 1 )		/* 写入队列头部 */
#define queueOVERWRITE                        ( ( BaseType_t ) 2 )		/* 覆写队列*/

#define  	xQueueSend(  xQueue,   pvItemToQueue,   xTicksToWait  )	 					\    
	    	xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
#define  	xQueueSendToBack(  xQueue,   pvItemToQueue,   xTicksToWait  )					 \    
	    	xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
#define  	xQueueSendToFront(  xQueue,   pvItemToQueue,   xTicksToWait  ) 					\   
	    	xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT )
#define  	xQueueOverwrite(  xQueue,   pvItemToQueue  ) 								\    
	    	xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), 0, queueOVERWRITE )
BaseType_t	xQueueGenericSend(	QueueHandle_t 			xQueue, 
								const void * const 		pvItemToQueue, 
								TickType_t 				xTicksToWait,
								const BaseType_t 		xCopyPosition);
  • 参数xQueue:待写入的队列
  • 参数pvItemToQueue:待写入消息
  • 参数xTicksToWait:阻塞超时时间
  • 参数xCopyPosition:写入的位置
  • 返回值:pdTRUE,队列写入成功;errQUEUE_FULL ,队列写入失败

const void * const 表示一个不可修改的指针,它指向不可修改的 void 类型数据。void 指针通常用于表示未知类型的数据,而 const 修饰符确保无论是指针本身还是指向的数据都不会被修改。
无论是写入数字还是地址,都只需要把变量的地址传入即可,函数会自动赋值。

3.3.读队列

  • xQueueReceive() :从队列头部读取消息,并删除消息
  • xQueuePeek():从队列头部读取消息
  • xQueueReceiveFromISR() :在中断中从队列头部读取消息,并删除消息
  • xQueuePeekFromISR() :在中断中从队列头部读取消息

头部读取删除的底层原理:队列结构体成员uxMessagesWaiting的变化,删除则变化,不删除则不变化

BaseType_t	xQueueReceive(	QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait )
BaseType_t  xQueuePeek( 	QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait )
  • 形参xQueue:待读取的队列
  • 形参pvBuffer:信息读取缓冲区
  • 形参xTicksToWait:阻塞超时时间
  • 返回值:pdTRUE,读取成功;pdFALSE,读取失败

void * const 表示一个指向不可修改的数据的指针,但它可以指向任何类型的数据。这种类型的指针通常用于需要保护指针不被意外修改,但允许修改指向的数据的情况。
无论是读出数字还是地址,都只需要把变量的地址传入即可,函数会自动赋值。

4.队列操作实验

  • 实验目的:学习 FreeRTOS 的队列相关API函数的使用 ,实现队列的入队和出队操作。
  • 实验设计:将设计四个任务:start_task、task1、task2、task3
    start_task:用来创建task1和task2以及task3任务
    task1:当按键key0或key1按下,将键值拷贝到队列key_queue(入队);当按键key_up按下,将传输大数据,这里拷贝大数据的地址到队列big_date_queue中
    task2:读取队列key_queue中的消息(出队),打印出接收到的键值
    task3:从队列big_date_queue读取大数据地址,通过地址访问大数据

5.队列相关API函数解析

5.1.队列的创建API函数(动态创建)xQueueCreate

在这里插入图片描述

5.2.写队列(尾部写入)xQueueSend

在这里插入图片描述

5.3.读队列(读取并出队) xQueueReceive

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/927757.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

手把手教你部署Jenkins教程,小白也能学会(多图预警)!

背景 公司的前端、后端构建及部署工作都是人工去做,随着业务扩大,项目迭代速度变快,人员增多,各种问题都暴露出来,将通过一个简单案例分享一下基于Jenkins的前后端自动化工作流搭建的过程,搭建完这套工作流…

做好客户服务的方法五部曲!

在每个商业领域中,提供优质的客户服务是成功的一个关键因素。无论企业的规模大小如何,都需要始终坚守为客户提供长期高质量服务的原则,以赢得客户信任与忠诚。今天,就让我们进一步探讨一下,客户服务有哪些方法技巧&…

快速学习制作数据查询系统的方法

无论是老师、企业还是机构,都会有信息查询的需求。例如,老师可能需要制作一个成绩查询、等级查询、分宿舍分寝室查询、分班查询、录取情况查询、新生报名查询等系统,让学生家长可以自行查询。 同样地,企业或机构也希望制作工资条查…

规划 2023 年拥有实体店的 DTC 品牌的发展方向

2023 年,DTC 品牌应谨慎考虑扩张实体店,以此作为扩大影响力和服务客户群的另一种方式。只有当企业在数字领域取得一定程度的成功,并且拥有适当管理数字和实体店的资源时,才应该进行这种扩张。这里的前提是,如果生意不好…

DockerCompose介绍与使用

DockerCompose介绍与使用 1、DockerCompose介绍 DockerCompose用于定义和运行多容器 Docker 应用程序的工具。 通过 Compose可以使用 YAML 文件来配置应用程序需要的所有服务。一个使用Docker容器的应用,通常由多个容器组成,使用Docker Compose不再需要…

C语言易错点整理

前言: 本文涵盖了博主在平常写C语言题目时经常犯的一些错误,在这里帮大家整理出来,一些易错点会帮大家标识出来,希望大家看完这篇文章后有所得,引以为戒~ 一、 题目: 解答: 首先在这个程序中…

动捕设备助力打造沉浸式虚拟现实体验

在纪录片《超时空寻找》中,借助了实时动捕设备,基于三维数字人技术进行老战士与历史场景还原,让抗美援朝老战士可以通过虚拟现实技术,跨越时空与战友实现隔空对话。 随着动捕设备的不断发展,虚拟现实技术越来越成熟&a…

clickhouse ssb-dbgen数据构造 及 clickhouse-benchmark简单压测

一、 测试数据构造 1. 数据样例 官方文档有给出一批数据样例。优点是比较真实,缺点是太大了,动辄上百G不适合简单小测试 Anonymized Yandex.Metrica DatasetStar Schema BenchmarkWikiStatTerabyte of Click Logs from CriteoAMPLab Big Data Benchma…

超实用的小红书种草方案分享!纯干货

小红书以“生活、时尚、美妆”等主题内容吸引了大量用户,成为了品牌方的种草宝地。那么,如何在小红书上打造爆款内容,吸引万千粉丝呢?本文伯乐网络传媒将从独特的角度深度剖析小红书种草方案,为你提供新知。 制定小红书…

SEMIDRIVE X9U 插入 USB 不识别调试要点

一、前言 客户用芯驰 X9U 平台做的智能座舱产品,在烧写固件时发现,通过 USB 连接到 SSA 的 USB 接口,Windows 上无法识别出 USB 设备,一直处在 Ready 状态。 二、SEMIDRIVE X9U 插入 USB 不识别调试要点 ① 建议客户测量 SoC 的…

PDF校对:让您的文件无瑕疵

无论您是企业家、学生、教育者还是作家,我们都知道,提交或发布一个充满错误的PDF文件可能会给您的声誉或品牌带来严重损害。这就是为什么PDF校对如此关键的原因。现在,让我们深入了解PDF校对的重要性,以及如何确保您的文件尽可能完…

RabbitMQ默认监听的ip地址

RabbitMQ 默认监听所有可用 ip 地址,当Rabbitmq 所在的服务端节点上存在多 ip 时,只要客户端能与服务端任一 ip 通信,即可向 RabbitMQ 发送消息

黑马 小兔鲜儿 uniapp 小程序开发- 02首页模块

黑马 小兔鲜儿 uniapp 小程序开发- 01项目起步_软工菜鸡的博客-CSDN博客 本课程是全网首套用 vue3 加 TS 写的 uniapp 项目, 里面大量封装自己的组件库,课程从 uni-app 基础入手,按照9大电商业务模块逐步实现完整的电商购物流程业务&#xff…

【LeetCode-中等题】73. 矩阵置零

题目 题解一&#xff1a;使用标记数组 public void setZeroes(int[][] matrix) {int m matrix.length;int n matrix[0].length;boolean[] row new boolean[m];boolean[] col new boolean[n];for(int i0; i< m;i){for(int j 0;j<n;j){if (matrix[i][j] 0) row[i]col…

【SQL中DDL DML DQL DCL所包含的命令】

SQL中DDL DML DQL DCL所包含的命令 关于DDL、DML、DQL、DCL的定义和适用范围如下&#xff1a; 数据定义语言&#xff08;Data Definition Language&#xff0c;DDL&#xff09;&#xff1a; DDL用于创建、修改和删除数据库中的表、视图、索引等对象。它的主要命令包括CREATE、A…

230814期优橙5G网络优化就业班开班啦!这样的学习环境泰酷辣!~

230814期为期8天的基础班顺利结束&#xff01; 接下来就是为期3个月的就业班 小优橙一点都不敢耽搁时间 紧跟优橙老师教学节奏 今日通知 230814期优橙就业班今天已经正式开班&#xff01; 本次就业班有哪些新收获&#xff01; 快来跟着学员视角看看8天在优橙真实感受吧~…

2831. 找出最长等值子数组

2831. 找出最长等值子数组 C代码&#xff1a; int longestEqualSubarray(int* nums, int numsSize, int k){int* a calloc(numsSize 1, sizeof(int));int ans 0, cnt 0;int l 0;for (int r 0; r < numsSize; r) {a[nums[r]]; // 滑动窗口中的字符次数if (ans <…

解读:未来汇全新商业模式,消费+增值包模式营销方案套路?

解读&#xff1a;未来汇全新商业模式&#xff0c;消费增值包模式营销方案套路&#xff1f; 大家好&#xff0c;我是微三云营销策划总监胡佳东&#xff0c;一家软件开发公司负责人。 在如今竞争激烈的商业环境中&#xff0c;传统的实体经营方式面临着越来越大的挑战。无论是哪个…

Module not found: Error: Can‘t resolve ‘less-loader‘解决办法

前言&#xff1a; 主要是在自我提升方面&#xff0c;感觉自己做后端还是需要继续努力&#xff0c;争取炮筒前后端&#xff0c;作为一个全栈软阿金开发人员&#xff0c;所以还是需要努力下&#xff0c;找个方面&#xff0c;目前是计划学会Vue&#xff0c;这样后端有java和pytho…

什么是数据中心IP,优缺点是什么?

如果根据拥有者或者说发送地址来分类的话&#xff0c;可以将代理分为三类&#xff1a;数据中心ip,住宅ip,移动ip 本文我们来了解数据中心ip的原理以及他们的优势劣势&#xff0c;才能选择适合自己的代理。 一、什么是数据中心ip代理&#xff1f; 数据中心ip是由数据中心拥有…