FreeRTOS队列之向队列发送消息

2024-05-28 05:04

本文主要是介绍FreeRTOS队列之向队列发送消息,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本篇文章记录我学习FreeRTOS队列相关的知识,主要是关于向队列发送消息的部分。

一、函数原型

创建好队列以后就可以向队列发送消息了,FreeRTOS提供了8个向队列发送消息的API函数。

1、函数xQueueSend()、xQueueSendToBack()和xQueueSendToFront()

这三个函数都是用于向队列中发送消息的,这三个函数本质都是宏,其中函数xQueueSend()和xQueueSendToBack()是一样的,都是后向入队,即将新的消息插入到队列的后面。函数xQueueSendToToFront()是前向入队,即将新消息插入到队列的前面。然而!这三个函数最后都是调用的同一个函数: xQueueGenericSend()。这三个函数只能用于任务函数中,不能用于中断服务函数,中断服务函数有专用的函数,它们以“FromISR”结尾,这三个函数的原型如下:

参数:

 返回值:

 2、函数xQueueOverwrite()

此函数也是用于向队列发送数据的,当队列满了以后会覆写掉旧的数据,不管这个旧数据有没有被其他任务或中断取走。这个函数常用于向那些长度为1的队列发送消息,此函数也是一个宏,最终调用的也是函数xQueueGenericSend(),函数原型如下:

3、函数xQueueGenericSend()

此函数才是真正干活的,上面讲的所有的任务级入队函数最终都是调用的此函数,此函数也是我们后面重点要讲解的,先来看一下函数原型:

4、函数xQueueSendFromISR()、
xQueueSendToBackFromISR()、
xQueueSendToFrontFromISR()

这三个函数也是向队列中发送消息的,这三个函数用于中断服务函数中。这三个函数本质也是宏,其中函数xQueueSendFromISR ()和xQueueSendToBackFromISR ()是一样的,都是后向入队,即将新的消息插入到队列的后面。函数xQueueSendToFrontFromISR()是前向入队,即将新消息插入到队列的前面。这三个函数同样调用同一个函数xQueueGenericSendFromISR()。这三个函数的原型如下:

我们注意观察,可以看出这些函数都没有设置阻塞时间值。原因很简单,这些函数都是在中断服务函数中调用的,并不是在任务中,所以也就没有阻塞这一说了!

 5、函数xQueueOverwriteFromISR()

此函数是xQueueOverwrite()的中断级版本,用在中断服务函数中,在队列满的时候自动覆写掉旧的数据,此函数也是一个宏,实际调用的也是函数xQueueGenericSendFromISR(),此函数原型如下:

此函数的参数和返回值同上面三个函数相同。

6、函数xQueueGenericSendFromISR()

上面说了4个中断级入队函数最终都是调用的函数xQueueGenericSendFromISR(),这是真正干活的主啊,也是我们下面会详细讲解的函数,先来看一下这个函数的原型,如下:

二、任务级通用入队函数

不管是后向入队、前向入队还是覆写入队,最终调用的都是通用入队函数xQueueGenericSend(),这个函数在文件queue.c文件中由定义,缩减后的函数代码如下:

(1)、要向队列发送数据,肯定要先检查一下队列是不是满的,如果是满的话肯定不能发送的。当队列未满或者是覆写入队的话就可以将消息入队了。


(2)、调用函数prvCopyDataToQueue()将消息拷贝到队列中。前面说了入队分为后向入队、前向入队和覆写入队,他们的具体实现就是在函数 prvCopyDataToQueue()中完成的。如果选择后向入队queueSEND_TO_BACK 的话就将消息拷贝到队列结构体成员 pcWriteTo 所指向的队列项,拷贝成功以后pcWriteTo增加 uxItemSize个字节,指向下一个队列项目。当选择前向入队queueSEND_TO_FRONT或者queueOVERWRITE的话就将消息拷贝到u.pcReadFrom所指向的队列项目,同样的需要调整u.pcReadFrom的位置。当向队列写入一个消息以后队列中统计当前消息数量的成员uxMessagesWaiting就会加一,但是选择覆写入队queueOVERWRITE的话还会将uxMessagesWaiting 减一,这样一减一加相当于队列当前消息数量没有变。

(3)、检查是否有任务由于请求队列消息而阻塞,阻塞的任务会挂在队列的xTasksWaitingToReceive列表上。
(4)、有任务由于请求消息而阻塞,因为在(2)中已将向队列中发送了一条消息了,所以调用函数xTaskRemoveFromEventList()将阻塞的任务从列表xTasksWaitingToReceive上移除,并且把这个任务添加到就绪列表中,如果调度器上锁的话这些任务就会挂到列表xPendingReadyList 上。如果取消阻塞的任务优先级比当前正在运行的任务优先级高还要标记需要进行任务切换。当函数xTaskRemoveFromEventList()返回值为pdTRUE的话就需要进行任务切换。


(5)、进行任务切换。
(6)、返回pdPASS,标记入队成功。


(7)、(2)到(6)都是非常理想的效果,即消息队列未满,入队没有任何障碍。但是队列满了以后呢?首先判断设置的阻塞时间是否为0,如果为О的话就说明没有阻塞时间。
(8)、由(7)得知阻塞时间为0,那就直接返回errQUEUE_FULL,标记队列已满就可以了。(9)、如果阻塞时间不为0并且时间结构体还没有初始化的话就初始化一次超时结构体变量,调用函数 vTaskSetTimeOutState()完成超时结构体变量xTimeOut 的初始化。其实就是记录当前的系统时钟节拍计数器的值 xTickCount和溢出次数xNumOfOverflows。


(10)、任务调度器上锁,代码执行到这里说明当前的状况是队列已满了,而且设置了不为0的阻塞时间。那么接下来就要对任务采取相应的措施了,比如将任务加入到队列的xTasksWaitingToSend列表中。
(11)、调用函数 prvLockQueue()给队列上锁,其实就是将队列中的成员变量cRxLock 和cTxLock 设置为queueLOCKED_UNMODIFIED。
(12)、调用函数xTaskCheckForTimeOut()更新超时结构体变量xTimeOut,并且检查阻塞时
间是否到了。
(13)、阻塞时间还没到,那就检查队列是否还是满的。
(14)、经过(12)和(13)得出阻塞时间没到,而且队列依旧是满的,那就调用函数vTaskPlaceOnEventList()将任务添加到队列的xTasksWaitingToSend 列表中和延时列表中,并且将任务从就绪列表中移除。注意!如果阻塞时间是 portMAX_DELAY并且宏INCLUDE_vTaskSuspend 为 1的话,函数 vTaskPlaceOnEventList()会将任务添加到列表xSuspendedTaskList 上。
(15)、操作完成,调用函数prvUnlockQueue()解锁队列。(16)、调用函数xTaskResumeAll)恢复任务调度器
(17)、阻塞时间还没到,但是队列现在有空闲的队列项,那么就在重试一次。
(18)、相比于第(12)步,阻塞时间到了!那么任务就不用添加到那些列表中了,那就解锁队列,恢复任务调度器。
(19)、返回errQUEUE_FULL,表示队列满了。

三、中断级通用入队函数

(1)、队列未满或者采用的覆写的入队方式,这是最理想的壮态。

(2)、读取队列的成员变量xTxLock,用于判断队列是否上锁。

(3)、将数据拷贝到队列中。
(4)、队列上锁了,比如任务级入队函数在操作队列中的列表的时候就会对队列上锁。
(5)、判断队列列表xTasksWaitingToReceive是否为空,如果不为空的话说明有任务在请求消息的时候被阻塞了。
(6)、将相应的任务从列表xTasksWaitingToReceive 上移除。跟任务级入队函数处理过程一样。
(7)、如果刚刚从列表xTasksWaitingToReceive 中移陈的仕分仇九纵比三里#元L冬i将那么标记pxHigherPriorityTaskWoken为pdTRUE,表示要进行任务切换。如果要进行任务切换
的话就需要在退出此函数以后,退出中断服务函数之前进行一次任务切换。
(8)、如果队列上锁的话那就将队列成员变量cTxLock 加一,农水进付」一次八队探IF,L队列解锁(prvUnlockQueue())的时候会对其做相应的处理。
(9)、返回pdPASS,表示入队完成。
(10)、如果队列满的话就直接返回errQUEUE_FULL,表示队列满。

这篇关于FreeRTOS队列之向队列发送消息的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1009609

相关文章

hdu1180(广搜+优先队列)

此题要求最少到达目标点T的最短时间,所以我选择了广度优先搜索,并且要用到优先队列。 另外此题注意点较多,比如说可以在某个点停留,我wa了好多两次,就是因为忽略了这一点,然后参考了大神的思想,然后经过反复修改才AC的 这是我的代码 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<

poj 3190 优先队列+贪心

题意: 有n头牛,分别给他们挤奶的时间。 然后每头牛挤奶的时候都要在一个stall里面,并且每个stall每次只能占用一头牛。 问最少需要多少个stall,并输出每头牛所在的stall。 e.g 样例: INPUT: 51 102 43 65 84 7 OUTPUT: 412324 HINT: Explanation of the s

poj 2431 poj 3253 优先队列的运用

poj 2431: 题意: 一条路起点为0, 终点为l。 卡车初始时在0点,并且有p升油,假设油箱无限大。 给n个加油站,每个加油站距离终点 l 距离为 x[i],可以加的油量为fuel[i]。 问最少加几次油可以到达终点,若不能到达,输出-1。 解析: 《挑战程序设计竞赛》: “在卡车开往终点的途中,只有在加油站才可以加油。但是,如果认为“在到达加油站i时,就获得了一

poj3750约瑟夫环,循环队列

Description 有N个小孩围成一圈,给他们从1开始依次编号,现指定从第W个开始报数,报到第S个时,该小孩出列,然后从下一个小孩开始报数,仍是报到S个出列,如此重复下去,直到所有的小孩都出列(总人数不足S个时将循环报数),求小孩出列的顺序。 Input 第一行输入小孩的人数N(N<=64) 接下来每行输入一个小孩的名字(人名不超过15个字符) 最后一行输入W,S (W < N),用

POJ2010 贪心优先队列

c头牛,需要选n头(奇数);学校总共有f的资金, 每头牛分数score和学费cost,问合法招生方案中,中间分数(即排名第(n+1)/2)最高的是多少。 n头牛按照先score后cost从小到大排序; 枚举中间score的牛,  预处理左边与右边的最小花费和。 预处理直接优先队列贪心 public class Main {public static voi

FreeRTOS-基本介绍和移植STM32

FreeRTOS-基本介绍和STM32移植 一、裸机开发和操作系统开发介绍二、任务调度和任务状态介绍2.1 任务调度2.1.1 抢占式调度2.1.2 时间片调度 2.2 任务状态 三、FreeRTOS源码和移植STM323.1 FreeRTOS源码3.2 FreeRTOS移植STM323.2.1 代码移植3.2.2 时钟中断配置 一、裸机开发和操作系统开发介绍 裸机:前后台系

Java并发编程之——BlockingQueue(队列)

一、什么是BlockingQueue BlockingQueue即阻塞队列,从阻塞这个词可以看出,在某些情况下对阻塞队列的访问可能会造成阻塞。被阻塞的情况主要有如下两种: 1. 当队列满了的时候进行入队列操作2. 当队列空了的时候进行出队列操作123 因此,当一个线程试图对一个已经满了的队列进行入队列操作时,它将会被阻塞,除非有另一个线程做了出队列操作;同样,当一个线程试图对一个空

ActiveMQ—消息特性(延迟和定时消息投递)

ActiveMQ消息特性:延迟和定时消息投递(Delay and Schedule Message Delivery) 转自:http://blog.csdn.net/kimmking/article/details/8443872 有时候我们不希望消息马上被broker投递出去,而是想要消息60秒以后发给消费者,或者我们想让消息没隔一定时间投递一次,一共投递指定的次数。。。 类似

FreeRTOS内部机制学习03(事件组内部机制)

文章目录 事件组使用的场景事件组的核心以及Set事件API做的事情事件组的特殊之处事件组为什么不关闭中断xEventGroupSetBitsFromISR内部是怎么做的? 事件组使用的场景 学校组织秋游,组长在等待: 张三:我到了 李四:我到了 王五:我到了 组长说:好,大家都到齐了,出发! 秋游回来第二天就要提交一篇心得报告,组长在焦急等待:张三、李四、王五谁先写好就交谁的

FreeRTOS学习笔记(六)队列

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、队列的基本内容1.1 队列的引入1.2 FreeRTOS 队列的功能与作用1.3 队列的结构体1.4 队列的使用流程 二、相关API详解2.1 xQueueCreate2.2 xQueueSend2.3 xQueueReceive2.4 xQueueSendFromISR2.5 xQueueRecei