FreeRTOS队列 | FreeRTOS九
创始人
2024-05-23 18:30:14
0

目录

说明:

一、队列简介

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、不需要:队列解锁,恢复调度器、返回队列为空错误

相关内容

热门资讯

一处美丽的自然景观作文四年级... 一处美丽的自然景观作文四年级85篇 篇一大自然给人类带来了无尽的美景,其中有一处我觉得最美丽的自然景...
关于描写妈妈的作文400字四... 关于描写妈妈的作文400字四年级 篇一妈妈是我最敬爱的人,她是一个温柔而又坚强的女人。她总是默默地为...
四年级作文小小动物园600字... 四年级作文小小动物园600字 篇一小小动物园的一天今天,我和同学们来到了小小动物园,我们都非常兴奋。...
春天来了四年级作文300字【... 春天来了四年级作文300字 篇一春天的脚步渐渐地临近了,大地一片生机勃勃。我喜欢春天,因为春天里有温...
我的心愿四年级100字作文怎... 篇一:我的心愿四年级100字作文怎么写42篇第一篇内容:我希望成为一名优秀的画家我是一个喜欢画画的孩...
感动的事四年级作文300字【... 感动的事四年级作文300字 篇一我的小伙伴我有一个特别好的小伙伴,他叫小明。他是一个非常善良和乐于助...
回乡偶书【优选4篇】 回乡偶书 篇一 回乡偶书 篇二回乡偶书 篇三 重庆市忠县实验小学四年级二班:申晓航         ...
想象四年级作文400字(精简... 想象四年级作文400字 篇一我的未来世界我是一位四年级的学生,我有一个梦想,那就是拥有一个充满科技和...
四年级作文【精彩6篇】 四年级作文 篇一我喜欢的动物我喜欢的动物是小狗。小狗是一种可爱的动物,它们有着憨态可掬的外表和忠诚的...
四年级描写北京故宫的作文40... 四年级描写北京故宫的作文400字 篇一北京故宫是我国古代宫殿建筑的代表之一,它位于北京市中心,是中国...
四年级作文我的暑生活(通用6... 四年级作文我的暑生活 篇一我的暑假生活充满了欢乐和收获。这个暑假,我参加了许多有趣的活动,学到了很多...
玫瑰花和小雨珠四年级作文【通... 玫瑰花和小雨珠四年级作文 篇一玫瑰花和小雨珠我有一个好朋友,她叫小雨珠。她是我们班的班花,而我则是班...
我我快乐300字四年级作文8... 我快乐300字四年级作文 篇一我快乐的一天今天是我快乐的一天。早上我起床后,妈妈给我做了我最喜欢吃的...
我们这美丽的校园四年级作文(... 我们这美丽的校园四年级作文 篇一我热爱我的校园,因为它是如此美丽。每天早上,当我走进校园时,我都被各...
古老而神秘的海神庙四年级作文... 古老而神秘的海神庙四年级作文 篇一海神庙是一座古老而神秘的庙宇,位于一个小岛上。我和我的家人去参观了...
小书迷四年级作文【推荐6篇】 小书迷四年级作文 篇一看见书,我就忍不住心里狂喜。那是一种浓郁的书香,让我仿佛置身于一个神奇的世界。...
五一劳动节四年级作文(精选6... 五一劳动节四年级作文 篇一五一劳动节是每年的五月一日,也是我们最期待的假期之一。这个节日是为了表彰劳...
四年级写我的动物朋友的作文第... 四年级写我的动物朋友的作文第四单元 篇一我的宠物狗我家养了一只非常可爱的宠物狗,它的名字叫小黑。小黑...
热爱生命四年级作文【优秀6篇... 热爱生命四年级作文 篇一热爱生命生命是最宝贵的财富,我们每个人都应该热爱生命。生命只有一次,我们要珍...
以我发现了为题的作文【优选3... 以我发现了为题的作文 篇一我发现了一片神奇的花海今天,我偶然发现了一片令人惊叹的花海,仿佛置身于童话...