新闻详情

新闻详情

首页 / 资讯中心 / 详情

FreeRTOS队列详解:从原理到实战

发布时间:2026/9/30 8:52:54来源:尧图网络
FreeRTOS队列详解:从原理到实战
1.1 前课准备1.1.1 课程内容了解 FreeRTOS 的队列掌握 FreeRTOS 队列的使用场景学会如何利用队列实现任务间的通信熟悉队列的 API。1.1.2 课程资料《FreeRTOS 中文实战教程》第 2 章。1.2 FreeRTOS 队列概述1.2.1 使用背景在实际的应用中常常会遇到一个任务或者中断服务函数需要和另外一个任务进行“沟通交流”这个“沟通交流”的过程其实就是消息传递的过程。在没有操作系统的时候两个应用程序进行消息传递一般使用全局变量的方式但是如果在使用操作系统的应用中用全局变量来传递消息就会涉及到“资源管理”的问题。FreeRTOS 对此提供了一个叫做“队列”的机制来完成任务与任务、任务与中断之间的消息传递。1.2.2 队列介绍队列是为了任务与任务、任务与中断之间的通信而准备的可以在任务与任务、任务与中断之间传递消息。队列中可以存储有限的、大小固定的数据项目。任务与任务、任务与中断之间要交流的数据保存在队列中叫做队列项目。队列所能保存的最大数据项目数量叫做队列的长度创建队列的时候会指定数据项目的大小和队列的长度。由于队列是用来传递消息的所以也称为消息队列。1.2.3 数据存储队列可以保存有限个具有确定长度的数据单元。队列可以保存的最大单元数目被称为队列的“深度”。在队列创建时需要设定其深度和每个单元的大小。通常情况下队列被作为 FIFO先进先出使用即数据由队列尾写入从队列首读出。当然由队列首写入也是可能的。往队列写入数据是通过字节拷贝把数据复制存储到队列中从队列读出数据则是把队列中的数据拷贝删除。读出一个字节数据队列中的数据就少一个1.2.4 多任务操作队列队列是具有自己独立权限的内核对象并不属于或赋予任何任务。所有任务都可以向同一队列写入和读出。一个队列由多方写入是经常的事但由多方读出倒是很少遇到。1.2.5 读阻塞当某个任务试图读一个队列时其可以指定一个阻塞超时时间。在这段时间中如果队列为空该任务将保持阻塞状态以等待队列数据有效。当其它任务或中断服务例程往其等待的队列中写入了数据该任务将自动由阻塞态转移为就绪态。当等待的时间超过了指定的阻塞时间即使队列中尚无有效数据任务也会自动从阻塞态转移为就绪态。由于队列可以被多个任务读取所以对单个队列而言可能存在多个任务处于阻塞状态以等待数据有效。这种情况下一旦队列数据有效这个任务就是所有等待任务中优先级最高的任务。而如果所有等待任务的优先级相同那么被解除阻塞的任务将是等待最久的任务。1.2.6 写阻塞同读队列一样任务也可以在写队列时指定一个阻塞超时时间。这个时间是当被写队列已满时任务进入阻塞态以等待队列空间有效的最长时间。由于队列可以被多个任务写入所以对单个队列而言也可能有多个任务处于阻塞状态以等待队列空间有效。这种情况下一旦队列空间有效只会有一个任务会被解除阻塞这个任务就是所有等待任务中优先级最高的任务。而如果所有等待任务的优先级相同那么被解除阻塞的任务将是等待最久的任务。1.3 队列的 API1.3.1 创建队列函数原型QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, UBaseType_t uxItemSize );函数功能创建一个队列深度为 uxQueueLength、数据大小为 uxItemSize 的队列。函数参数uxQueueLength队列深度保存最大的数据单元数目。uxItemSize每个数据单元的大小单位是字节。函数说明xQueueGenericCreate( ( uxQueueLength ), // 队列深度 ( uxItemSize ), // 每个数据单元大小 ( queueQUEUE_TYPE_BASE ) // 队列类型 )函数返回值NULL表示没有足够的堆空间分配给队列而导致创建失败。非 NULL创建成功返回队列的句柄。示例定义队列的句柄变量QueueHandle_t Queue_t;创建队列Queue_t xQueueCreate(10, 5);1.3.2 写入数据函数原型BaseType_t xQueueSend( QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait );函数功能向指定的队列写入数据写入的是队列的队尾。函数参数QueueHandle_t xQueue写入的队列的句柄。const void * pvItemToQueue写入的数据缓存空间。TickType_t xTicksToWait超时时间。函数说明xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK );函数返回值pdPASS数据被成功发送到队列。errQUEUE_FULL1、写阻塞没有设置超时时间2、写阻塞超时时间到达。中断服务函数专用xQueueSendFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken )函数原型BaseType_t xQueueSendToBack( QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait );函数功能向指定的队列写入数据写入的是队列的队尾。函数参数QueueHandle_t xQueue写入的队列的句柄。const void * pvItemToQueue写入的数据缓存空间。TickType_t xTicksToWait超时时间。函数说明xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK );xQueueSendToBackFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken )函数原型BaseType_t xQueueSendToFront( QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait );函数功能向指定的队列写入数据写入的是队列的队首。函数参数QueueHandle_t xQueue写入的队列的句柄。const void * pvItemToQueue写入的数据缓存空间。TickType_t xTicksToWait超时时间。函数说明xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT );xQueueSendToFrontFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken )示例定义队列的句柄变量QueueHandle_t Queue_t;创建队列Queue_t xQueueCreate(10, 5);向队列写入数据xQueueSend(Queue_t, ABCDE, 0);1.3.3 读取数据函数原型BaseType_t xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait );函数功能从指定的队列读取数据读取的是队列的队首并删除读取的数据。函数参数QueueHandle_t xQueue读取的队列的句柄。void * const pvBuffer读取的数据存放缓存空间。TickType_t xTicksToWait超时时间。函数返回值pdPASS数据被成功从队列读取。errQUEUE_FULL1、读阻塞没有设置超时时间2、读阻塞超时时间到达。xQueueReceiveFromISR( QueueHandle_t xQueue, void * const pvBuffer, BaseType_t * const pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;函数原型xQueuePeek( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;函数功能从指定的队列读取数据读取的是队列的队首不会删除读取的数据。函数参数QueueHandle_t xQueue读取的队列的句柄。void * const pvBuffer读取的数据存放缓存空间。TickType_t xTicksToWait超时时间。函数返回值pdPASS数据被成功从队列读取。errQUEUE_FULL1、读阻塞没有设置超时时间2、读阻塞超时时间到达。xQueuePeekFromISR( QueueHandle_t xQueue, void * const pvBuffer ) PRIVILEGED_FUNCTION;1.3.4 删除队列函数原型void vQueueDelete( QueueHandle_t xQueue );函数参数QueueHandle_t xQueue删除队列的句柄。1.4 队列实战1.4.1 实战 1创建两个任务一个任务获取光照强度和 MCU 内部温度然后写入到队列另一个任务进行读取并打印。注意所使用的模块一定不能有 SysTick 延时函数从现在开始就不能使用该延时函数。1.4.2 实战 2#include main.h QueueHandle_t Quete_Handler; TaskHandle_t TaskA_Handler; TaskHandle_t TaskB_Handler; TaskHandle_t TaskC_Handler; typedef struct{ char name[10]; u8 flag; } LED_Status; void Start_Task(void *pvParameters) { Quete_Handler xQueueCreate(4, sizeof(LED_Status)); xTaskCreate(Task_A, LED1_FZ, 100, NULL, 2, TaskA_Handler); xTaskCreate(Task_B, LED2_FZ, 100, NULL, 1, TaskB_Handler); xTaskCreate(Task_C, READ_STATUS, 100, NULL, 0, TaskC_Handler); vTaskDelete(NULL); } void Task_A(void *pvParameters) { LED_Status LED1 {LED_1, 0}; while(1) { LED_G_Tog; if(!GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_8)) LED1.flag 1; else LED1.flag 0; xQueueSend(Quete_Handler, LED1, 0); vTaskDelay(50); } vTaskDelete(NULL); } void Task_B(void *pvParameters) { LED_Status LED2 {LED_2, 0}; while(1) { LED_R_Tog; if(!GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_9)) LED2.flag 1; else LED2.flag 0; xQueueSend(Quete_Handler, LED2, 0); vTaskDelay(30); } vTaskDelete(NULL); } void Task_C(void *pvParameters) { LED_Status Status; LED_Status Dev[2]; while(1) { while(xQueueReceive(Quete_Handler, Status, 0) pdPASS) { if(strncmp(Status.name, LED_1, 5) 0) { Dev[0] Status; } else { Dev[1] Status; } } printf(name:%s,Led_Status:%d\r\n, Dev[0].name, Dev[0].flag); printf(name:%s,Led_Status:%d\r\n, Dev[1].name, Dev[1].flag); printf(\r\n); vTaskDelay(40); } vTaskDelete(NULL); }
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Why Cannot Large Language Models Ever Make True Correct Reasoning? 2026/9/30 11:05:23

Why Cannot Large Language Models Ever Make True Correct Reasoning?

文章总结与翻译 一、文章主要内容 本文围绕“大型语言模型(LLMs)为何无法实现真正正确推理”展开研究,核心内容可分为以下五部分: 引言:指出当前以ChatGPT为代表的基于LLMs的AIGC工具应用中,许多专家与非专业人士夸大LLMs的“推理能力”,作者认为这是概念模糊导致的错…

阅读更多 →
YOLOv8 PCB缺陷检测落地实战:从Gerber合成到RK3588部署 2026/9/30 11:05:07

YOLOv8 PCB缺陷检测落地实战:从Gerber合成到RK3588部署

简介:本资源是一份面向计算机专业本科生的毕业设计论文,聚焦电子制造领域关键问题——PCB板缺陷检测,为深度学习与工业质检结合的实践项目提供完整技术方案。论文基于YOLOv8目标检测框架,系统阐述了从数据集构建、模型训练调优、P…

阅读更多 →
阿里国际站代运营的坑有哪些?新手老板必看的防套路清单 2026/9/30 11:05:05

阿里国际站代运营的坑有哪些?新手老板必看的防套路清单

核心摘要代运营行业鱼龙混杂,“保效果”“低价包年”往往是套路的起点,签约前需重点审查服务流程和团队配置。判断代运营是否靠谱的关键,不在于对方承诺多少,而在于是否提供透明的数据汇报、明确的关键词和直通车操作方案。国际站…

阅读更多 →
旋转电磁铁控场系统|动态旋转磁场实验解决方案 2026/9/30 11:04:59

旋转电磁铁控场系统|动态旋转磁场实验解决方案

在磁性材料各向异性测试、动态旋转磁场模拟、磁器件角度性能标定、磁场姿态仿真等科研场景中,固定磁场设备已无法满足多角度、动态旋转、连续可调的实验需求。高精度旋转电磁铁控场系统集成卧式磁场发生单元、精密电动旋转平台、高稳直流励磁电源与高精度磁场采集模…

阅读更多 →
ScrapeGraphAI 的 models_tokens 模块全解析:跨 Provider 模型 Token 上限字典与分片机制 2026/9/30 11:04:59

ScrapeGraphAI 的 models_tokens 模块全解析:跨 Provider 模型 Token 上限字典与分片机制

网页爬虫人工智能AI 应用 【免费下载链接】Scrapegraph-ai Python scraper based on AI 项目地址: https://gitcode.com/GitHub_Trending/sc/Scrapegraph-ai 点击查看 免费下载 导读 ScrapeGraphAI 是面向 AI 的 Python 抓取框架,其核心能力之一是根据…

阅读更多 →
Docker Compose 一键部署 Redis + Redis-Commander 可视化管理工具 2026/9/30 11:04:59

Docker Compose 一键部署 Redis + Redis-Commander 可视化管理工具

Docker Compose 部署 Redis6.2 Redis‑Commander 可视化管理【redis有密码】-CSDN博客 一、方案简介 本文提供一套完整 docker-compose-redis.yml 编排文件,可一次性启动 Redis 6.2 服务与 Redis Commander 可视化管理面板,具备容器自重启、健康检查、…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉