FreeRTOS内部机制学习04(任务通知和软件定时器)
文章目录
- 何为任务通知?
- 任务通知使用例子
- 任务通知的优势以及劣势
- 优势
- 劣势
- 深入源码看看API函数内部干了什么
- 函数的种类
- 函数都做了啥?
- 软件定时器
- 软件定时器的作用
- 软件定时器内部到底做了什么实现了“闹钟”功能
- 引入守护任务,守护任务做了啥?
- 守护任务的调度
- 简单深入源码学习软件定时器
何为任务通知?
所谓"任务通知",你可以反过来读"通知任务"。就是就是一个简单唤醒其他任务的功能吗?那这样我队列、信号量、互斥量一样可以啊!那为什么要引进任务通知呢?那么我们就可以去看看任务通知到底有什么宇宙不同。
任务通知的通信是没有间隔的:
使用队列、信号量、事件组时,我们都要事先创建对应的结构体,双方通过中间的结构体通信:

使用任务通知时,任务结构体TCB中就包含了内部对象,可以直接接收别人发过来的"通知":
就是说创建任务的时候,任务里面创建的TCB结构体里面的某些变量就足以使用任务通知了

通知状态:

任务通知就是根据这个TCB里面的通知状态进行通信的。
任务通知使用例子

被通知的任务TCB结构体的通信状态的变换:

任务通知的优势以及劣势
优势
明确性、效率高:我们使用队列、信号量、事件组等等方法时,并不知道对方是谁。使用任务通知时,可以明确指定:通知哪个任务。
节省资源:相信深入学习过队列、信号量、互斥量的都知道它们在使用之前都需要创建,创建的时候里面都会分配一个结构体空间,里面会有链表、以及其他数据,队列传递数据时更多成了一个Buffer缓冲区,这些都是需要空间的,对于队列的细节可以看看我的这个文章:队列内部机制,在嵌入式里面,所谓是寸土寸金,对于空间利用来说所谓是斤斤计较,所以能省则省!任务通知则是不用创建,节省了很多空间!
劣势
不能发送数据给ISR:
ISR并没有任务结构体,所以无法使用任务通知的功能给ISR发送数据。但是ISR可以使用任务通知的功能,发数据给任务。
数据只能给该任务独享
使用队列、信号量、事件组时,数据保存在这些结构体中,其他任务、ISR都可以访问这些数据。
使用任务通知时,数据存放入目标任务中,只有它可以访问这些数据。
在日常工作中,这个限制影响不大。因为很多场合是从多个数据源把数据发给某个任务,而不是把一个数据源的数据发给多个任务。
无法缓冲数据
使用队列时,假设队列深度为N,那么它可以保持N个数据。
使用任务通知时,任务结构体中只有一个任务通知值,只能保持一个数据。
无法广播给多个任务
使用事件组可以同时给多个任务发送事件。
使用任务通知,只能发个一个任务。
如果发送受阻,发送方无法进入阻塞状态等待
假设队列已经满了,使用 xQueueSendToBack() 给队列发送数据时,任务可以进入阻塞状态等待发送完成。
使用任务通知时,即使对方无法接收数据,发送方也无法阻塞等待,只能即刻返回错误。
深入源码看看API函数内部干了什么
函数的种类
任务通知有2套函数,简化版、专业版,列表如下:
简化版函数的使用比较简单,它实际上也是使用专业版函数实现的
专业版函数支持很多参数,可以实现很多功能

具体的API函数使用方法以及参数可以看看这个手册:FreeRTOS开发手册
函数都做了啥?
这些函数都无非和队列它们一样都是唤醒任务或者阻塞本身,任务通知就是有一点不一样,就是要修改任务里面的TCB里面的通知状态,仅此而已!关于任务的唤醒以及阻塞可以看看我之前写的文章:任务的调度机制
就可以把他们的作为概括为这样:
挑出其中一个函数来分析:

软件定时器
软件定时器的作用
软件定时器就是"闹钟",你可以设置闹钟,
1、在30分钟后让你起床工作
2、每隔1小时让你例行检查机器运行情况
软件定时器也可以完成两类事情:
1、在"未来"某个时间点,运行函数
2、周期性地运行函数
日常生活中我们可以定无数个"闹钟",这无数的"闹钟"要基于一个真实的闹钟。
在FreeRTOS里,我们也可以设置无数个"软件定时器",它们都是基于系统滴答中断(Tick Interrupt)。
软件定时器内部到底做了什么实现了“闹钟”功能
前面所学的什么队列、信号量啊等等,处理任务通知,其他都需要创建,这个软件定时器也是需要创建的,那它的创建都创建了些什么呢?毫无疑问,还是那些结构体,以及=链表!那么它们的结构体里面的内容成员是什么呢?

在人类世界中,我们都是以时分秒为单位计算的,比如一个小时后去上班,等我五分钟,我上个厕所…等等。那么软件定时器是怎么样的呢?它们的单位是什么呢?其实它们的单位是Tick,学习任务调度的时候,任务调度也是由Tick Interrupt控制调度的,那么,对于它们来说就是,多少个Tick后我就来运行!还有就是我们人类世界是有一个表来计数时间的,那它们是通过什么来计数时间的呢?它们是在Tick中断里面进行计数的:
那时间到了,我要去哪里找到那些任务到点了需要运行呢?这时候就需要链表上场表演了,创建的定时器的时候创建的各个结构体都会储存在一个链表里面,到时候我就会里面找,比对一下就知道了谁时间到了,周期性的还会更新里面的启动时间和到点时间,方便下次运行!

引入守护任务,守护任务做了啥?
在事件组中我们看到FreeRTOS的作者担心的问题,就是唤醒任务,你不知道要唤醒的任务的个数,具体可以看看我写的这个文章:事件组内部机制学习,害怕唤醒所需的时间过长,影响中断的性能,那么定时器也会有类似的担忧问题,讨论这个担忧的问题是什么之前,==我们来看看在哪里执行定时器回调函数呢?==第一印象就是在Tick中断中执行:
1、在Tick中断中判断定时器是否到时间了
2、如果时间到了,就调用软件定时器的回调函数
3、回调函数里面不得影响到别的任务,需要尽快执行:
不要调用会导致阻塞的API函数,比如 vTaskDelay()
可以调用 xQueueReceive() 之类的函数,但是超时时间要设为0:即刻返回,不可阻塞
但是,在FreeRTOS实时操作系统中,它想做到实时,就不可能允许在内核,在中断中执行不确定的大小,万一定时器函数非常的长(运行的时间非常长),就会导致Tick中断迟迟无法退出,影响任务的调度,进入影响整个系统!
所以在FreeRTOS中,不再Tick中断中执行软件定时器的回调函数。
那么在哪里调用定时器回调函数呢?它的做法和事件组的做法相同!都是利用队列唤醒一个任务来执行其他的工作的,软件定时器中的这个任务叫“守护任务”!以前被称为"Timer server",但是这个任务要做并不仅仅是定时器相关,所以改名为:RTOS Damemon Task。因为这个做法使用了队列,而不是在Tick中断中调用回调函数的,所以软件定时器的启动、停止函数的参数有一个超时时间也就不足为怪了!
BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );
BaseType_t xTimerStop( TimerHandle_t xTimer, TickType_t xTicksToWait );
当FreeRTOS的配置项 configUSE_TIMERS 被设置为1时,在启动调度器时,会自动创建RTOSDamemon Task。
守护任务的优先级为:configTIMER_TASK_PRIORITY;定时器命令队列的长度为configTIMER_QUEUE_LENGTH。
守护任务不是专为某个定时器服务的,它还要处理其他定时器
守护任务的调度
守护任务的调度,跟普通的任务并无差别。当守护任务是当前优先级最高的就绪态任务时,它就可以运行。它的工作有两类:
1、处理命令:从命令队列里取出命令、
2、处理执行定时器的回调函数
能否及时处理定时器的命令、能否及时执行定时器的回调函数,严重依赖于守护任务的优先级。下面使用2个例子来演示。
例子1:守护任务的优先性级较低
t1:Task1处于运行态,守护任务处于阻塞态。
守护任务在这两种情况下会退出阻塞态切换为就绪态:命令队列中有数据、某个定时器超时了。至于守护任务能否马上执行,取决于它的优先级。
t2:Task1调用 xTimerStart()
要注意的是, xTimerStart() 只是把"start timer"的命令发给"定时器命令队列",使得守护任务退出阻塞态。
在本例中,Task1的优先级高于守护任务,所以守护任务无法抢占Task1。
t3:Task1执行完 xTimerStart()
但是定时器的启动工作由守护任务来实现,所以 xTimerStart() 返回并不表示定时器已经被启动了。
t4:Task1由于某些原因进入阻塞态,现在轮到守护任务运行。
守护任务从队列中取出"start timer"命令,启动定时器。
t5:守护任务处理完队列中所有的命令,再次进入阻塞态。
Idel任务时优先级最高的就绪态任务,它执行。
注意:假设定时器在后续某个时刻tX超时了,超时时间是"tX-t2",而非"tX-t4",从xTimerStart() 函数被调用时算起。
例子2:守护任务的优先性级较高
t1:Task1处于运行态,守护任务处于阻塞态。
守护任务在这两种情况下会退出阻塞态切换为就绪态:命令队列中有数据、某个定时器超时了。
至于守护任务能否马上执行,取决于它的优先级。
t2:Task1调用 xTimerStart()
要注意的是, xTimerStart() 只是把"start timer"的命令发给"定时器命令队列",使得守护任务退出阻塞态。
在本例中,守护任务的优先级高于Task1,所以守护任务抢占Task1,守护任务开始处理命令队列。
Task1在执行 xTimerStart() 的过程中被抢占,这时它无法完成此函数。
t3:守护任务处理完命令队列中所有的命令,再次进入阻塞态。
此时Task1是优先级最高的就绪态任务,它开始执行。
t4:Task1之前被守护任务抢占,对 xTimerStart() 的调用尚未返回。现在开始继续运行次函数、返回。
==t5:Task1由于某些原因进入阻塞态,进入阻塞态。==Idel任务时优先级最高的就绪态任务,它执行。
注意,定时器的超时时间是基于调用 xTimerStart() 的时刻tX,而不是基于守护任务处理命令的时刻tY。假设超时时间是10个Tick,超时时间是"tX+10",而非"tY+10"。
简单深入源码学习软件定时器
#define xTimerstart(xTimer,xTicksTowait ) \
xTimerGenericCommand(( xTimer ), tmrCONWMAND_START,( xTaskGetTickCount()),NULL,( xTicksTowait ) )
函数内部都做了什么?

那么毫无疑问肯定是守护函数在接收队列!那么守护函数里面具体做了什么呢?

相关文章:
FreeRTOS内部机制学习04(任务通知和软件定时器)
文章目录 何为任务通知?任务通知使用例子任务通知的优势以及劣势优势劣势 深入源码看看API函数内部干了什么函数的种类函数都做了啥? 软件定时器软件定时器的作用软件定时器内部到底做了什么实现了“闹钟”功能引入守护任务,守护任务做了啥&a…...
华为eNSP :WLAN的配置
一、WLAN的知识点: VLAN配置: VLAN:可以想象成一个大房子(网络)里划分的不同房间(VLAN)。每个房间可以有自己的功能,比如一个用于睡觉(管理),另一…...
中国大数据产业的融资热潮来袭,哪些领域最受资本青睐?
大数据产业是以数据及数据所蕴含的信息价值为核心生产要素,通过数据技术、数据产品、数据服务等形式,使数据与信息价值在各行业经济活动中得到充分释放的赋能型产业。 基于启信产业大脑的海量数据与专业研判模型,本文将从产业图谱、区域分析…...
Unity数据持久化 之 使用Excel.DLL读写Excel表格
本文仅作笔记学习和分享,不用做任何商业用途 本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正 终于找到一个比较方便容易读表的方式了,以前用json读写excel转的cvs格式文件我怎么使用怎么别扭…...
Linux系统:chown命令
1、命令详解: chown命令用于设置文件所有者和文件关联组的命令,全称为change directory。在Linux当中默认文件均有拥有者,可以利用 chown 将指定文件的拥有者改为指定的用户或组,输入参数时用户可以是用户名或者用户 ID࿰…...
Unity3D ARPG(动作角色扮演游戏)设计与实现详解
动作角色扮演游戏(Action Role-Playing Game, ARPG)结合了传统角色扮演游戏(RPG)的深度与动作游戏(Action Game)的即时反应和流畅战斗体验。Unity3D 作为一款强大的跨平台游戏开发引擎,为开发者…...
Qt实现登录界面
本文基于Qt实现一个简单的登录界面,主要使用到Widget、button、edit等控件,基于自定义的信号槽实现界面的跳转,使用绘图设备添加背景图等。 1. 创建主界面 设计主界面的样式,并添加相关的控件。如下显示: 代码如下&…...
big.LITTLE
big.LITTLE 1 多核异构调度算法 http://www.linaro.org/?sbig.LITTLE http://git.linaro.org https://wiki.linaro.org/Archived%20LSK%20Versions big.LITTLE CPUs can be configured in 2 modes of operation: IKS – In Kernel Switcher (also known as CPU Migration…...
汤臣倍健,三七互娱,得物,顺丰,快手,游卡,oppo,康冠科技,途游游戏,埃科光电25秋招内推
汤臣倍健,三七互娱,得物,顺丰,快手,游卡,oppo,康冠科技,途游游戏,埃科光电25秋招内推 ①得物 【八大职类】技术、供应链、产品、运营、设计、职能、商品研究、风控等大类…...
再谈c++模板
前言 在前面我们曾经简单的介绍过c的模板,但还并不全面,我们通过stl容器的学习加深了我们对c这门语言的理解。那么今天我们就再来谈一谈c模板,对模板再进行一点简单的补充 非类型模板参数 前面我们介绍的是类型模板参数,简单理…...
9.11 codeforces Div 2
文章目录 9.11 Div 2A. Doras Set(删除三个互质数)思路代码 B. Index and Maximum Value(范围加减1求max)思路代码 C. Dora and C(加a/b,最小化极差)思路代码 9.11 Div 2 Dashboard - Codeforces Round 969 (Div. 2) …...
二级菜单的两种思路(完成部分)
第一种 <el-form ref"formRef" :model"form" :rules"rules" label-width"120px"><el-form-item label"类型" prop"type"><el-select v-model"form.type" placeholder"请选择类型&q…...
【机器学习导引】ch2-模型评估与选择
文章目录 经验误差与过拟合 (Empirical error &overfitting)1. **均方误差(Mean Squared Error, MSE)**2. **均方根误差(Root Mean Squared Error, RMSE)**3. **平均绝对误差(Mean Absolute…...
二开ihoneyBakFileScan备份扫描
优点:可以扫描根据域名生成的扫描备份的扫描工具 二开部分:默认网址到字典(容易被封),二开字典到网址(类似test404备份扫描规则),同时把被封不能扫描的网址保存到waf_url.txt 中&am…...
leetcode21. 合并两个有序链表
思路: 用一个新链表来表示合并后的有序链表, 每次比较两个链表,将较小的那个结点存储至新链表中 # Definition for singly-linked list. # class ListNode(object): # def __init__(self, val0, nextNone): # self.val val # …...
搭建 WordPress 及常见问题与解决办法
浪浪云活动链接 :https://langlangy.cn/?i8afa52 文章目录 环境准备安装 LAMP 堆栈 (Linux, Apache, MySQL, PHP)配置 MySQL 数据库 安装 WordPress配置 WordPress常见问题及解决办法数据库连接错误白屏问题插件或主题冲突内存限制错误 本文旨在介绍如何在服务器上…...
《ORANGE‘s 一个操作系统的实现》--保护模式进阶
保护模式进阶 大内存读写 GDT段 ;GDT [SECTION .gdt] ; 段基址, 段界限 , 属性 LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符 LABEL_DESC_NORMAL: Descriptor 0, 0ffffh, DA_DRW ; Normal 描…...
【可变参模板】可变参类模板
可变参类模板也和可变参函数模板一样,允许模板定义含有0到多个(任意个)模板参数。可变参类模板参数包的展开方式有多种,以下介绍几种常见的方法。 一、递归继承展开 1.1类型模板参数包的展开 首先先看下面的代码: /…...
Linux 递归删除大量的文件
一般情况下 在 Ubuntu 中,递归删除大量文件和文件夹可以通过以下几种方式快速完成。常用的方法是使用 rm 命令,配合一些适当的选项来提高删除速度和效率。 1. 使用 rm 命令递归删除 最常见的方式是使用 rm 命令的递归选项 -r 来删除目录及其所有内容。…...
设计一个算法,找出由str1和str2所指向两个链表共同后缀的起始位置
假定采用带头结点的单链表保存单词,当两个单词有相同的后缀时,则可共享相同的后缀存储空间,例如,’loading’和’being’的存储映像如下图所示。 设str1和str2分别指向两个单词所在单链表的头结点,链表结点结构为 data…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分: 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...
关于easyexcel动态下拉选问题处理
前些日子突然碰到一个问题,说是客户的导入文件模版想支持部分导入内容的下拉选,于是我就找了easyexcel官网寻找解决方案,并没有找到合适的方案,没办法只能自己动手并分享出来,针对Java生成Excel下拉菜单时因选项过多导…...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...
