FreeRTOS队列 | FreeRTOS九

news2024/11/26 23:24:47

目录

说明:

一、队列简介

1.1、什么是队列

1.2、队列的优势

1.3、队列实现功能

1.4、队列使用了解

1.5、队列特点

1.6、队列阻塞处理

1.7、队列出队入队过程

二、队列结构体

2.1、结构体了解

2.2、共同体了解

2.3、队列结构体存储区

三、队列API函数

3.1、创建队列函数

3.2、入队函数

3.3、出队函数

四、队列API函数实现步骤

4.1、队列创建API函数

4.2、队列写入数据API函数

4.3、队列读取数据API函数


说明:

关于内容:

1)以下内容多为概念了解与步骤分析

2)暂无个人示例代码,使用的是FreeRTOS的官方示例代码

3)若想移植代码测试的,请移步其它地方寻找,下文内容暂无个人示例代码供测试

关于其它:

1)操作系统:win 10

2)平台:keil 5 mdk

3)语言:c语言

4)板子:STM32系列移植FreeRTOS
 

一、队列简介

1.1、什么是队列

        队列是任务到任务任务到中断中断到任务数据交互的一种机制(一种消息机制)。

 

1.2、队列的优势

        1)相比于裸机常用的全局变量,在FreeRTOS中队列保证了数据的安全性

        2)当出现多个任务同时操作一个变量时,该变量的读写数据不安全,如下图1、2

               

                             图1                                                                          图2

1.3、队列实现功能

        1)FreeRTOS基于队列,实现了多种功能,包括队列集、互斥信号量、计数型信号量、二值信号量、递归互斥信号量等

        2)读队列与写队列做了保护,防止多任务干扰,在使用时只需调用相关的API函数即可,如下图3、4

                                               

                    图3                                                                                                     图4

1.4、队列使用了解

        1)在队列中可以存储数量有限、大小固定的数据。队列中的每一个数据称为“队列项目”,队列能够存储“队列项目”的最大数量称为队列的长度

        2)在创建队列时,就要指定队列长度以及队列项目的大小(数值不固定),如下图5

 图5

1.5、队列特点

        1)数据出队方式,通常采用“先进先出”(FIFO)的数据存储缓冲机制,先入队的数据先被读取;当然也可以配置“后进后出”(LIFO)方式

        2)数据传递方式,采用实际值传递,直接将数值放到队列中传递;也可以使用传递指针,一般在传递较大数据是采用指针传递

        3)多任务访问,队列不属于某个任务,任何任务和中断都可以向队列发送(入队)/读取(出队)消息

        4)出队、入队阻塞,当任务向一个队列发送(入队)消息时,可以指定一个阻塞时间,当此队列已满无法入队时,有如下三种情况:

        1、阻塞时间为0,直接返回不会继续等待

        2、阻塞时间为0-port_Max_DELAY,等待设定的阻塞时间,在该时间内未能入队,返回

        3、阻塞时间为port_Max_DELAY,一直等到可以入队为止

        说明:出队与入队一样,不在重复

1.6、队列阻塞处理

        1)入队阻塞,当队列已满,而依然有任务X要入队时,此时无法入队,首先将任务X状态列表项挂载到pxDelayedTaskList,然后将任务X事件列表项挂载到xTaskWaitingToSend

        2)出队阻塞,当队列为空,而依然有任务Y要入队时,此时无法出队(因为没有数据),首先将任务Y状态列表项挂载到pxDelayedTaskList,然后将任务X事件列表项挂载到xTaskWaitingToReceive

当出现多个任务同时入队到一个“满队列”时,这些任务都会进入阻塞状态,也就是说多个任务在等待同一个队列的空间,当出现一个空间,那个任务先进入就绪态?

        1)在多个任务中优先级最高的任务

        2)如果多个任务中优先级相同,等待时间最久的任务会进入就绪态

1.7、队列出队入队过程

        1)创建队列,如下图6

图6

        2)入队(位置填充),如下图7、8

 图7

 图8

        3)出队(位置填充),如下图9、10

 图9

 图10

二、队列结构体

2.1、结构体了解

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 uxltemSize;                                              /*队列项目的大小*/
        volatile int8_ _t cRxLock;                                                /*读取上锁计数器*/
        volatile int8_ _t cTxLock;                                                /*写入上锁计数器*/
/*其他的一些条件编译*/
}xQUEUE;

2.2、共同体了解

用于队列时:

typedef struct QueuePointers

{
        int8_ _t* pcTail;                             /*存储区的结束地址*/
        int8_ _t * pcReadFrom;                /*最后一个读取队列的地址*/
} QueuePointers_ _t;

用于互斥信号量和递归互斥信号量时:

typedef struct SemaphoreData

{
        TaskHandle_ t xMutexHolder;                         /* 互斥信号量持有者*/
        UBaseType_ t uxRecursiveCallCount;           /* 递归互斥信号量的获取计数器*/
} SemaphoreData_ t;

2.3、队列结构体存储区

如下图11:

 图11

三、队列API函数

使用队列的主要流程:创建流程-->写队列-->读队列

3.1、创建队列函数

1)函数名,xQueueCreate(),作用:动态方式创建队列

2)函数名,xQueueCreateStatic(),作用:静态方式创建队列

3)二者区别:动态方式创建队列内存由FreeRTOS所管理的内存动态分配,而静态创建需要用户自己分配内存

代码部分:

#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
    #define xQueueCreate( uxQueueLength, uxItemSize )    xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) )
#endif

参数解释:

uxQueueLength,含义:队列长度

uxItemSize ,含义:队列项目大小

queueQUEUE_TYPE_BASE ,含义:实现什么功能的队列

可选参数如下图12:

 图12

返回值解释:

返回:NULL,含义:队列创建失败

返回:其他值,含义:队列创建成功

3.2、入队函数

如下图13:

图13

代码部分:

如下图14:

 图14

入队位置,如下图15:

 图15

入队入口函数:

BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
                              const void * const pvItemToQueue,
                              TickType_t xTicksToWait,
                              const BaseType_t xCopyPosition );

参数解释:

xQueue,含义:待写入的队列

pvItemToQueue,含义:待写入消息

xTicksToWait,含义:阻塞超时时间

xCopyPosition ,含义:消息写入位置

返回值解释:

返回:pdTRUE,含义:队列写入成功

返回:errQUEUE_FULL,含义:队列写入失败

3.3、出队函数

如下图16:

 图16

代码部分:

BaseType_t xQueueReceive( QueueHandle_t xQueue,
                          void * const pvBuffer,
                          TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;

参数解释:

xQueue,含义:待读出队列

pvBuffer,含义:消息读取缓存区

xTicksToWait ,含义:阻塞超时时间

返回值解释:

返回:pdTRUE,含义:队列写入成功

返回:pdFALSE,含义:队列写入失败

说明:

此函数在成功读取消息后,会讲已读取的消息移除,而函数xQueuePeek函数不会移除已读消息

四、队列API函数实现步骤

4.1、队列创建API函数

名称:xQueueCreate

实现过程:

1)实际执行的是xQueueGenericCreate( )
2)xQueueGenericCreate( ( uxQueueLength ). ( uxltemSize ), (
queueQUEUE_ TYPE. BASE))
3)计算队列需要多大内存xQueueSizeInBytes = ( size. t)( uxQueueLength *
uxltemSize )
4)为队列申请内存,申请大小: sizeof( Queue, t) + xQueueSizeInBytes .前面部分存
放结构体成员,后面存放队列项
5)判断内存是否申请成功,成功即计算出队列项存储区的首地址
6)调用prvlnitialiseNewQueue ()初始化新队列pxNewQueue

1、初始化队列结构体成员变量
2、调用xQueueGenericReset ()复位队列

4.2、队列写入数据API函数

名称:xQueueSend

实现过程:

1)实际执行的是:xQueueGenericSend( QueueHandle_t xQueue,
                              const void * const pvItemToQueue,
                              TickType_t xTicksToWait,
                              const BaseType_t xCopyPosition );

2)进入临界区(关中断)

3)判断队列是否已满

4)队列有空闲位置,则

1、只有在队列有空闲位置或为覆写的情况才能写入消息

2、当有空闲位置或覆写时,将代写入消息按指定写入方式复制到队列中

3、判断是否有因为读不到消息而阻塞的任务,有则解除阻塞态,通过:xTaskRemoveFromEventList()函数实现-->判断调度器是否被挂起

        1、没有被挂起:将移除相应的事件列表项和状态列表项,并且将任务添加到就绪列表中

        2、已挂起:将移除事件列表项,将事件列表项添加到等待就绪列表项:xPendingReadyList,当调用恢复任务调度器xTaskResumeALL(),xPendingReadyList中任务就会被处理

4、退出临界区

5)队列已满,则

1、此时不能写入消息,因此要将任务阻塞

2、如果阻塞时间为0,代表不阻塞,直接返回队列已满的错误

3、如果阻塞时间不为0,任务需要阻塞,记录下此时系统节拍计数器的值和溢出次数,用于下面对阻塞时间进行补偿

4.3、队列读取数据API函数

名称:xQueueReceive

实现过程:

1)进入临界区

2)判断队列是否为空

3)有数据,则

1、使用函数prvCopyDataFromQueue()拷贝数据

2、队列项目个数减一

3、因为前面已经减了一个队列项,所以队列存在空位,如果xTaskWaitingToSend等待发送列表中,有任务,解除阻塞态,通过xTaskRemoveFromEventList()函数判断调度器是否被挂起:

        1、没有被挂起:将移除相应的事件列表项和状态列表项,并且将任务添加到就绪列表中

        2、已挂起:将移除事件列表项,将事件列表项添加到等待就绪列表项:xPendingReadyList,当调用恢复任务调度器xTaskResumeALL(),xPendingReadyList中任务就会被处理

        

4、退出临界区(开中断)

4)没有数据

1、此时读取不到消息,将任务阻塞

2、如果阻塞时间为0,代表不阻塞,直接返回队列为空的错误

3、如果阻塞时间不为0,任务需要阻塞,记录下此时系统节拍计数器的值和溢出次数,用于下面对阻塞时间进行补偿

4、判断阻塞时间补偿后,是否还需要继续阻塞,则

        1、需要:将任务的事件列表添加到等待接收列表中,将任务状态列表项添加到阻塞列表进行阻塞,队列解锁,恢复调度器

        2、不需要:队列解锁,恢复调度器、返回队列为空错误

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

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

相关文章

nacos配置中心搭建

网站每次更新版本都有短暂暂停,影响用户使用,返回经常不可用,需要改进 需要实现高可用,搭建负载均衡,实现jenkinsnacos不停机部署 nacos搭建预备环境准备 64 bit OS,支持 Linux/Unix/Mac/Windows&#x…

vue2.0项目第一部分

论坛项目后端管理系统服务器地址:http://172.16.11.18:9090swagger地址:http://172.16.11.18:9090/doc.html前端h5地址:http://172.16.11.18:9099/h5/#/前端管理系统地址:http://172.16.11.18:9099/admin/#/搭建项目vue create . …

JavaScript 变量提升

文章目录JavaScript 变量提升JavaScript 初始化不会提升在头部声明你的变量JavaScript 变量提升 JavaScript 中,函数及变量的声明都将被提升到函数的最顶部。 JavaScript 中,变量可以在使用后声明,也就是变量可以先使用再声明。 以下两个实…

前端面试题汇总

一:JavaScript 1、闭包是什么?利弊?如何解决弊端? 闭包是什么:JS中内层函数可以访问外层函数的变量,外层函数无法操作内存函数的变量的特性。我们把这个特性称作闭包。 闭包的好处: 隔离作用…

三、Linux文件 - Close函数讲解实战,文件权限

目录 1.Close函数 2.Linux文件权限 3.项目实战 3.1Close 项目实战1 3.2 文件权限项目实战 -Open函数设置权限 1.Close函数 参数说明 在Linux系统库的定义&#xff1a; int close(int fd) 包含的头文件 #include <unistd.h> 功能就是简单的关闭文件 注&#x…

荧光素标记PEG衍生物Fluorescein-PEG-Acid,FITC-PEG-COOH

英文名称&#xff1a;FITC-PEG-COOH&#xff0c;Fluorescein-PEG-Acid 中文名称&#xff1a;荧光素-聚乙二醇-羧基 荧光素标记的聚乙二醇PEG衍生物的荧光波长为495 nm&#xff0c;发射大约515 ~ 520 nm处有最大吸收。FITC组可以很容易地从它的黄色和绿色荧光。额外的功能&…

Python算法:深度优先搜索—DFS(模板及其样例)

深度优先搜索搜索 【介绍】 • 沿着一条路径一直搜索下去&#xff0c;在无法搜索时&#xff0c;回退到刚刚访问过的节点。 • 并且每个节点只能访问一次。 • 本质上是持续搜索&#xff0c;遍历了所有可能的情况&#xff0c;必然能得到解。 • 流程是一个树的形式&#xff0c;…

深度学习基础-机器学习基本原理

本文大部分内容参考《深度学习》书籍&#xff0c;从中抽取重要的知识点&#xff0c;并对部分概念和原理加以自己的总结&#xff0c;适合当作原书的补充资料阅读&#xff0c;也可当作快速阅览机器学习原理基础知识的参考资料。 前言 深度学习是机器学习的一个特定分支。我们要想…

项目管理的前路,前辈能给一些意见吗?

什么是项目管理&#xff1f;关于项目管理的解释主要是基于国际项目管理三大体系不同的解释及本领域权威专家的解释!!!! 项目管理就是以项目为对象的系统管理方法&#xff0c;通过一个临时性的、专门的柔性组织&#xff0c;对项目进行高效率的计划、组织、指导和控制&#xff0c…

活动目录(Active Directory)管理,AD自动化

每个IT管理员几乎每天都在Active Directory管理中面临许多挑战&#xff0c;尤其是在管理Active Directory用户帐户方面。手动配置用户属性非常耗时、令人厌烦且容易出错&#xff0c;尤其是在大型、复杂的 Windows 网络中。Active Directory管理员和IT经理大多必须执行重复和世俗…

关于Zebec生态的改进提案,即将上线的 Nautilus 链

概括 在最初作为 Solana 原生应用程序推出一年后&#xff0c;Zebec 团队已经能够通过在 BNB和NEAR区块链上成功部署来扩大其产品的范围。 凭借继续向尽可能多的公司/协议/基金提供薪资工具和基础设施的雄心勃勃的计划&#xff0c;我们决定采用最终将使 Zebec生态系统及其核心…

情人节又到了 程序员高逼格表白套路 附源码

又到了每月都有的情人节了&#xff08;笑&#xff09; 一个相当重要的日子&#xff1a;214&#xff0c;不知道是从啥时候开始兴起来的&#xff0c;单身的羡慕着有对象的&#xff0c;有对象的羡慕着单身的&#xff0c; 但也有很大一部分单身人士等待着表白的好机会&#xff0c;毕…

08.程序环境和预处理

1. 程序的翻译环境和执行环境在ANSI C的任何一种实现中&#xff0c;存在两个不同的环境。第1种是翻译环境&#xff0c;在这个环境中源代码被转换为可执行的机器指令。第2种是执行环境&#xff0c;它用于实际执行代码。2. 详解编译链接2.1 翻译环境 //.obg组成一个程序的每个源文…

力扣方法总结:其他数据结构(单调栈等)

单调栈 单调栈代码模板 找下一个更大&#xff08;不是大于等于&#xff09;元素 vector<int> nextGreaterElement(vector<int>& nums) {int n nums.size();vector<int> res(n, -1);stack<int> s;// 从后向前构建单调栈for (int i n - 1; i >…

在 Eclipse 中创建 Maven 项目

1.在 Eclipse 中配置 MavenEclipse 中默认自带 Maven 插件&#xff0c;但是自带的 Maven 插件不能修改本地仓库&#xff0c;所以通常我们不使用自带的 Maven &#xff0c;而是使用自己安装的&#xff0c;在 Eclipse 中配置 Maven 的步骤如下&#xff1a; 1) 点击 Eclipse 中的 …

C# 引用DLL 静态字段和非静态字段

再讲一下如何引用dll动态链接库&#xff1a;右键项目----添加 --项目引用----选择你要添加的dll即可。在依赖项这里就可以看到。再在要用的项目那里using一下这个dll的命名空间&#xff1a;using 生成dll;然后就可以使用以下所说的两种方法去调用dll里的函数了。切记&#xff0…

KDZD832 智能蓄电池活化仪

一、产品概述 KDZD832 智能蓄电池活化仪&#xff08;2V-24V 一体机&#xff0c;适用于 2V、6V、12V/24V 蓄电池&#xff0c;以下简称活化仪&#xff09;&#xff0c;是专用于日常维护中对落后蓄电池处理的便携式产品&#xff0c;它具有四种独立的使用方式&#xff1a;电池放电…

python爬虫--beautifulsoup模块简介

BeautifulSoup 的引入 我们学习了正则表达式的相关用法&#xff0c;但是一旦正则写的有问题&#xff0c;可能得到的就不是我们想要的结果了&#xff0c;而且对于一个网页来说&#xff0c;都有一定的特殊的结构和层级关系&#xff0c;而且很多标签都有 id 或 class 来对作区分&…

Vue3+node.js实现webScoket双向通信

Vue3 webScoket方法封装 Node.js webScoket 方法封装 1.先实现服务端node.js scoket方法的封装 先安装ws(基于node.js开发的webScoket 库) npm install ws 2.新建一个webScoket.js文件 3.代码逻辑实现 const Scoket require(ws) // 当前scoket对象 let scoket {} //当前…

C++STL剖析(四)—— stack和queue的概念和使用

文章目录1. stack的介绍2. stack的构造3. stack的使用&#x1f351; push&#x1f351; top&#x1f351; pop&#x1f351; empty&#x1f351; size&#x1f351; swap&#x1f351; emplace4. queue的介绍5. queue的构造6. queue的使用&#x1f351; push&#x1f351; size…