2、FreeRTOS之队列管理

xQueueReceive() 用于从队列中接收 ( 读取)数据单元。接收到的单元同时会从队列
中删除。
xQueuePeek() 也是从从队列中接收数据单元,不同的是并不从队列中删出接收到
的单元。

 uxQueueMessagesWaiting()用于查询队列中当前有效数据单元个数。

写队列任务的代码实现:
这个任务被创建了两个实例,一个不
停地往队列中写数值 100 ,而另一个实例不停地往队列中写入数值 200 。任务的入口参
数被用来为每个实例传递各自的写入值。
static void vSenderTask( void *pvParameters ) 
{ 
	long lValueToSend; 
	portBASE_TYPE xStatus; 
	/* 该任务会被创建两个实例,所以写入队列的值通过任务入口参数传递 – 这种方式使得每个实例使用不同的
	值。队列创建时指定其数据单元为long型,所以把入口参数强制转换为数据单元要求的类型 */ 
	lValueToSend = ( long ) pvParameters; 
	/* 和大多数任务一样,本任务也处于一个死循环中 */ 
	for( ;; ) 
	{ 
		/* 往队列发送数据
		第一个参数是要写入的队列。队列在调度器启动之前就被创建了,所以先于此任务执行。
		第二个参数是被发送数据的地址,本例中即变量lValueToSend的地址。
		第三个参数是阻塞超时时间 – 当队列满时,任务转入阻塞状态以等待队列空间有效。本例中没有设定超
		时时间,因为此队列决不会保持有超过一个数据单元的机会,所以也决不会满。
		 */ 
		xStatus = xQueueSendToBack( xQueue, &lValueToSend, 0 ); 
		if( xStatus != pdPASS ) 
		{ 
		/* 发送操作由于队列满而无法完成 – 这必然存在错误,因为本例中的队列不可能满。 */ 
		vPrintString( "Could not send to the queue.\r\n" ); 
		} 
		/* 允许其它发送任务执行。 taskYIELD()通知调度器现在就切换到其它任务,而不必等到本任务的时
		间片耗尽 */ 
		taskYIELD(); 
	} 
}
读队列任务的代码实现:
读队列任务设定了 100 毫秒的阻塞超时时
间,所以会进入阻塞态以等待队列数据有效。一旦队列中数据单元有效,或者即使队列
数据无效但等待时间超过 100 毫秒,此任务将会解除阻塞。在本例中,将永远不会出
100 毫秒超时,因为有两个任务在不停地往队列中写数据。
static void vReceiverTask( void *pvParameters ) 
{ 
	/* 声明变量,用于保存从队列中接收到的数据。 */ 
	long lReceivedValue; 
	portBASE_TYPE xStatus; 
	const portTickType xTicksToWait = 100 / portTICK_RATE_MS; 
	/* 本任务依然处于死循环中。 */ 
	for( ;; ) 
	{ 
	/* 此调用会发现队列一直为空,因为本任务将立即删除刚写入队列的数据单元。 */ 
	if( uxQueueMessagesWaiting( xQueue ) != 0 ) 
	{ 
		vPrintString( "Queue should have been empty!\r\n" ); 
	} 
	/* 从队列中接收数据
	第一个参数是被读取的队列。队列在调度器启动之前就被创建了,所以先于此任务执行。
	第二个参数是保存接收到的数据的缓冲区地址,本例中即变量lReceivedValue的地址。此变量类型与
	队列数据单元类型相同,所以有足够的大小来存储接收到的数据。
	第三个参数是阻塞超时时间 – 当队列空时,任务转入阻塞状态以等待队列数据有效。本例中常量
	portTICK_RATE_MS用来将100毫秒绝对时间转换为以系统心跳为单位的时间值。
	 */ 
	xStatus = xQueueReceive( xQueue, &lReceivedValue, xTicksToWait ); 
	if( xStatus == pdPASS ) 
	{ 
		/* 成功读出数据,打印出来。 */ 
		vPrintStringAndNumber( "Received = ", lReceivedValue ); 
	} 
	else 
	{ 
		/* 等待100ms也没有收到任何数据。
		必然存在错误,因为发送任务在不停地往队列中写入数据 */ 
		vPrintString( "Could not receive from the queue.\r\n" ); 
	} 
	} 
}
main()函数的实现:
其在启动调度器之前创建了一个队列和三
个任务。尽管对任务的优先级的设计使得队列实际上在任何时候都不可能多于一个数据
单元,本例代码还是创建了一个可以保存最多 5 long 型值的队列
/* 声明一个类型为 xQueueHandle 的变量. 其用于保存队列句柄,以便三个任务都可以引用此队列 */ 
xQueueHandle xQueue; 
int main( void ) 
{ 
	/* 创建的队列用于保存最多5个值,每个数据单元都有足够的空间来存储一个long型变量 */ 
	xQueue = xQueueCreate( 5, sizeof( long ) ); 
	if( xQueue != NULL ) 
	{ 
		/* 创建两个写队列任务实例,任务入口参数用于传递发送到队列的值。所以一个实例不停地往队列发送
		100,而另一个任务实例不停地往队列发送200。两个任务的优先级都设为1。 */ 
		xTaskCreate( vSenderTask, "Sender1", 1000, ( void * ) 100, 1, NULL ); 
		xTaskCreate( vSenderTask, "Sender2", 1000, ( void * ) 200, 1, NULL ); 
		/* 创建一个读队列任务实例。其优先级设为2,高于写任务优先级 */ 
		xTaskCreate( vReceiverTask, "Receiver", 1000, NULL, 2, NULL ); 
		/* 启动调度器,任务开始执行 */ 
		vTaskStartScheduler(); 
	} 
	else 
	{ 
	/* 队列创建失败*/ 
	} 
	/* 如果一切正常,main()函数不应该会执行到这里。但如果执行到这里,很可能是内存堆空间不足导致空闲
	任务无法创建。第五章有讲述更多关于内存管理方面的信息 */ 
	for( ;; ); 
}
写队列任务在每次循环中都调用 taskYIELD() taskYIELD() 通知调度器立即进行任 务切换,而不必等到当前任务的时间片耗尽。某个任务调用 taskYIELD() 等效于其自愿 放弃运行态。由于本例中两个写队列任务具有相同的任务优先级,所以一旦其中一个任 务调用了 taskYIELD() ,另一个任务将会得到执行 调用 taskYIELD()的任务转移到 就绪态,同时另一个任务进入运行态。这样就可以使得这两个任务轮翻地往队列发送数据。

使用队列传递复合数据类型

通常接收方收到数 据后,需要知道数据的来源,并根据数据的来源决定下一步如何处理。一个简单的方式 就是利用队列传递结构体,结构体成员中就包含了数据信息和来源信息。

写队列任务具有最高优先级,所以队列正常情况下一直
是处于满状态。这是因为一旦读队列任务从队列中读走一个数据单元,某个写队列任务
就会立即抢占读队列任务,把刚刚读走的位置重新写入,之后便又转入阻塞态以等待队
列空间有效。
/* 定义队列传递的结构类型。 */ 
typedef struct 
{ 
	unsigned char ucValue; 
	unsigned char ucSource; 
} xData; 
/* 声明两个xData类型的变量,通过队列进行传递。 */ 
static const xData xStructsToSend[ 2 ] = 
{ 
	{ 100, mainSENDER_1 }, /* Used by Sender1. */ 
	{ 200, mainSENDER_2 } /* Used by Sender2. */ 
};

static void vReceiverTask( void *pvParameters ) 
{ 
	/* 声明结构体变量以保存从队列中读出的数据单元 */ 
	xData xReceivedStructure; 
	portBASE_TYPE xStatus; 
	/* This task is also defined within an infinite loop. */ 
	for( ;; ) 
	{ 
		/* 读队列任务的优先级最低,所以其只可能在写队列任务阻塞时得到执行。而写队列任务只会在队列写
		满时才会进入阻塞态,所以读队列任务执行时队列肯定已满。所以队列中数据单元的个数应当等于队列的
		深度 – 本例中队列深度为3 */ 
		if( uxQueueMessagesWaiting( xQueue ) != 3 ) 
		{ 
			vPrintString( "Queue should have been full!\r\n" ); 
		} 
		/* Receive from the queue. 
		第二个参数是存放接收数据的缓存空间。本例简单地采用一个具有足够空间大小的变量的地址。
		第三个参数是阻塞超时时间 – 本例不需要指定超时时间,因为读队列任会只会在队列满时才会得到执行,
		故而不会因队列空而阻塞 */ 
		xStatus = xQueueReceive( xQueue, &xReceivedStructure, 0 ); 
		if( xStatus == pdPASS ) 
		{ 
			/* 数据成功读出,打印输出数值及数据来源。 */ 
			if( xReceivedStructure.ucSource == mainSENDER_1 ) 
			{ 
				vPrintStringAndNumber( "From Sender 1 = ", xReceivedStructure.ucValue ); 
			} 
			else 
			{ 
				vPrintStringAndNumber( "From Sender 2 = ", xReceivedStructure.ucValue ); 
			} 
		} 
		else 
		{ 
			/* 没有读到任何数据。这一定是发生了错误,因为此任务只支在队列满时才会得到执行 */ 
			vPrintString( "Could not receive from the queue.\r\n" ); 
		} 
	} 
}

int main( void ) 
{ 
	/* 创建队列用于保存最多3个xData类型的数据单元。 */ 
	xQueue = xQueueCreate( 3, sizeof( xData ) ); 
	if( xQueue != NULL ) 
	{ 
		/* 为写队列任务创建2个实例。 The 
		任务入口参数用于传递发送到队列中的数据。因此其中一个任务往队列中一直写入
		xStructsToSend[0],而另一个则往队列中一直写入xStructsToSend[1]。这两个任务的优先级都
		设为2,高于读队列任务的优先级 */ 
		xTaskCreate( vSenderTask, "Sender1", 1000, &( xStructsToSend[ 0 ] ), 2, NULL ); 
		xTaskCreate( vSenderTask, "Sender2", 1000, &( xStructsToSend[ 1 ] ), 2, NULL ); 
		/* 创建读队列任务。
		读队列任务优先级设为1,低于写队列任务的优先级。 */ 
		xTaskCreate( vReceiverTask, "Receiver", 1000, NULL, 1, NULL ); 
		/* 启动调度器,创建的任务得到执行。 */ 
		vTaskStartScheduler(); 
	} 
	else 
	{ 
	/* 创建队列失败。 */ 
	} 
	/* 如果一切正常,main()函数不应该会执行到这里。但如果执行到这里,很可能是内存堆空间不足导致空闲
	任务无法创建。第五章将提供更多关于内存管理方面的信息 */ 
	for( ;; ); 
}

如果队列存储的数据单元尺寸较大,那最好是利用队列来传递数据的指针而不是对
数据本身在队列上一字节一字节地拷贝进或拷贝出。
但是,当你利用队列传递指针时,一定要十分小心地做到以
下两点:
1、指针指向的内存空间的所有权必须明确
原则上,共享内存在其指针发送到队列之前,其内容只允许被发送任务访问;
共享内存指针从队列中被读出之后,其内容亦只允许被接收任务访问。
2.、指针指向的内存空间必须有效
切忌用指针访问任务栈上分配的空间。因为当栈帧发生改变后,栈上的数据将不再
有效

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

简介:项目管理九大知识五大过程

前言 项目管理(Project Management,PM/Management by Projects,MBP) 在有限的资源约束下,运用系统的观点、方法和理论,对项目涉及的全部工作进行有效地管理。即从项目的投资决策开始到项目结束的全过程进行计划、组织、指挥、协调…

【首次抽奖】16G、32G免费送!云服务器选购推荐 京东云 阿里云 腾讯云对比 幻兽帕鲁 雾锁王国 省钱学生党

好消息:抽奖活动开启!时间:3月17日——3月24日 最高奖品:16G 6个月;32G 3个月 抽奖规则:B站点赞评论关注即可参与抽奖,3.24日公布获奖名单。 抽奖地址: 【首次抽奖】16G、32G免费…

TTS 擂台: 文本转语音模型的自由搏击场

对文本转语音 (text-to-speech, TTS) 模型的质量进行自动度量非常困难。虽然评估声音的自然度和语调变化对人类来说是一项微不足道的任务,但对人工智能来说要困难得多。为了推进这一领域的发展,我们很高兴推出 TTS 擂台。其灵感来自于LMSys为 LLM 提供的…

检索增强生成(RAG)应用的构建:LangChain与LlamaIndex的比较与选择

对于我要做RAG应用,我应该使用两者中的哪一个。或者说还是都使用? 在人工智能领域,检索增强生成(RAG)应用正变得越来越受欢迎,因为它们能够结合大型语言模型(LLMs)的自然语言处理能力…

不允许你不知道的Python私有属性和私有方法

​ 1.为什么要使用私有属性和私有方法 嘿,各位Python爱好者们,你们有没有遇到过这样的情况:你正在编写一个类,里面有一些属性或方法,你并不想让它们被外部直接访问或修改,但又需要某种方式来控制它们的访问…

【C/C++】C语言开发者必读:迈向C++的高效编程之旅

🧑 作者简介:阿里巴巴嵌入式技术专家,深耕嵌入式人工智能领域,具备多年的嵌入式硬件产品研发管理经验。 📒 博客介绍:分享嵌入式开发领域的相关知识、经验、思考和感悟,欢迎关注。提供嵌入式方…

VUE3项目学习系列--Axios二次封装(五)

Axios中文文档 | Axios中文网 (axios-http.cn) Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequ…

【回归预测】基于SSA-BP(麻雀搜索算法优化BP神经网络)的回归预测 多输入单输出【Matlab代码#69】

文章目录 【可更换其他算法,获取资源请见文章第6节:资源获取】1. BP神经网络2. 麻雀搜索算法3. SSA-BP神经网络模型的构建4. 部分代码展示5. 仿真结果展示 【可更换其他算法,获取资源请见文章第6节:资源获取】 1. BP神经网络 BP&…

新手向-从VNCTF2024的一道题学习QEMU Escape

[F] 说在前面 本文的草稿是边打边学边写出来的,文章思路会与一个“刚打完用户态 pwn 题就去打 QEMU Escape ”的人的思路相似,在分析结束以后我又在部分比较模糊的地方加入了一些补充,因此阅读起来可能会相对轻松(当然也不排除这是…

python之前端css样式(一)

css ID选择器 #c1{color:red;#边框为红色border:1px solid red; } <div id"c2">中国移动</div> 类选择器 .xx{color:blue; } <div class"xx">中国联通</div> 标签选择器 li{color: pink; } <ul><li>北京</li…

STM32输入捕获模式测频率

STM32频率的测量&#xff1a;高频适合使用的方法是测频法&#xff0c;低频适合使用的是测周法&#xff0c;&#xff08;其中使用测频法测量频率比较稳定&#xff0c;使用测周法测量频率的方式没有这么稳定&#xff0c;因为测周法只会通过一次的测量就能得出结果所以测试出来的频…

任务管理器进程结束错了,电脑显示白屏该怎么办

电脑就是一个全白&#xff0c;吓人的一批&#xff0c;毕竟以前出过cmd运行出错&#xff0c;然后黑屏&#xff0c;最后只能重装系统。这里出现白屏是还好的&#xff0c;切换了另外的用户&#xff0c;发现电脑上原来的文件还在&#xff0c;所有按下面的方法就解决了。 1.打开任务…

网络编程—DAY3

模拟面试 1.什么是IP地址 是给互联网上的每台主机分配的唯一标识 2.IP地址和mac地址的区别 mac地址是设备的硬件地址&#xff0c;ip地址是给主机分配的网络地址 3.当电脑从一个网络切换到另一个网络哪个会变 ip地址会变&#xff0c;mac地址不会变 4.什么是端口号 用于区…

leetcode 热题 100_环形链表 II

题解一&#xff1a; 哈希表&#xff1a;遍历链表&#xff0c;用哈希表存储遍历过的链表节点&#xff0c;判断链表节点是否在哈希表中存在&#xff0c;如果存在说明链表出现过&#xff0c;第一个重复出现的节点即为开始入环的第一个节点。 import java.util.HashSet;public cla…

【计算机网络】什么是http?

​ 目录 前言 1. 什么是HTTP协议&#xff1f; 2. 为什么使用HTTP协议&#xff1f; 3. HTTP协议通信过程 4. 什么是url&#xff1f; 5. HTTP报文 5.1 请求报文 5.2 响应报文 6. HTTP请求方式 7. HTTP头部字段 8. HTTP状态码 9. 连接管理 长连接与短连接 管线化连接…

无线局域网——wlan

目录 一.wlan的含义和发展 二.wlan技术带来的挑战 1.企业办公场景多样 2.位置速度的要求 3.安全的要求 4.规范的挑战 三.家庭和企业不同的部署需求 1.胖AP模式组网 2.AC瘦AP模式组网 3.组网模式的不同 四.三层隧道转发实验 1.拓扑 2.AP上线 核心交换机vlan ​编辑…

IIS上部署.netcore WebApi项目及swagger

.netcore项目一般是直接双击exe文件&#xff0c;运行服务&#xff0c;今天有个需求&#xff0c;需要把.netcore项目运行在IIS上&#xff0c;遇到了一个小坑&#xff0c;在这里记录一下。 安装IIS&#xff0c;怎么部署站点&#xff0c;这些过于简单就不细说了&#xff0c;不知道…

vue3+Ts项目按需引入Echarts,并封装成hooks

记录 vue3Ts 项目中&#xff0c;按需引入echarts并进行二次封装使用。 1、安装&#xff1a;npm i echarts 2、新增按需引入配置文件&#xff1a;echartsConfig.ts // 引入 echarts 核心模块&#xff0c;核心模块提供了 echarts 使用必须要的接口。 import * as echarts from …

代码随想录阅读笔记-字符串【反转字符串】

题目 编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。 不要给另外的数组分配额外的空间&#xff0c;你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 你可以假设数组中的所有字符都是 ASCII 码表中的可打印…

Web核心,HTTP,tomcat,Servlet

1&#xff0c;JavaWeb技术栈 B/S架构:Browser/Server&#xff0c;浏览器/服务器架构模式&#xff0c;它的特点是&#xff0c;客户端只需要浏览器&#xff0c;应用程序的逻辑和数据都存储在服务器端。浏览器只需要请求服务器&#xff0c;获取Web资源&#xff0c;服务器把Web资源…