FreeRTOS入门教程(任务通知)

文章目录

  • 前言
  • 一、什么是任务通知
  • 二、任务通知和队列,信号量的区别
  • 三、任务通知的优点和缺点
    • 1.优点
    • 2.缺点
  • 四、任务状态和通知值
  • 五、任务通知相关的函数
    • 发出通知
    • 取出通知
  • 六、任务通知具体使用
    • 1.实现轻量级信号量
      • 二进制信号量
      • 计数型信号量
    • 2.实现轻量级队列
  • 总结


前言

本篇文章将带大家学习任务通知的概念和使用方法。

一、什么是任务通知

FreeRTOS中的任务通知(Task Notification)是一种轻量级的同步机制,允许一个任务通知另一个任务已发生的事件或条件。这对于多任务系统中的协作和同步非常有用。以下是有关FreeRTOS任务通知的详细讲解:

任务通知的作用:
任务通知的主要作用是允许一个任务通知其他任务已发生的事件,而无需使用更重的互斥锁或信号量。这可以用于线程间的通信和同步,以及处理任务之间的依赖关系。

通知值(Notification Value):
任务通知包括一个32位的通知值,用于传递信息。通知值可以是整数或位掩码,具体的含义由应用程序自行定义。任务可以等待特定的通知值或位掩码,以便在通知发生时采取相应的行动。

二、任务通知和队列,信号量的区别

任务通知、队列和信号量是FreeRTOS中用于任务间通信和同步的不同机制,它们有不同的特点和适用场景:

1.任务通知(Task Notification):

用途:任务通知主要用于任务之间的事件通知和同步,一个任务向其他任务发送通知,以表明某些事件已发生。
特点:轻量级、高效,通常用于一对一或一对多的任务通信。
通信方式:通知是无数据的,只包含一个32位的通知值,任务可以等待特定的通知值。
适用场景:适用于任务之间的事件通知、依赖关系、同步等情况,以及需要高效且快速的通信。

使用任务通知时发送方可以直接将发送信息给接收方,不需要通过中间的结构体对象(信号量,队列结构体)。
在这里插入图片描述

2.队列(Queue):

用途:队列用于任务之间的数据传递,允许一个任务发送数据给另一个任务。
特点:队列是有缓冲区的,可以传输多个数据元素,支持FIFO(先进先出)顺序。
通信方式:队列是带数据的通信机制,任务可以发送和接收数据。
适用场景:适用于需要任务之间传递数据的情况,如生产者-消费者问题、数据采集等。

3.信号量(Semaphore):

用途:信号量用于控制对共享资源的访问,允许任务对资源的使用进行同步和互斥。
特点:信号量通常用于资源保护和互斥访问,可以是二进制信号量(互斥锁)或计数信号量(资源计数)。
通信方式:信号量通常用于任务之间互斥,以确保只有一个任务可以访问共享资源。
适用场景:适用于共享资源的访问控制、互斥操作等情况,如保护共享内存、硬件设备等。

使用队列,信号量时都需要创建出通信对象结构体,通过这个结构体进行通信。
在这里插入图片描述

总的来说,任务通知适用于事件通知和轻量级的同步,队列适用于任务之间的数据传递,而信号量适用于资源访问的同步和互斥。在选择合适的通信和同步机制时,应根据具体需求和任务之间的关系来决定使用哪种机制。有时,这些机制也可以结合使用,以满足更复杂的任务间通信和同步需求。

三、任务通知的优点和缺点

1.优点

1.轻量级和高效: 任务通知是一种轻量级的通信机制,它不需要大量的内存和处理时间来维护,因此非常高效。

2.适用于一对多通信: 任务通知适用于一对多的任务通信,一个任务可以通知多个等待通知的任务,这在某些场景下非常有用。

3.实时性强: 任务通知可以提供较低的延迟,因为一旦通知被发送,接收通知的任务可以立即响应。

4.支持不同类型的通知: 任务通知可以发送不同类型的通知,任务可以等待特定的通知类型。

5.无需额外的资源: 与消息队列等机制不同,任务通知不需要为数据缓冲区分配额外的内存,因此它更节省资源。

2.缺点

1.无数据传递: 任务通知本身不支持数据传递,只能传递一个32位的通知值。如果需要传递数据,你可能需要结合其他机制来实现。

2.适用性有限: 任务通知更适用于简单的事件通知和同步需求,对于复杂的数据交换和同步需求,可能需要使用其他机制,如消息队列或信号量。

3.不适用于多生产者-多消费者问题: 任务通知通常不适合解决多生产者和多消费者问题,因为它不提供数据缓冲区来处理多个生产者和消费者之间的数据共享。

4.不适合长期阻塞: 任务通知通常用于短期同步,如果任务需要长期等待,其他机制如消息队列可能更合适。

总的来说,任务通知是一种非常高效的任务间通信机制,适用于简单的事件通知和同步需求,但对于复杂的数据传递和同步问题,可能需要结合其他FreeRTOS机制来实现。选择合适的通信机制应根据具体的应用需求来决定。

四、任务状态和通知值

每个任务都有一个结构体: TCB(Task Control Block),里面有2个成员。

一个是uint8 t类型,用来表示通知状态。

volatile uint8_t ucNotifyState[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];

ucNotifyState[] 数组:

类型:volatile uint8_t
作用:通常用于存储任务通知的状态。
FreeRTOS允许任务等待多个通知。这个数组可能用于记录每个任务是否已经接收到通知,或者通知的处理状态。每个元素可能对应一个任务的通知状态。

任务通知的三种状态:

#define taskNOT_WAITING_NOTIFICATION              ( ( uint8_t ) 0 )

含义:任务处于未等待通知的状态。
初始状态或者任务已经完成了对通知的等待,准备进入下一个等待通知的周期。

#define taskWAITING_NOTIFICATION                  ( ( uint8_t ) 1 )

含义:任务正在等待通知的状态。
当任务调用 ulTaskNotifyTake 等待通知时,它的状态将变为等待通知状态。任务会一直保持在这个状态,直到它收到通知或者等待超时。

#define taskNOTIFICATION_RECEIVED                 ( ( uint8_t ) 2 )

含义:任务已经收到通知的状态。
当任务成功接收到通知时,其状态将从等待通知状态切换到通知已接收状态。任务可以通过调用 ulTaskNotifyTake 函数获取通知的值,并执行相应的操作。
一个是uint32 t类型,用来表示通知值。

volatile uint32_t ulNotifiedValue[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];

ulNotifiedValue[] 数组:

类型:volatile uint32_t
作用:通常用于存储任务接收到的通知值。
每个任务都可以使用 ulTaskNotifyTake 函数等待通知,并在接收到通知时获得相应的值。这个数组可能被设计为记录多个任务接收到的通知值。数组的每个元素对应一个任务。

五、任务通知相关的函数

发出通知

发出通知有两个函数可以使用,分别是xTaskNotifyGive和xTaskNotify。

xTaskNotifyGive(TaskHandle_t xTaskToNotify);

功能:向指定的任务发送一个通知。
参数:xTaskToNotify 是要通知的任务的句柄(handle)。
返回值:无。
详细说明:这个函数用于向另一个任务发送通知。通知的具体内容可以是一个比特位或者一个32位的值,取决于任务通知的类型。被通知的任务可以通过 ulTaskNotifyTake 函数获取通知的值。

xTaskNotify(TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction)

功能:向指定的任务发送一个通知,可以指定通知的值和通知的行为。
参数:
xTaskToNotify:要通知的任务的句柄(handle)。
ulValue:通知的值,可以是一个比特位或者32位的值。
eAction:通知的行为,例如覆盖之前的通知值或者增加到之前的通知值。
返回值:无。
详细说明:这个函数允许发送带有值的通知,并且可以选择通知的行为。同样,被通知的任务可以通过 ulTaskNotifyTake 函数获取通知的值。

xTaskNotifyGive和xTaskNotify区别:

xTaskNotifyGive:
用途:向指定的任务发送一个通知,但不提供通知的具体值。
示例用法:xTaskNotifyGive(xTaskHandle);
适用情况:当通知的具体值不关键,只是为了触发目标任务执行某个操作时,使用此函数。

xTaskNotify:
用途:向指定的任务发送一个通知,可以指定通知的具体值和通知的行为。
示例用法:xTaskNotify(xTaskHandle, ulValue, eAction);
适用情况:当通知的具体值对于目标任务的操作非常重要时,或者需要更精细的控制通知的行为时,使用此函数。

取出通知

取出通知有两个函数可以使用,分别是ulTaskNotifyTake和xTaskNotifyWait。

ulTaskNotifyTake(BaseType_t xClearCountOnExit, TickType_t xTicksToWait);

功能:等待接收任务通知。
参数:
xClearCountOnExit:标志是否在任务等待通知时清零通知计数。
xTicksToWait:等待通知的超时时间。
返回值:接收到的通知的值。
详细说明:任务调用这个函数等待接收通知。如果在超时时间内收到通知,任务将返回通知的值;否则,返回0。通知的具体值和行为由前面的 xTaskNotify 函数设置。

xTaskNotifyWait(uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait);

功能:等待接收任务通知,并且可以设置在进入和退出时要清零的通知比特位。
参数:
ulBitsToClearOnEntry:进入等待通知时要清零的通知比特位。
ulBitsToClearOnExit:退出等待通知时要清零的通知比特位。
pulNotificationValue:指向接收到的通知值的指针。
xTicksToWait:等待通知的超时时间。
返回值:如果在超时时间内收到通知,返回 pdTRUE;否则,返回 pdFALSE。
详细说明:这个函数允许更加细粒度的控制,可以在进入和退出等待通知的时候清零通知的比特位。同样,被通知的任务可以通过 ulTaskNotifyTake 函数获取通知的值。

ulTaskNotifyTake和xTaskNotifyWait区别:

ulTaskNotifyTake:
用途:等待接收任务通知,返回接收到的通知的值。
示例用法:ulNotifiedValue = ulTaskNotifyTake(pdFALSE, xTicksToWait);
适用情况:当只需等待通知并获取其值时,使用此函数。通常用于轻量级的通知接收。

xTaskNotifyWait:
用途:等待接收任务通知,可以设置在进入和退出时要清零的通知比特位,返回是否在超时时间内收到通知。
示例用法:xResult = xTaskNotifyWait(ulBitsToClearOnEntry, ulBitsToClearOnExit, &ulNotificationValue, xTicksToWait);
适用情况:当需要更灵活的通知等待,并且需要在等待前后清零通知比特位时,使用此函数。通常用于更复杂的通知场景。

六、任务通知具体使用

1.实现轻量级信号量

xTaskNotifyGive函数可以让通知值加1,ulTaskNotifyTake可以让通知值减1,而且可以设置ulTaskNotifyTake的第一个参数来决定,是否清除通知值,设置为pdTURE则清除通知值(实现二进制信号量),设置为pdFALSE则不清除通知值(实现计数型信号量)。

二进制信号量

void Task1Function(void * param)
{
	volatile int i = 0;
	while (1)
	{
		for (i = 0; i < 10000; i++)
			sum++;
		//printf("1");
		for (i = 0; i < 10; i++)
		{
			// xSemaphoreGive(xSemCalc);
			xTaskNotifyGive(xHandleTask2);
		}
		vTaskDelete(NULL);
	}
}

void Task2Function(void * param)
{
	int i = 0;
	int val;
	while (1)
	{
		//if (flagCalcEnd)
		flagCalcEnd = 0;
		//xSemaphoreTake(xSemCalc, portMAX_DELAY);
		val = ulTaskNotifyTake(pdTURE, portMAX_DELAY);
		flagCalcEnd = 1;
		printf("sum = %d, NotifyVal = %d, i = %d\r\n", sum, val, i++);
	}
}

计数型信号量

void Task1Function(void * param)
{
	volatile int i = 0;
	while (1)
	{
		for (i = 0; i < 10000; i++)
			sum++;
		for (i = 0; i < 10; i++)
		{
			xTaskNotifyGive(xHandleTask2);
		}
		vTaskDelete(NULL);
	}
}

void Task2Function(void * param)
{
	int i = 0;
	int val;
	while (1)
	{
		val = ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
		printf("sum = %d, NotifyVal = %d, i = %d\r\n", sum, val, i++);
	}
}

2.实现轻量级队列

xTaskNotify和xTaskNotifyWait可以实现轻量级队列,用于传输一个uint32_t类型的数值。

void Task1Function(void * param)
{
	volatile int i = 0;
	while (1)
	{
		for (i = 0; i < 10000; i++)
			sum++;
		for (i = 0; i < 10; i++)
		{
			xTaskNotify(xHandleTask2, sum, eSetValueWithOverwrite);
			sum++;
		}
		vTaskDelete(NULL);
	}
}

void Task2Function(void * param)
{
	int val;
	int i = 0;
	
	while (1)
	{
		xTaskNotifyWait(0, 0, &val, portMAX_DELAY);
		printf("sum = %d, i = %d\r\n", val, i++);
	}
}

总结

本篇文章就讲解到这里,下篇文章继续讲解FreeRTOS中的内容。

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

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

相关文章

数仓中数据清洗的方法

在数据采集的过程中&#xff0c;需要从不同渠道获取数据并汇集在数仓中&#xff0c;采集的原始数据首先需要进行解析&#xff0c;然后对不准确、不完整、不合理、格式、字符等不规范数据进行过滤清洗&#xff0c;清洗过的数据才能更加符合需求&#xff0c;从而使后续的数据分析…

【数据库】执行计划中二元操作对一趟扫描算法的应用,理解代价评估的应用和优化,除了磁盘代价还有CPU计算代价不容忽略

二元操作的一趟算法 ​专栏内容&#xff1a; 手写数据库toadb 本专栏主要介绍如何从零开发&#xff0c;开发的步骤&#xff0c;以及开发过程中的涉及的原理&#xff0c;遇到的问题等&#xff0c;让大家能跟上并且可以一起开发&#xff0c;让每个需要的人成为参与者。 本专栏会定…

Java中的异常语法知识居然这么好玩!后悔没有早点学习

学习异常后&#xff0c;发现异常的知识是多么的吸引人&#xff01;不仅可以用来标记错误&#xff0c;还可以自己定义一个异常&#xff0c;用来实现自己想完成的业务逻辑&#xff0c;接下来一起去学习吧 目录 一、异常的概念及体系结构 1.异常的概念 2.异常的体系结构 3.异常…

【数据处理】 -- 【两分钟】了解【最好】的方式 -- 【正则表达式】

直接匹配&#xff1b; 普通字符 元匹配&#xff1a; . 任意单字符 r’表示单引号里字符为其特殊含义&#xff0c;比如.不是句号是匹配符的意思 *任意次数&#xff08;换行结束&#xff09; 一次及以上 {3,4}指定次数,至少3次&#xff0c;最多4次|{3}固定4次 [\d.]单个任意…

软件工程简明教程

软件工程简明教程 何为软件工程&#xff1f; 1968 年 NATO&#xff08;北大西洋公约组织&#xff09;提出了软件危机&#xff08;Software crisis&#xff09;一词。同年&#xff0c;为了解决软件危机问题&#xff0c;“软件工程”的概念诞生了。一门叫做软件工程的学科也就应…

redis运维(二十)redis 的扩展应用 lua(二)

一 redis 的扩展应用 lua redis lua脚本语法 ① 什么是脚本缓存 redis 缓存lua脚本 说明&#xff1a; 重启redis,脚本缓存会丢失 下面讲解 SCRIPT ... 系列 SCRIPT ② LOAD 语法&#xff1a;SCRIPT LOAD lua代码 -->载入一个脚本,只是预加载,不执行思考1&#xff1…

吴恩达《机器学习》10-4-10-5:诊断偏差和方差、正则化和偏差/方差

一、诊断偏差和方差 在机器学习中&#xff0c;诊断偏差和方差是改进模型性能的关键步骤。通过了解这两个概念&#xff0c;能够判断算法的问题究竟是欠拟合还是过拟合&#xff0c;从而有针对性地调整模型。 1. 概念理解 偏差&#xff08;Bias&#xff09;&#xff1a; 表示模…

《微信小程序开发从入门到实战》学习三十一

3.4 开发参与投票页面 3.4.9 显示投票结果 在实际使用中&#xff0c;一个用户不能对同一个投票进行重复提交&#xff0c;因此需要向服务器端提交投票结果和提交用户ID。另外页面&#xff0c;需要完善。用户提交完投票后 &#xff0c;还需要显示投票目前的结果&#xff0c;提交…

C#,《小白学程序》第二十课:大数的加法(BigInteger Add)

大数的&#xff08;加减乘除&#xff09;四则运算、阶乘运算。 乘法计算包括小学生算法、Karatsuba和Toom-Cook3算法。 重复了部分 19 课的代码。 1 文本格式 using System; using System.Linq; using System.Text; using System.Collections.Generic; /// <summary>…

字符串函数

目录 读取字符串的函数 1.gets()函数 2.fgets()函数&#xff08;不是所有的编译器都支持例如CodeBlocks&#xff09; 3.scanf()函数 4.getchar()函数 输出字符串的函数 1.puts()函数 2.fputs()函数&#xff08;编译器不一定支持&#xff09; 3.printf()函数 4.putchar…

【开源】基于Vue.js的陕西非物质文化遗产网站

文末获取源码&#xff0c;项目编号&#xff1a; S 065 。 \color{red}{文末获取源码&#xff0c;项目编号&#xff1a;S065。} 文末获取源码&#xff0c;项目编号&#xff1a;S065。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 设计目标2.2 研究内容2.3 研究方法与…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《基于多尺度分量特征学习的用户级超短期负荷预测》

这篇文章的标题表明研究的主题是用户级超短期负荷预测&#xff0c;并且该预测方法基于多尺度分量特征学习。让我们逐步解读这个标题&#xff1a; 用户级&#xff1a; 这表示研究的焦点是在个体用户层面上进行的。负荷预测可能是指电力系统中的负荷&#xff0c;即电力需求。用户…

大模型能否生成搜索引擎的未来?

文&#xff5c;郝 鑫 编&#xff5c;刘雨琦 ChatGPT火爆之前&#xff0c;水面下&#xff0c;也有中国公司也在朝着智能助手的方向努力。夸克便是其中之一。在GPT风靡科技圈后&#xff0c;国内就开始陆续冒出一些大模型厂商。对当时夸克而言&#xff0c;做大模型毋庸置疑&am…

五种多目标优化算法(MOPSO、MOAHA、NSGA2、NSGA3、MOGWO)求解微电网多目标优化调度(MATLAB)

一、多目标优化算法简介 &#xff08;1&#xff09;多目标粒子群优化算法MOPSO 多目标应用&#xff1a;基于多目标粒子群优化算法MOPSO求解微电网多目标优化调度&#xff08;MATLAB代码&#xff09;-CSDN博客 &#xff08;2&#xff09;多目标人工蜂鸟算法&#xff08;MOAHA…

Redis-Redis 高并发分布式锁

集群分布式场景高并发 1.negix配置代理和路由 高并发场景超卖问题 1.使用原生redis控制超卖时(若是商品&#xff0c;则可以将商品id作为锁对象)&#xff0c;会遇到的问题 问题一&#xff1a;若直接使用&#xff1a;将获取锁的对象和设置的超时的时间分开&#xff0c;则不能控…

桥接设计模式

package com.jmj.pattern.bridge;/*** 视频文件(实现化角色)*/ public interface VideoFile {void decode(String fileName); }package com.jmj.pattern.bridge;public class RmvFile implements VideoFile{Overridepublic void decode(String fileName) {System.out.println(&…

论文阅读——MCAN(cvpr2019)

补充一下MCAN-VQA&#xff1a; 对图片的处理&#xff1a;首先输入图片到Faster R-CNN&#xff0c;会先设定一个判断是否检测到物体的阈值&#xff0c;这样动态的生成m∈[10,100]个目标&#xff0c;然后从检测到的对应的区域通过平均池化提取特征。第i个物体特征表示为&#xff…

ubuntu22.04系统下载程序和依赖,并拷贝到指定路径下

脚本1 apt install aptitude apt-get -d install xxx #xxx是待下载的安装包 mv /var/cache/apt/archives/* /home/tuners/1apt install aptitude apt-get -d install xxx mv /var/cache/apt/archives/*.deb /home/tuners/1 xxx 为程序包名称 /home/tuners/1为保存程序包的…

网络通信基础概念介绍

网络通信基础概念介绍 局域网LAN 局域网&#xff0c;即 Local Area Network&#xff0c;简称LAN。 局域网内的主机之间能方便的进行网络通信&#xff0c;又称为内网&#xff1b;局域网和局域网之间在没有连接的情况下&#xff0c;是无法通信的。 局域网是指在一个相对较小的…

微机课设--汇编语言在51单片机上写一个四位十进制加法器

代码如下 KEYVAL EQU 30HKEYTM EQU 31HKEYSCAN EQU 32HDAT EQU 33HSCANLED EQU 37HS_DAT EQU 38HD_DAT EQU 39HR_DATL EQU 3AHR_DATH EQU 3BH CALFLAG EQU 3CHFLAG BIT 00HORG 0000HLJMP MAINORG 000BHLJMP T0ISRORG 0030HMAIN:MOV SP,#5FHMOV TMOD,#01HMOV TH0,#0D8HMOV TL0,…