【FreeRTOS】队列的使用

news2024/11/30 10:49:40

队列的使用

  • 前言
  • 创建队列
  • 发送数据
  • 接收数据
  • 查询队列数据个数
  • 使用示例
    • 创建两个线程
    • 配置按键驱动
    • 编写按键发送子函数
    • 编写按键读取子函数

前言

基于 FreeRTOS 的应用程序由一组独立的任务构成——每个任务都是具有独立权限的小程序。这些独立的任务之间很可能会通过相互通信以提供有用的系统功能。FreeRTOS 中所有的通信与同步机制都是基于队列实现的;

创建队列

队列是具有自己独立权限的内核对象,并不属于或赋予任何任务。所有任务都可以向同一队列写入和读出。一个队列由多方写入是经常的事,但由多方读出倒是很少遇到。

xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, 
						   unsigned portBASE_TYPE uxItemSize );

unsigned portBASE_TYPE uxQueueLength:指定队列的长度,即最多可以存放的元素个数

unsigned portBASE_TYPE uxItemSize:队列中存储的元素的大小(占用的字节数)

返回值:返回NULL代表创建失败,没有足够的堆空间来创建当前队列;创建成功则返回队列的句柄。

发送数据

xQueueSendToBack()用于将数据发送到队列尾;而 xQueueSendToFront()用于将数据发送到队列首,这两个函数在中断中不可使用,在中断中应该采用xQueueSendToFrontFromISR()和xQueueSendToBackFromISR()他们可以在中断中实现和前面两个函数相同的功能(下一章节中断再说明);

portBASE_TYPE xQueueSendToFront( xQueueHandle xQueue, 
								const void * pvItemToQueue, 
								portTickType xTicksToWait );
								
portBASE_TYPE xQueueSendToBack( xQueueHandle xQueue, 
								const void * pvItemToQueue, 
								portTickType xTicksToWait );

xQueueHandle xQueue:目标队列的句柄。

const void * pvItemToQueue:入队元素的指针。队列将存储此指针指向的数据的备份。

portTickType xTicksToWait:指定等待队列有空间可以容纳新元素入队的最长等待(阻塞)时间,这种情况发生在队列已经满了的时候。如果需要等待,则任务会因为调用这个函数而进入阻塞状态,直到队列非满而能让这个任务写入数据或者指定的阻塞时间过期,才会转变为就绪态。如果此参数使用0,则当队列已经满了的时候,此函数立即返回而不阻塞。使用portMAX_DELAY作为参数将使得等待时间为无限长,直到队列非满而能让这个任务写入数据,注意如果要使用portMAX_DELAY为参数,则必须在FreeRTOSConfig.h将INCLUDE_vTaskSuspend定义为1。

返回值
pdPASS,当元素成功入队时返回pdPASS。例如,在限定超时时间(xTicksToWait非0)过期前成功入队。

errQUEUE_FULL,因为队列满而无法入队时返回errQUEUE_FULL。例如,在限定超时时间(xTicksToWait非0)过期后,队列一直为满而无法入队新元素。

由于队列可以被多个任务写入,所以对单个队列而言,也可能有多个任务处于阻塞状态以等待队列空间有效。这种情况下,一旦队列空间有效,只会有一个任务会被解除阻塞,这个任务就是所有等待任务中优先级最高的任务。而如果所有等待任务的优先级相同,那么被解除阻塞的任务将是等待最久的任务;

接收数据

xQueueReceive()用于从队列中接收(读取)数据单元。接收到的单元同时会从队列中删除。xQueuePeek()也是从从队列中接收数据单元,不同的是并不从队列中删出接收到的单元。xQueuePeek()从队列首接收到数据后,不会修改队列中的数据,也不会改变数据在队列中的存储序顺。
在中断中应该采用数 xQueueReceiveFromISR()(下一章节中断再说明);

portBASE_TYPE xQueueReceive( xQueueHandle xQueue, 
							const void * pvBuffer, 
							portTickType xTicksToWait );

portBASE_TYPE xQueuePeek( xQueueHandle xQueue, 
							const void * pvBuffer, 
							portTickType xTicksToWait );

xQueueHandle xQueue:目标队列的句柄。

const void * pvBuffer:用于存放读取到的队列元素的缓冲区,队列将把出队的元素拷贝到此缓冲区中。

portTickType xTicksToWait:参见xQueueSendToBack()函数的解释。

返回值
pdPASS,当成功从队列读取到元素时返回pdPASS。例如,在限定超时时间(xTicksToWait非0)过期前,成功读取到元素。

errQUEUE_EMPTY,因为队列空而无法出队时返回errQUEUE_EMPTY。例如,在限定超时时间(xTicksToWait非0)过期后,队列一直为空而无法读取元素。

由于队列可以被多个任务读取,所以对单个队列而言,也可能有多个任务处于阻塞状态以等待队列数据有效。这种情况下,一旦队列数据有效,只会有一个任务会被解除阻塞,这个任务就是所有等待任务中优先级最高的任务。而如果所有等待任务的优先级相同,那么被解除阻塞的任务将是等待最久的任务;

简单来说就是写队列和读队列是有先后顺序的,优先级高的先读写,优先级相同的情况下根据等待时间来判断,等待时间长的先读写;

查询队列数据个数

uxQueueMessagesWaiting()用于查询队列中当前有效数据单元个数,中断中使用uxQueueMessagesWaitingFromISR()替代;

unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle xQueue );

xQueueHandle xQueue:队列的句柄
返回值:队列中的元素个数,返回0代表队列为空

使用示例

创建两个线程

创建一个入队的线程和一个出队的线程

    xTaskCreate((TaskFunction_t )SenderTask,  		/* 任务入口函数 */
              (const char*    )"send",			/* 任务名字 */
              (uint16_t       )512,  			/* 任务栈大小 */
              (void*          )NULL,			/* 任务入口函数参数 */
              (UBaseType_t    )10, 				/* 任务的优先级 */
               NULL);	                        /* 任务控制块指针 */ 
              
              
    xTaskCreate((TaskFunction_t )RevcerTask,  		/* 任务入口函数 */
              (const char*    )"revc",			/* 任务名字 */
              (uint16_t       )512,  			/* 任务栈大小 */
              (void*          )NULL,			/* 任务入口函数参数 */
              (UBaseType_t    )10, 				/* 任务的优先级 */
               NULL);	                        /* 任务控制块指针 */ 

配置按键驱动

打开cubemx工程
在这里插入图片描述
配置引脚重新生成工程,这里需要注意生成完工程我们工程中前面的更改就需要重新做了,比如讲__NVIC_PRIO_BITS的4U改成4,屏蔽三个中断服务函数;
在这里插入图片描述
还需要注意的是配置正点原子的板子按键引脚需要上拉;

编写按键发送子函数

static void SenderTask(void *par)
{
    uint8_t key_state;
    BaseType_t err;
    while(1)
    {
        if((queue!=NULL)&&(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == 0)) 
        {
            while(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == 0); // 按键弹起
            key_state = KEY1_PRESS;
            err = xQueueSend(queue,&key_state,10);
            if(err==errQUEUE_FULL)   	//发送按键值
            {
                printf("数据发送失败\r\n");
            }
        }    
        if((queue!=NULL)&&(HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == 0)) 
        {
            while(HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == 0);
            key_state = KEY2_PRESS;
            err = xQueueSend(queue,&key_state,10);
            if(err==errQUEUE_FULL)   	//发送按键值
            {
                printf("数据发送失败\r\n");
            }
        }    
        vTaskDelay(100); // 去抖       
    }
}

编写按键读取子函数

static void RevcerTask(void *par)
{
    uint8_t key = 0;
    while(1)
    {
        if(queue!=NULL)
        {
            if(xQueueReceive(queue,&key,portMAX_DELAY))//请求消息Key_Queue
            {
                switch(key)
                {
                    case KEY1_PRESS:	
                        printf("KEY1_PRESS\r\n");
                        break;
                    case KEY2_PRESS:		
                        printf("KEY2_PRESS\r\n");
                        break;
                    default:break;
                }
            }
        }
        vTaskDelay(10);
    }
}

实验效果
在这里插入图片描述

后面的资源都会在这个连接更新

链接:https://pan.baidu.com/s/1nc1rfyLiMyw6ZhxiZ1Cumg?pwd=free
提取码:free

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/3079.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

leetcode算法每天一题010: 正则表达式,判断pattern和string是否匹配(动态规划)

题目描述 ‘.’ 匹配任意单个字符‘*’ 匹配零个或多个前面的那一个元素 PATTERNTRUEFALSEa.baab,abb,acba, ab,ba*bb,ab,aab,aaaba,abb,acbc*a.baab,caab,cccccacb,ccabbbaab,cabbbdp[i] [j] 的含义是当字符串 s 的长度为 i,模式串 p 的长度为 j 时,两…

KubeVela 插件指南:轻松扩展你的平台专属能力

KubeVela 插件(addon)可以方便地扩展 KubeVela 的能力。正如我们所知,KubeVela 是一个微内核高度可扩展的平台,用户可以通过模块定义(Definition)[1]扩展 KubeVela 的系统能力,而 KubeVela 插件…

C# Winform程序开发笔记

C#d的开发发展到今天,已经改进了不少,对于非常多的应用可以使用C#进行开发,也非常方便,希望以下笔记对于高级开发者(网络通信、线程应用)而言能有所帮助吧。 1、INI文件的读写操作 1.1 类文件 using System; using System.Collections.Generic; using System.IO; usin…

【SpringBoot笔记21】SpringBoot框架使用AOP + 自定义注解实现请求日志记录

这篇文章,主要介绍SpringBoot框架使用AOP 自定义注解实现请求日志记录。 目录 一、SpringBoot记录日志 1.1、环境搭建 1.2、配置FastJson 1.3、自定义LogRecord注解 1.4、定义日志实体类 1.5、创建HttpRequestUtil工具类 1.6、定义AOP切面 1.7、编写测试类…

arm服务器运行onlyoffice

公司的arm服务器上运行onlyoffice报错 是x86_64架构的镜像在arm服务器下不兼容 需要下载兼容arm架构的docker镜像 在dockerhub上 onlyoffice地址 Docker Hubhttps://hub.docker.com/r/onlyoffice/documentserver 下载兼容arm架构的镜像版本 # docker --version Docker ver…

《从0开始写一个微内核操作系统》5-页表映射

ChinOS https://github.com/jingjin666/GN-base/tree/chinos 页表需要多少空间 在第4节中,我们了解到,每一级页表实际上就是一个512大小的unsigned long数组,一个页表本身占用512*84K空间 /* PGD */ /* 每个ENTRY包含512G内存区域 */ typed…

JavaWeb传统商城(MVC三层架构)的促销功能模块【进阶版】

文章目录一.JavaWeb商城项目的促销功能模块【进阶版】开发过程记录1.1 项目背景1.2 需求分析1.3 开发流程/顺序二.促销页面(0.1颗星)2.1 需求介绍2.2 JSP页面2.3效果展示三,商品详情页面(0.2颗星)3.1 需求介绍和效果图3.2 数据库分析3.2 Servlet层3.3 Service层3.4 DAO层3.5 JS…

一本通1064;奥运奖牌计数

#include <iostream> using namespace std; int main() {int n, Jin, Yin, Tong;int JinSum 0, YinSum 0, TongSum 0, sum;cin >> n;for (int i 1; i < n; i) // 循环n次{cin >> Jin >> Yin >> Tong; // 输入一天获得的金银铜牌数JinSum …

InfluxDB学习记录(三)——influxdb的flux语法

什么是Flux Flux 是 InfluxData 的功能性数据脚本语言&#xff0c;设计用于查询、分析和处理数据&#xff0c;它是InfluxQL 和其他类似 SQL 的查询语言的替代品。 每个 Flux 查询都需要以下内容&#xff1a; 数据源时间范围数据过滤器 Flux代码示例 from(bucket:"example…

重装系统后打印机状态已暂停如何恢复

​当我们在使用打印机打印文件的时候&#xff0c;有时候会发现打印机状态已暂停&#xff0c;打印不下去了&#xff0c;这时候怎么恢复呢&#xff0c;其实只需要取消掉打印暂停就可以了&#xff0c;下面就和大家讲讲重装系统后打印机状态已暂停如何恢复吧。 打印机状态已暂停怎…

【前端】Vue+Element UI案例:通用后台管理系统-Home组件:卡片、表格

文章目录目标代码0.布局1.左上User卡片2.左下table卡片2.1数据&#xff1a;TableData.js2.2table2.3代码优化&#xff1a;循环3.右上数据卡片3.1数据&#xff1a;CountData3.2结构3.3布局3.4样式总代码Home.vue参考目标 红框内部分都是卡片&#xff0c;鼠标悬停会有阴影左下是表…

java计算机毕业设计基于安卓Android的天文观星系统app uniapp 小程序

项目介绍 信息技术的发展带来了大量的数据内容,在这些数据中,想要找到自己需要的只有通过搜索引擎。如今,通过百度去查找信息成为大众的首选,然而在经济利益的驱动下,许多百度来的信息都是商业内容,很难找到真实有用的实际信息。在互联网中平台,天文信息交流和资源共享是一个非…

【每日训练】进制转换

目录 题目链接&#xff1a; 测试用例&#xff1a; 解析&#xff1a; 程序&#xff1a; 题目链接&#xff1a; 进制转换_牛客题霸_牛客网 (nowcoder.com) 测试用例&#xff1a; 解析&#xff1a; 题目描述&#xff1a; 输入一个十进制数&#xff0c;转化为对应输入的几进制数…

微服务及其在app自动化领域的应用

微服务是一种软件开发技术- 面向服务的体系结构&#xff08;SOA&#xff09;架构样式的一种变体&#xff0c;它提倡将单一应用程序划分成一组小的服务&#xff0c;服务之间互相协调、互相配合&#xff0c;为用户提供最终价值。每个服务运行在其独立的进程中&#xff0c;服务与服…

5款可视化工具优缺点比对,谁赢了?

利用Excel表格进行汇报&#xff0c;底下坐着的领导可能会看起来眼花缭乱&#xff0c;但如果是以图表可视化的形式展现出来&#xff0c;那可简洁明了多了&#xff0c;不仅仅可以看到某个项目近几个月的走势&#xff0c;并且还能知道之后的决策。 可视化图表用什么工具做&#xf…

FP8训练调研

FP8训练调研 一、FP8训练相关技术要点总结 1、基于块的累加技术&#xff0c;减小低精度数之间相加的累积误差 2、随机舍入技术代替四舍五入&#xff0c;降低舍入误差 3、混合FP8技术&#xff0c;用1-4-3进行前向&#xff0c;1-5-2进行反向 4、设置指数偏移&#xff0c;使F…

windows搭建WebDAV服务,并内网穿透公网访问【无公网IP】

自己用Windows Server搭建了家用NAS主机&#xff0c;WebDAV的文件共享方式当然也是必不可少的。 本文使用的是WIN10 专业版。 1. 安装IIS必要WebDav组件 1.1 打开控制面板&#xff0c;查看方式改为“类别”&#xff0c;进入“程序”&#xff0c;“启用或关闭Windows功能” 1…

数据结构链表之无头单向循环链表的实现

文章目录前言1.链表的相关介绍1.什么是节点2.链表和顺序表的对比3.链表的种类2.链表的实现1.节点的定义和创建2.链表的相关函数接口的实现1.链表的创建2.数据的插入头插尾插指定位置插入3.数据的删除头删尾删指定位置删除4.打印显示节点数据5.数据查找6.链表销毁3.总结前言 之…

2022新版加壳工具-支持.NET虚拟化加密

.NET 虚拟化保护 .NET 程序的保护技术在对抗中不断演进&#xff0c;出现了控制流混淆、名称混淆、文件加壳、动态方法、JIT 加密等保护技术&#xff0c;这些保护技术都有其各自的优缺点&#xff0c;虽然组合起来也能达到一定的效果&#xff0c;但近几年已经流传出一些脱壳机和…

单点架构、集群架构、服务化架构、SOA、微服务到底有什么联系和关系?

本篇参考总结 IT老齐的学习笔记 原视频SOA面向服务架构 原视频智慧城市实践指南 &#xff08;书籍-SOA概述&#xff09; 最近我在负责研发智慧园区的智慧平台产品&#xff0c;目前需求阶段和设计阶段已经完成&#xff0c;正式开始开发阶段&#xff0c;但是作为一个算法类学习者…