当前位置: 首页 > news >正文

FreeRTOS Queue消息队列-笔记

FreeRTOS Queue消息队列-笔记

    • **一、进程间通信(IPC)概述**
      • 1. **进程的定义**
      • 2. **进程间通信的实现方式**
    • **二、队列的核心概念与作用**
      • 1. **队列的作用**
      • 2. **双缓冲区在ADC采样中的应用**
    • **三、队列的创建**
    • **四、队列的发送与接收操作**
      • 1. **向队列发送数据**
      • 2. **从队列接收数据**
    • **五、队列的典型应用场景**
      • 1. **ADC连续采样与双缓冲区**
        • **代码示例**
    • **六、任务通知(Task Notification)的替代方案**
      • 1. **任务通知的优势**
      • 2. **任务通知的使用**
        • **从ISR发送通知**
        • **从任务接收通知**
        • **示例:ADC中断通知任务**

一、进程间通信(IPC)概述

1. 进程的定义

在使用RTOS时有多个任务,还可以有多个中断的ISR。任务和ISR可以统称为进程。
任务与任务之间或者任务与ISR之间有时候需要进行通信或者同步,这称为进程间通信。
在这里插入图片描述
总结就是在FreeRTOS中,任务(Tasks)和中断服务程序(ISRs)统称为进程。多任务系统中,进程之间常需要数据传递和状态同步
例如:
在实际的ADC连续采集中,一般使用双缓中区,一个缓冲区存满之后用于读取和处理,而另一个缓冲区继续用于保存ADC转换结果数据。两个缓冲区交替使用以保证采集和处理的连续性。

进程间通信就是ADC中断ISR与数据处理任务之间的通信,在ADC中断ISR向缓冲区写入数据后,如果发现缓冲区满了,就可以发出一个标志信号,通知数据处理任务一直在阻塞状态下,等待这个信号的数据处理任务就可以退出。阻塞状态被调度为运行状态后,就可以及时的读取缓冲区的数据并进行处理。

2. 进程间通信的实现方式

FreeRTOS提供以下机制:

在这里插入图片描述

在这里插入图片描述

补充一个是在事件组后面:任务通知task notification。使用任务通知不需要创建任何的中间对象,可以直接从任务向任务或者从ISR向任务发送通知,传递一个通知值。任务通知可以模拟二值信号量、计数信号量或者长度为一的消息队列。使用任务通知通常效率更高,消耗内存更少好。


二、队列的核心概念与作用

1. 队列的作用

  • 数据缓冲:解决生产者-消费者问题(如ADC采样与数据处理的速率不匹配)。
  • 任务同步:通过阻塞等待数据,避免忙等待浪费CPU资源。
  • 优先级处理:支持FIFO或优先级插入。

2. 双缓冲区在ADC采样中的应用

  • 双缓冲区工作原理
    • 一个缓冲区用于采集数据,另一个用于处理数据。
    • 缓冲区满时通过队列通知任务处理,切换缓冲区继续采集。
  • 队列的作用:在ADC中断与数据处理任务之间传递缓冲区切换信号。

三、队列的创建

在FreeRTOS创建对象,如任务队列、信号量等,都有静态分配内存和动态分配内存两种方式。
在这里插入图片描述

函数原型
在这里插入图片描述

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

在这里插入图片描述

xQueueCreate实际上是一个宏函数,它调用的函数xQueueGenericCreate,这个函数是创建队列、信号量、互斥量等对象的通用函数。

QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength,UBaseType_t uxItemSize);

在这里插入图片描述

四、队列的发送与接收操作

1. 向队列发送数据

在这里插入图片描述
可以把数据写到队列头部,也可以写到尾部,这些函数有两个版本:在任务中使用、在ISR中使用。函数原型如下:

/* 等同于xQueueSendToBack 
往队列尾部写入数据,如果没有空间,阻塞时间为xTicksToWait 
*/
BaseType_t xQueueSend(QueueHandle_t    xQueue,                                const void       *pvItemToQueue,                                TickType_t       xTicksToWait                            );  
/*
* 往队列尾部写入数据,如果没有空间,阻塞时间为xTicksToWait 
*/
BaseType_t xQueueSendToBack(                                QueueHandle_t    xQueue,                                const void       *pvItemToQueue,                                TickType_t       xTicksToWait                            );
/*
* 往队列尾部写入数据,此函数可以在中断函数中使用,不可阻塞 
*/
BaseType_t xQueueSendToBackFromISR(                                      QueueHandle_t xQueue,                                     const void *pvItemToQueue,                                      BaseType_t *pxHigherPriorityTaskWoken                                   ); 
/* 
* 往队列头部写入数据,如果没有空间,阻塞时间为xTicksToWait 
*/BaseType_t xQueueSendToFront(                                QueueHandle_t    xQueue,                                const void       *pvItemToQueue,                                TickType_t       xTicksToWait                            );
/*  
往队列头部写入数据,此函数可以在中断函数中使用,不可阻塞 
*/
BaseType_t xQueueSendToFrontFromISR(QueueHandle_t xQueue,                                      const void *pvItemToQueue,                                      BaseType_t *pxHigherPriorityTaskWoken                                   );

这些函数用到的参数是类似的,统一说明如下:
在这里插入图片描述

2. 从队列接收数据

使用 xQueueReceive() 函数读队列,读到一个数据后,队列中该数据会被移除。
这个函数有两个版本:在任务中使用、在ISR中使用。函数原型如下:

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

BaseType_t xQueueReceiveFromISR(QueueHandle_t xQueue, void *pvBuffer, BaseType_t *pxTaskWoken);

参数说明如下:
在这里插入图片描述

五、队列的典型应用场景

1. ADC连续采样与双缓冲区

代码示例
// 定义双缓冲区
#define BUFFER_SIZE 100
uint16_t buffer1[BUFFER_SIZE];
uint16_t buffer2[BUFFER_SIZE];// 队列用于缓冲区切换信号
QueueHandle_t xADCQueue = xQueueCreate(1, sizeof(uint16_t*));// ADC中断服务程序
void ADC_IRQHandler(void) {static uint16_t *currentBuffer = buffer1;static uint16_t index = 0;// 读取ADC数据uint16_t data = ADC_GetValue();// 写入当前缓冲区currentBuffer[index++] = data;// 判断是否填满缓冲区if (index >= BUFFER_SIZE) {index = 0;// 切换缓冲区if (currentBuffer == buffer1) {currentBuffer = buffer2;} else {currentBuffer = buffer1;}// 通过队列通知任务处理数据xQueueSendToBackFromISR(xADCQueue, &currentBuffer, NULL);}
}// 数据处理任务
void vDataProcessingTask(void *pvParameters) {uint16_t *pBuffer;while (1) {// 等待缓冲区切换信号xQueueReceive(xADCQueue, &pBuffer, portMAX_DELAY);// 处理缓冲区数据ProcessData(pBuffer);}
}

六、任务通知(Task Notification)的替代方案

1. 任务通知的优势

  • 无需创建中间对象:直接从ISR或任务向任务发送通知。
  • 内存占用低:每个任务自带一个通知值,无需额外内存。
  • 效率更高:减少队列操作的开销。

2. 任务通知的使用

从ISR发送通知
BaseType_t xTaskNotifyFromISR(TaskHandle_t xTaskToNotify,uint32_t ulValue,eNotifyAction eAction,BaseType_t *pxHigherPriorityTaskWoken
);
从任务接收通知
BaseType_t xTaskNotifyWait(uint32_t ulBitsToClearOnEntry,uint32_t ulBitsToClearOnExit,uint32_t *pulNotificationValue,TickType_t xTicksToWait
);
示例:ADC中断通知任务
// 中断中发送通知
void ADC_IRQHandler(void) {xTaskNotifyFromISR(xDataProcessingTask, 0, eSetValueWithOverwrite, NULL);
}// 任务中等待通知
void vDataProcessingTask(void *pvParameters) {while (1) {ulTaskNotifyTake(pdTRUE, portMAX_DELAY);// 处理ADC数据}
}

功能关键函数适用场景
队列创建xQueueCreate() / xQueueCreateStatic()数据缓冲、任务同步
队列发送xQueueSend() / xQueueSendToBackFromISR()任务与ISR间的数据传递
队列接收xQueueReceive() / xQueueReceiveFromISR()任务等待数据处理
任务通知xTaskNotifyFromISR() / xTaskNotifyWait()轻量级同步替代方案
http://www.xdnf.cn/news/375895.html

相关文章:

  • AlimaLinux设置静态IP
  • 护网HVV初级蓝队面试题总结
  • Axure :基于中继器的列表删除 、 列表编辑
  • 自动语音拨号系统V2.6.0产品说明书
  • Dockers部署oscarfonts/geoserver镜像的Geoserver
  • BERT类模型
  • CenOS7切换使用界面
  • 推荐一款免费开源工程项目管理系统软件,根据工程项目全过程管理流程开发的OA 办公系统
  • 基于定制开发开源AI智能名片S2B2C商城小程序的公私域流量融合运营策略研究
  • 策略路由更改路径
  • Best Video下载器——抖音视频去水印工具
  • day21python打卡
  • 【Linux第三章】vim
  • HTTP/2概览及内核解析
  • excel大表导入数据库
  • comfyu BiRefNet-General模型下载及存放地方
  • JS正则表达式介绍(JavaScript正则表达式)
  • 《Python星球日记》 第51天:神经网络基础
  • 边缘计算从专家到小白
  • iperf3的介绍与舒勇
  • Kubernetes 生产实战(十五):生产环境敏感信息纳入Secret管理指南
  • MLOps 详解
  • 汇编语言的温度魔法:单总线温度采集与显示的奇幻之旅
  • Java动态代理超详细解析:三步+内存图(堆栈分析)
  • 批量统计PDF页数,统计图像属性
  • dify插件接入fastmcp示例
  • Flink 实时数据一致性与 Exactly-Once 语义保障实战
  • Linux架构篇、第四章_ELK与EFK-7.17.9的日志管理
  • 深入解析Vue3中ref与reactive的区别及源码实现
  • PPT图表怎么制作?说5款自己使用过的PPT图表制作工具