FreeRTOS实验使用02

news2024/11/29 13:28:14

1:队列集使用

主要就是函数xQueueSelectFromSet 返回值的判断,用于判断里面的消息谁有效

Pend (or block) on multiple RTOS queues and semaphores in a set (freertos.org)

官方给的例程更好,更规范

2:任务通知使用

xR = xTaskNotify(Task2_Handler,4,eIncrement); //返回值一直为1,分析源码返回值为pdPASS=1

xReturn =  ulTaskNotifyTake(pdFALSE ,portMAX_DELAY );//这个保持不变

pdTRUE:把通知值清零;pdFALSE:把通知值减一

 更改任务通知方式

任务通知方式如何理解--分析源码

 xTaskGenericNotify()源码分析

BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue )
	{
	TCB_t * pxTCB;
	BaseType_t xReturn = pdPASS;

		pxTCB = ( TCB_t * ) xTaskToNotify;//xTaskToNotify是任务句柄,接收方

		taskENTER_CRITICAL();
		{
			if( pulPreviousNotificationValue != NULL ) //不为NULL,就保存之前的值
			{
				*pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
			}

			switch( eAction ) //任务更新方式
			{
				case eSetBits	:
					pxTCB->ulNotifiedValue |= ulValue;//此时的ulValue的值为某一位,把该为置一
					break;

				case eIncrement	:
					( pxTCB->ulNotifiedValue )++;//把原先的值加一
					break;

				case eSetValueWithOverwrite	:
					pxTCB->ulNotifiedValue = ulValue;//覆盖原来的值
					break;

				case eSetValueWithoutOverwrite :
					if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )//如果你是第一次进来就执行if里面的,如果不是则执行下面的,一般都是第一次进来
					{
						pxTCB->ulNotifiedValue = ulValue;
					}
					else
					{
						/* The value could not be written to the task. */
						xReturn = pdFAIL;
					}
					break;

				case eNoAction:
					/* The task is being notified without its notify value being
					updated. */
					break;
			}

			traceTASK_NOTIFY();

			
		taskEXIT_CRITICAL();

		return xReturn;
	}

 ulTaskNotifyTake源码分析 

uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait )
	{
	uint32_t ulReturn;

		taskENTER_CRITICAL();
		{
			/* Only block if the notification count is not already non-zero. */
			if( pxCurrentTCB->ulNotifiedValue == 0UL )
			{
//判断你发送的通知值是否为0,为0表示没发送,那么把此时的状态变成阻塞等待
				/* Mark this task as waiting for a notification. */
				pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;

				if( xTicksToWait > ( TickType_t ) 0 )
				{
					prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
					traceTASK_NOTIFY_TAKE_BLOCK();

					/* All ports are written to allow a yield in a critical
					section (some will yield immediately, others wait until the
					critical section exits) - but it is not something that
					application code should ever do. */
					portYIELD_WITHIN_API();
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		taskEXIT_CRITICAL();

		taskENTER_CRITICAL();
		{
			traceTASK_NOTIFY_TAKE();
			ulReturn = pxCurrentTCB->ulNotifiedValue;

			if( ulReturn != 0UL )
			{
				if( xClearCountOnExit != pdFALSE )
				{
					pxCurrentTCB->ulNotifiedValue = 0UL;//二值信号量情况
				}
				else
				{
					pxCurrentTCB->ulNotifiedValue = ulReturn - 1;//然后赋值回去--计数型信号量
				}
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}

			pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
		}
		taskEXIT_CRITICAL();

		return ulReturn;
	}

模拟二值信号量

我们只需要关注有没有发通知即可,不需要关注发的内容是啥

 xR =  xTaskNotifyGive(Task2_Handler); //xR的值为1

xTaskNotifyGive这个函数自带加一,所以接收到了1,然后清零,等待下一次

xReturn =  ulTaskNotifyTake(pdTRUE ,portMAX_DELAY ); //xReturn的值为1

pdTRUE清零,为了下次继续,如果改成不清零,改成减一呢?

结果是一样的,发过去为1,再减一,变成0了,就不会继续下一次了,除非我们发的通知值为大于1的值

 xR =  xTaskNotify(Task2_Handler,4,eNoAction);  //结果NotifyTask is fail

分析上面的源码就知道为什么是错误了,因为它啥都没有干,所以错误

 xR =  xTaskNotify(Task2_Handler,4,eIncrement);//xReturn = 1,为什么不是4呢?因为我没有覆盖,源码上是原来的值加一,而原来的值是0,因此这个4是没用的

xR =  xTaskNotify(Task2_Handler,4,eSetValueWithOverwrite);//会打印四次,因为通知值变成了4覆盖了,接收到了4,然后减一,变成了3,此时又满足了,因此接收到了3,除非你清零就不会了

如果只是想单纯的接收值得话,需要更换另外一个接收函数xTaskNotifyWait

模拟计数信号量

发送者10ms延时,接收者1000ms延时,两者需要存在时间差,不然成功不了

任务通知发送键值,接收键值

这里可以衍生到发送其他数据啊等,但是一次性只能发送一个数据

 BaseType_t xReturn; 
    uint32_t pulNotificationValue;    
    while(1)
    {   
     // xReturn =  ulTaskNotifyTake(pdFALSE ,portMAX_DELAY ); //模拟信号量  //pdFALSE           pdTRUE
      xReturn =  xTaskNotifyWait(0,0XFFFF, &pulNotificationValue,portMAX_DELAY);
//        switch()
//        {
//             //对通知值进行操作
//        }
       if(xReturn == pdTRUE)
       {
            printf("pulNotificationValue = %ld\r\n",pulNotificationValue);
       }
       else
       {
       
            printf("NotifyTask is fail\r\n");
       }

任务通知发送设置不同标志位

按键0设置第二位(0X02),按键1设置第三位(0X04)

xTaskNotify(Task2_Handler,0X02,eSetBits); 

xTaskNotify(Task2_Handler,0X04,eSetBits);

 xReturn =  xTaskNotifyWait(0,0XFFFFFFFF, &pulNotificationValue,portMAX_DELAY);
0XFFFFFFFF是把标志位清零,为0的话,上一次的会被记录下来,因此会一直成立打印K0K1
  if(pulNotificationValue & 0X02)//如果成立,表示按键0按下
        {
            printf("K0\r\n");
            event_bit |= 0x02;
        }
         if(pulNotificationValue & 0X04)//如果成立,表示按键1按下
        {
            printf("K1\r\n");
            event_bit |= 0x04;
        }
        if(event_bit == (0x02 | 0x04 ))                             //如果成立,表示按键0和按键1都发生了
        {
             printf("K0K1\r\n");
            event_bit = 0;
        }

低功耗源码分析

#if ( configUSE_TICKLESS_IDLE != 0 )
		{
		TickType_t xExpectedIdleTime;

			/* It is not desirable to suspend then resume the scheduler on
			each iteration of the idle task.  Therefore, a preliminary
			test of the expected idle time is performed without the
			scheduler suspended.  The result here is not necessarily
			valid. */
			xExpectedIdleTime = prvGetExpectedIdleTime();//获取下一个任务的解锁时间,即进入低功耗的时间

			if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
			{
//如果大于
				vTaskSuspendAll();
				{
					/* Now the scheduler is suspended, the expected idle
					time can be sampled again, and this time its value can
					be used. */
					configASSERT( xNextTaskUnblockTime >= xTickCount );
					xExpectedIdleTime = prvGetExpectedIdleTime();

					if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
					{
						traceLOW_POWER_IDLE_BEGIN();
						portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );//这个就是核心函数
						traceLOW_POWER_IDLE_END();
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}
				}
				( void ) xTaskResumeAll();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		#endif /* configUSE_TICKLESS_IDLE */
	}

低功耗实际操作

就是操作两个函数即可--自己宏定义的函数

/* 低功耗模式 */
#define configPRE_SLEEP_PROCESSING(x)         PRE_SLEEP_PROCESSING()
#define configPOSR_SLEEP_PROCESSING(x)        POSR_SLEEP_PROCESSING()

 

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

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

相关文章

手把手教你从0到1通过 Express 完成图片上传并保存至阿里云OSS功能(附详细源码)

🧨 大家好,我是 Smooth,一名大三的 SCAU 前端er 🙌 如文章有误,恳请评论区指正,谢谢! ❤ 写作不易,「点赞」「收藏」「转发」 谢谢支持! 背景 近期一个项目由于缺人&…

遗传算法解决旅行商问题

问题描述旅行商问题(TSP). 一个商人欲从自己所在的城市出发,到若干个城市推销商品,然后回到其所在的城市。如何选择一条周游路线,使得商人经过每个城市一次且仅一次后回到起点,并使他所走过的路径最短&…

oom killer理解和日志分析:知识储备

参考:oom killer 详解 oom killer日志分析,这是前篇,准备一些基础知识 带着问题看: 1.什么是oom killer 是Linux内核设计的一种机制,在内存不足的时候,选择一个占用内存较大的进程并kill掉这个进程&…

【JVM系列】JVM内存结构

JVM内存结构 运行时数据区 JAVA运行时内存划分堆,方法区,虚拟机栈,本地方法栈和程序计数器。 线程私有的有: - 程序计数器 - 虚拟机栈 - 本地方法栈​ 线程共享的有: - 堆 - 方法区程序计数器 用来记录当前线程执…

Redundant Paths(双向图的缩点(边联通分量缩成点))

F-Redundant Paths_2022图论班第二章连通性例题与习题 (nowcoder.com) 为了从F(1 \leq F \leq 5000)F(1≤F≤5000)一块牧场(编号为1..F)到另一块牧场,贝西和牛群的其他成员不得不穿过烂苹果树附近。奶牛现在厌倦了经常被迫走一条特定的路,想要建造一些新…

YOLO-V5 系列算法和代码解析(六)—— 分布式训练

文章目录预备知识DPDDPDP和DDP对比YOLO-V5 实际使用参考链接预备知识 为了更好的理解分布式相关的内容,需要提前熟悉一些基本概念和特定的名称。分布式训练涉及到设备端(CPU,GPU),算法端(梯度更新&#xff…

项目团队承诺管理的3个重要因素

每一个项目都需要一个强有力的领导者,以获得适当的成功机会。与一个优柔寡断、缺乏经验的项目领导者相比,一个有组织的领导者在管理一个精心策划的项目时,更有可能取得项目的成功和客户的满意。再加上一个非常投入和负责任的项目团队&#xf…

[ docker相关知识 ] 删除 docker 拉取的镜像 -- 释放内存

🍬 博主介绍 👨‍🎓 博主介绍:大家好,我是 _PowerShell ,很高兴认识大家~ ✨主攻领域:【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 🎉点赞➕评论➕收藏 养成习…

Speckle 3d数据引擎Python开发实战

在这个教程中,我们将使用 Speckle 数据并使用它来创建一个超级简单的仪表板。 我们将从Speckle流中接收几何图形,更新数据,并使用它来使用 Plotly 和 Dash 进行一些计算和简单绘图。 我们假设你具有 Python 和 Speckle 的一般知识。 如果有任…

信号处理——MATLAB音频信号加噪、滤波

音频信号叠加噪声及滤波一、前言二、信号分析及加噪三、滤波去噪四、总结很抱歉大家,最近经常有朋友私信问我关于这篇信号处理的一些问题,因为最近比较忙所以没能一一回复,给大家说句抱歉,希望那些给我私信的人可以看到。大家问的…

golang 垃圾回收-三色标记法(白话版)

对于golang 垃圾回收的了解,我理解更多的就是了解,实际做项目能用到垃圾回收的知识点不多,但有些晦涩难懂的语言,是我们的绊脚石,对于技术怎么能理解就怎么记忆。 1. golang垃圾回收的基础:标记&#xff08…

ESNI 和ECH的前世今生

这边文章中提到过虽然 TLS 能够加密整个通信过程,但是在协商的过程中依旧有很多隐私敏感的参数不得不以明文方式传输,其中最为重要且棘手的就是将要访问的域名,即 SNI(Server Name Indication)。同时还有用于告知客户端…

javaEE高阶---MyBatis

一 : 什么是MyBatis MyBatis是更简单完成程序和数据库交互的工具,也就是更简单的操作和读取数据库的工具.MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 去除了几乎所有的 JDBC 代码以及设置参数和获取结果集的动作 . MyBatis …

[oeasy]python0037_终端_terminal_电传打字机_tty_shell_控制台_console_发展历史

换行回车 回忆上次内容 换行 和 回车 是两回事 换行 对应字节0x0ALine-Feed 水平 不动垂直 向上喂纸 所以是 feed 回车 对应字节0x0DCarriage-Return 垂直 不动水平 回到纸张左侧 可移动的打印头 运输字符 的 装置 (Carriage)回到 行首 所以是 Return tty、terminal、shell、…

【视觉SLAM】DM-VIO: Delayed Marginalization Visual-Inertial Odometry

L. v. Stumberg and D. Cremers, “DM-VIO: Delayed Marginalization Visual-Inertial Odometry,” in IEEE Robotics and Automation Letters, vol. 7, no. 2, pp. 1408-1415, April 2022, doi: 10.1109/LRA.2021.3140129. 论文阅读方法:Title,Abstract…

百趣代谢组学文献分享:学科交叉研究,微生物回收重金属机制研究

发表期刊:Environment International 影响因子:7.297 发表时间:2019年 合作单位:福建农林大学 百趣代谢组学文献分享,该文章是BIOTREE协助客户2019年发表在Environment International上的关于微生物回收重金属机制研…

Tomcat的Connector启动过程分析

一. 前言 前面分析了tomcat的整体架构和tomcat的启动过程,在分析启动过程的时候只讲了整体的启动过程,本篇来重点分析一下tomcat的Connector(连接器)组件的启动过程。 二.从Connector的构造开始 那么org.apache.catalina.connector.Connector是在什么…

文献学习06_利用句法指示符和句子上下文加强关系抽取

论文信息 Subjects: Computation and Language (cs.CL) (1)题目:Enhancing Relation Extraction Using Syntactic Indicators and Sentential Contexts (利用句法指示符和句子上下文加强关系抽取) (2&…

论文精读:RPM-Net: Robust Point Matching using Learned Features

论文地址:https://arxiv.org/pdf/2003.13479.pdf 点云配准任务 点云配准可以当做一个基础的上游任务,根据从不同视角下获取的点云数据配准为完整的点云数据,下游任务众多 基本任务:求一个变换矩阵,使得两个具有未知点的点云数据重合。 刚性与非刚性: 刚性配准:旋转和平…

Leetcode 121买卖股票的最佳时机

题目描述: 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔…