FreeRTOS学习笔记(六)队列

2024-09-08 15:04
文章标签 学习 笔记 队列 freertos

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

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、队列的基本内容
    • 1.1 队列的引入
    • 1.2 FreeRTOS 队列的功能与作用
    • 1.3 队列的结构体
    • 1.4 队列的使用流程
  • 二、相关API详解
    • 2.1 xQueueCreate
    • 2.2 xQueueSend
    • 2.3 xQueueReceive
    • 2.4 xQueueSendFromISR
    • 2.5 xQueueReceiveFromISR
    • 2.6 uxQueueMessagesWaiting
    • 2.7 uxQueueSpacesAvailable
    • 2.8 vQueueDelete


前言

  队列(Queue) 是一种用于任务间通信和同步的重要机制。它允许不同任务或者中断服务例程之间交换数据,而无需直接共享变量。这种机制不仅确保数据在任务之间传递的安全性,还解决了多任务系统中的并发和同步问题。


一、队列的基本内容

1.1 队列的引入

  在以前的代码中,如果我们想让一个变量在不同函数中进行传递操作,下意识可能会想到全局变量,但是这种方式存在一个问题:当我们使用freertos时,低优先级的任务会被高优先级的任务打断,这意味着可能会导致变量的结果不可控。为了解决这个问题,我们引入了队列,他自带临界保护,我们只要进行相关的API操作即可。在队列中可以存储固定大小且有限的数据,其中每一个数据叫“队列项目”,而所能存储的最大“队列项目”的数量称为队列的长度。除了可以被多任务访问之外,队列还有以下的特性:

  • FreeRTOS 中的队列是先进先出的结构,即最先插入队列的数据会最先被读取;
  • 队列的长度和每个队列项的大小在创建时由用户指定
  • FreeRTOS 提供了阻塞模式和非阻塞模式的队列操作。如果任务需要立即返回,可以使用超时为 0 的非阻塞模式;如果任务愿意等待队列有空位或数据,可以设置阻塞时间(如 0~portMAX_DELAY)让任务进入阻塞状态;
  • FreeRTOS 中的队列在数据传递时通常会直接拷贝数据进行实值传输,当然也可以传递指针。

1.2 FreeRTOS 队列的功能与作用

  • 任务间通信:FreeRTOS 的队列可以让多个任务之间安全地传递数据。例如,一个任务可以向队列发送数据,另一个任务从队列读取数据。这使得不同任务之间可以高效地共享信息,而不需要频繁访问全局变量。
  • 任务与中断间通信:队列不仅适用于任务间通信,还适用于中断和任务之间的通信。FreeRTOS 提供了特定的 ISR(中断服务例程)函数,比如 xQueueSendFromISR() 和 xQueueReceiveFromISR(),可以让中断处理函数安全地与任务交换数据。
  • 同步与调度:当一个任务尝试从空队列中读取数据时,任务可以选择进入阻塞状态,直到有数据可读。当另一个任务或中断向队列中发送数据时,等待的任务会被唤醒并立即处理数据。这样,队列不仅传递数据,还能用作同步机制,协调任务间的执行顺序。
  • 队列引发的任务切换: 在 FreeRTOS 中,如果一个任务向队列发送数据,并唤醒了一个更高优先级的任务,该任务会立刻抢占当前任务进行执行。这使得队列不仅用于数据交换,还起到了一定的任务调度作用。

1.3 队列的结构体

  在 FreeRTOS 中,队列是通过一个结构体来实现的。虽然具体实现可能根据不同平台有所调整,但通常队列的结构体包含了队列长度、队列项大小、存储数据的缓冲区指针、队列的头尾指针、队列的同步机制(如等待队列的任务列表)等信息。在 FreeRTOS 的源码中,定义队列的结构体一般为 QueueDefinition,其在 queue.c 中实现,通常通过类型定义 QueueHandle_t 来间接引用该结构体。

struct QueueDefinition  
{int8_t *pcHead;          /* 指向队列存储区的指针(队列缓冲区的头部) */int8_t *pcTail;          /* 指向队列存储区的尾部 */int8_t *pcWriteTo;       /* 指向队列中下一个写入位置 */int8_t *pcReadFrom;      /* 指向队列中下一个读取位置 */UBaseType_t uxMessagesWaiting;  /* 队列中的消息数 */UBaseType_t uxLength;           /* 队列的长度(队列项的最大数量) */UBaseType_t uxItemSize;         /* 每个队列项的大小(以字节为单位) */TaskHandle_t xTasksWaitingToSend;   /* 等待发送的任务列表 */TaskHandle_t xTasksWaitingToReceive;/* 等待接收的任务列表 *//* 下面的成员用于同步多任务或中断访问队列 */BaseType_t xRxLock;           /* 接收锁,用于控制接收操作 */BaseType_t xTxLock;           /* 发送锁,用于控制发送操作 *//* Mutexes 和 Semaphores 使用的额外信息 */UBaseType_t uxQueueType;      /* 队列的类型(普通队列、互斥量、信号量等) */...
} xQUEQUE;

  值得一提的是,这个结构体中还包含了一个联合体,它的作用是允许 QueueDefinition 结构体根据队列类型的不同(普通消息队列、信号量、互斥量)共享不同的结构。具体而言:对于普通的消息队列,队列用 xQueue 这个结构来管理等待发送和等待接收的任务列表;对于互斥量,队列使用 xMutex 这个结构来管理递归计数和互斥量的持有者。通过这个联合体,队列的结构体可以根据不同的队列类型选择不同的字段来使用,从而节省内存,并让队列既能处理消息队列,也能处理信号量和互斥量。

 /* 通过联合体实现不同类型队列的支持 */union{/* 用于消息队列和信号量 */struct{UBaseType_t uxRecursiveCallCount;  /* 递归互斥量使用时的递归计数 */TaskHandle_t xMutexHolder;         /* 持有互斥量的任务句柄 */} xMutex;/* 用于普通队列 */struct{List_t xTasksWaitingToSend;        /* 等待发送的任务列表 */List_t xTasksWaitingToReceive;     /* 等待接收的任务列表 */} xQueue;} u;  /* 联合体名称 */

参数说明:

  • uxRecursiveCallCount 用于递归互斥量的递归调用计数,这样持有互斥量的任务可以多次锁定互斥量。
  • xMutexHolder 用于保存当前持有互斥量的任务句柄。

1.4 队列的使用流程

  1. 创建队列:可以指定队列的长度和每个队列项的大小(例如,传递一个整数,结构体,或者更复杂的数据)。
  2. 向队列发送数据:一个任务可以使用 xQueueSend() 或 xQueueSendToBack() 向队列中发送数据,如果队列已满,任务可以选择进入阻塞状态,直到队列有空位,或者直接返回发送失败。
  3. 从队列读取数据:任务可以使用 xQueueReceive() 从队列中读取数据,如果队列为空,任务可以选择阻塞,直到有数据可读取。
  4. 中断安全的队列操作:如果队列操作发生在中断服务例程中,FreeRTOS 提供了 xQueueSendFromISR() 和 xQueueReceiveFromISR() 等函数,以确保队列操作的线程安全。

二、相关API详解

  FreeRTOS 提供了丰富的队列相关 API,用于在任务之间或中断和任务之间传递数据,进行任务同步。队列机制是 FreeRTOS 中最常用的 IPC(进程间通信)工具之一。以下是一些常用的队列 API 及其功能介绍:

2.1 xQueueCreate

// 功能:创建一个新的队列,并返回该队列的句柄。
QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize);
  • 参数:
    • uxQueueLength:队列中可以容纳的最大数据项数
    • uxItemSize:每个队列项的大小(以字节为单位)
  • 返回值:
    • 成功:队列句柄
    • 失败:NULL

  这里简单提一下,xQueueCreate的实现是调用了xQueueGenericCreate这个的底层函数,所有的队列(包括普通队列、信号量、互斥量)都通过这个函数创建。通常我们不会直接调用 xQueueGenericCreate,而是使用更高层的 API,如 xQueueCreate、xSemaphoreCreate 等。

QueueHandle_t xQueueGenericCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize, uint8_t ucQueueType);
  • 参数说明
    • uxQueueLength:队列的长度,即队列中可以容纳的最大数据项数。
    • uxItemSize:每个队列项的大小(以字节为单位)。如果创建的是信号量或互斥量,这个值为 0。
    • ucQueueType:队列的类型,常见的类型有:
      • queueQUEUE_TYPE_BASE:普通队列
      • queueQUEUE_TYPE_SET:队列集
      • queueQUEUE_TYPE_MUTEX:互斥量
      • queueQUEUE_TYPE_BINARY_SEMAPHORE:二元信号量
      • queueQUEUE_TYPE_COUNTING_SEMAPHORE:计数信号量
  • 返回值
    • 成功:创建的队列的句柄
    • 失败:返回 NULL

2.2 xQueueSend

// 功能 :将一个项目发送到队列中,如果队列满,任务将阻塞直到有空间可用或超时(不可应用于中断)
BaseType_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);
  • 参数:
    • xQueue:队列的句柄
    • pvItemToQueue:指向要放入队列的数据项的指针
    • xTicksToWait:如果队列满,任务等待插入的时间(以 Tick 数表示),portMAX_DELAY 表示无限等待
  • 返回值:
    • 成功:pdPASS
    • 失败:errQUEUE_FULL(队列已满)

2.3 xQueueReceive

// 功能:从队列中接收一个项目,如果队列为空,任务将阻塞直到有数据可用或超时。
BaseType_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait);
  • 参数:
    • xQueue:队列的句柄
    • pvBuffer:指向接收数据项的缓冲区
    • xTicksToWait:如果队列为空,任务等待接收的时间(以 Tick 数表示),portMAX_DELAY 表示无限等待
  • 返回值:
    • 成功:pdPASS
    • 失败:errQUEUE_EMPTY(队列为空)

2.4 xQueueSendFromISR

// 功能:从中断服务例程(ISR)中向队列发送数据,与 xQueueSend 类似,但适用于中断上下文。
BaseType_t xQueueSendFromISR(QueueHandle_t xQueue, const void *pvItemToQueue, BaseType_t *pxHigherPriorityTaskWoken);
  • 参数:
    • xQueue:队列的句柄
    • pvItemToQueue:指向要放入队列的数据项的指针
    • pxHigherPriorityTaskWoken:如果发送数据后需要进行任务切换,设置为 pdTRUE
  • 返回值:
    • 成功:pdPASS
    • 失败: errQUEUE_FULL

2.5 xQueueReceiveFromISR

// 功能:从中断服务例程(ISR)中接收队列数据。与 xQueueReceive 类似,但适用于中断上下文。
BaseType_t xQueueReceiveFromISR(QueueHandle_t xQueue, void *pvBuffer, BaseType_t *pxHigherPriorityTaskWoken);
  • 参数:
    • xQueue:队列的句柄。
    • pvBuffer:指向接收数据项的缓冲区。
    • pxHigherPriorityTaskWoken:如果接收数据后需要进行任务切换,设置为 pdTRUE。
  • 返回值:
    • 成功:pdPASS
    • 失败:errQUEUE_EMPTY

2.6 uxQueueMessagesWaiting

// 功能:返回队列中当前存储的消息数。
UBaseType_t uxQueueMessagesWaiting(QueueHandle_t xQueue);
  • 参数:
    • xQueue:队列的句柄
  • 返回值:队列中已存储的消息数

2.7 uxQueueSpacesAvailable

// 功能:返回队列中剩余可用的空间数。
UBaseType_t uxQueueSpacesAvailable(QueueHandle_t xQueue);
  • 参数:
    • xQueue:队列的句柄。
  • 返回值:队列中剩余的可用空间数量

2.8 vQueueDelete

// 功能:删除队列并释放其占用的内存。
void vQueueDelete(QueueHandle_t xQueue);
  • 参数:
    • xQueue:要删除的队列句柄

免责声明:本文参考了网上公开资料,仅用于学习交流,若有错误或侵权请联系笔者。

这篇关于FreeRTOS学习笔记(六)队列的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

hdu1180(广搜+优先队列)

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

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

poj 3190 优先队列+贪心

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