当前位置: 首页 > news >正文

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格式文件我怎么使用怎么别扭&#xf…...

Linux系统:chown命令

1、命令详解: chown命令用于设置文件所有者和文件关联组的命令,全称为change directory。在Linux当中默认文件均有拥有者,可以利用 chown 将指定文件的拥有者改为指定的用户或组,输入参数时用户可以是用户名或者用户 ID&#xff0…...

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-模型评估与选择

文章目录 经验误差与过拟合 &#xff08;Empirical error &overfitting&#xff09;1. **均方误差&#xff08;Mean Squared Error, MSE&#xff09;**2. **均方根误差&#xff08;Root Mean Squared Error, RMSE&#xff09;**3. **平均绝对误差&#xff08;Mean Absolute…...

二开ihoneyBakFileScan备份扫描

优点&#xff1a;可以扫描根据域名生成的扫描备份的扫描工具 二开部分&#xff1a;默认网址到字典&#xff08;容易被封&#xff09;&#xff0c;二开字典到网址&#xff08;类似test404备份扫描规则&#xff09;&#xff0c;同时把被封不能扫描的网址保存到waf_url.txt 中&am…...

leetcode21. 合并两个有序链表

思路&#xff1a; 用一个新链表来表示合并后的有序链表&#xff0c; 每次比较两个链表&#xff0c;将较小的那个结点存储至新链表中 # Definition for singly-linked list. # class ListNode(object): # def __init__(self, val0, nextNone): # self.val val # …...

搭建 WordPress 及常见问题与解决办法

浪浪云活动链接 &#xff1a;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 描…...

【可变参模板】可变参类模板

可变参类模板也和可变参函数模板一样&#xff0c;允许模板定义含有0到多个&#xff08;任意个&#xff09;模板参数。可变参类模板参数包的展开方式有多种&#xff0c;以下介绍几种常见的方法。 一、递归继承展开 1.1类型模板参数包的展开 首先先看下面的代码&#xff1a; /…...

Linux 递归删除大量的文件

一般情况下 在 Ubuntu 中&#xff0c;递归删除大量文件和文件夹可以通过以下几种方式快速完成。常用的方法是使用 rm 命令&#xff0c;配合一些适当的选项来提高删除速度和效率。 1. 使用 rm 命令递归删除 最常见的方式是使用 rm 命令的递归选项 -r 来删除目录及其所有内容。…...

设计一个算法,找出由str1和str2所指向两个链表共同后缀的起始位置

假定采用带头结点的单链表保存单词&#xff0c;当两个单词有相同的后缀时&#xff0c;则可共享相同的后缀存储空间&#xff0c;例如&#xff0c;’loading’和’being’的存储映像如下图所示。 设str1和str2分别指向两个单词所在单链表的头结点&#xff0c;链表结点结构为 data…...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发&#xff0c;后来由Pivotal Software Inc.&#xff08;现为VMware子公司&#xff09;接管。RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写。广泛应用于各种分布…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...