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

FreeRTOS学习笔记:任务通知和软件定时器

任务通知

A写数据到队列的环形Buf,B读取Buf中的数据

A不知道谁读取的,B也不知道谁写入的

A想要写队列,当Buf写满时,A就会阻塞,在某个链表中挂入A,当B读取Buf时,会空出一个位置,读队列函数会去队列中,找链表唤醒第一个任务,对于任务B来说,B也不知道唤醒的谁。(B只知道唤醒链表的第一个任务)

他们之间相互不知道

A去give 释放一个信号量 B去take获得信号量或互斥量,两个任务之间也是通过信号量/互斥量进行通信的。双方不知道彼此

假设B想要take信号量或互斥量,里面的Value为0,B决定阻塞,于是在某个链表中挂起B。如果A来give信号量或互斥量,会顺便去结构体中,找到这个链表,把里面的第一个任务,拿出来唤醒。(A不知道谁是第一个任务)

任务通知

当中断或者任务A里面,明确该通知谁,去通知B任务。(中间不引入其他结构体)

场景一 :

A追求B

B的状态一开始处于任务没有在等待通知,当去处理别的任务,导致B阻塞,此时A发来通知特无法唤醒B,而B的状态变为接收到通知(但是B不受A通知的影响),当B再次运行时,B的状态为接收到通知,但是B不在乎。

但是如果B回心转意后,就会再次运行。因为A已经通知过了,所以B会立刻运行,不进行阻塞,此时B的状态为任务没有在等待通知

可以看为A舔狗追求B女神

场景二:

一开始B的状态为,任务没有通知,而任务B调用某个函数,他想等待通知,因为等待通知,进入阻塞,B的状态为,任务在等待通知,此时A发来通知唤醒B,(如何唤醒?将B的TCB结构体的值变为一个新值,状态为接收到任务通知),B开始运行,此时B的状态为任务没有通知。

使用任务通知有两类函数

简化版

xTaskNotifyGive/ulTaskNotifyTake

就是B的Val的值当成信号量(类比的说法),就是一个统计值cnt。

如果A  give  B

让B的Val值++

B的状态根据有没有调用 ulTaskNotifyTake 进行判断。如果B调用了函数ulTaskNotifyTake而处于等待任务通知状态(taskWAITING_NOTIFICATION)

B就会被A唤醒

B的Val值--  

如果B没有调用 ulTaskNotifyTake 函数,B对A不管兴趣,变修改B的状态为接收到任务通知(taskNOTIFICATION_RECEIVED)

专业版

简化版就是调用 eIncrement 的形式

A想要通知B 调用 xTaskNotify 修改B的值,状态为接收到通知

B调用 xTaskNotifyWait

uint32_t ulBitsToClearOnEntry,

如果在入口处,B不是接收到通知,就会清除B的Val中的值。如果接收到通知就不会清除B中Val的值。

uint32_t *pulNotificationValue,

收到通知后,用来保存通知值

uint32_t ulBitsToClearOnExit

接收通知后,记录通知值,清除B的Val值的若干位

任务通知,车辆运行

 第一辆车到达终点后,发出任务通知,让第二辆车,第三辆车开始运行

  1. 发送任务通知

同过调用任务句柄,来调用任务。

调用任务二

当任务三的值为100(覆盖型)时,调用任务三

 

 

  1. 等待任务通知

任务2 等待

任务3 等待 Val值为100

  • 第一个参数 ~0(即所有位为 1):表示 “关注所有通知位”(不屏蔽任何位)。
  • 第二个参数 ~0:表示 “接收后清除所有通知位”(处理完通知后复位通知状态)。
  • 第三个参数 &val:用于存储接收到的通知值。
  • 第四个参数 portMAX_DELAY:表示永久阻塞等待,直到收到通知才唤醒。

软件定时器

保证定时器任务的优先级足够高

软件定时器就是在Tick中断中调用

定时器:

就是某个结构体{

                            .Flg 一次性,周期性

                            .Period 周期

                            .fun       函数

                            .params 参数

                            .链表项

}

定时器A B C

A:2个周期后调用

B:5个周期后调用

C:10个周期后调用

怎么处理这些定时器呢?通过一个链表,把定时器串在一起

谁的时间先到达,谁就在链表的前面

 怎么处理链表里面的定时器?

两种办法

  • 在硬件中断处理函数中处理

每有一次硬件中断cnt值就++

当在cnt=x时,启动定时器,定时器会自动计算超时时间

A=cnt+2=x+2

B= cnt+5=x+5

C= cnt+10=x+10

在Tick ISR

  1. 判断Time List 有无已超时的Timer
  2. 若有调用其函数

在中断函数调用:中断要快速执行,不要执行的时间太长,如果要执行很复杂的程序,就不要放在定时器函数中做,否则会影响整个系统的效率。

定时器的任务运行于中断函数的上下文

二、 也是在Tick中断里进行判断定时器的时间是否到了。但是他不是调用其函数,而是通知一个“Timer 任务”,唤醒。

怎么唤醒“Timer任务”,通过写一个队列

平时,这个定时器任务就会读队列,当收到写入的数据后,就会知道,某个定时器的时间到了,调用其函数

定时器的函数运行于任务的上下文

当操作定时器时,就是写队列,以便唤醒定时器的任务。如果有别的任务的优先级高于定时器任务的优先级,那么定时器就会全部报废,一个用不了

所以当使用FreeRTOS里面的定时器时,要注意定时器的任务的优先级足够高。

进行设置软件定时器优先级

使用的函数

要使用定时器,需要先创建它,得到它的句柄。

启动定时器:

让定时器为Running状态

任务:

软件定时器 增加游戏音效

启动PWM发出声音,启动定时器

定时器的时间到后,定制PWM以静音

由于想要发出不同频率的声音

先初始化

先初始化蜂鸣器,再创建定时器

就封装一个函数,设置蜂鸣器的频率,时间

设置蜂鸣器的发声频率和 PWM 占空比

启动定时器,发声多长时间

  1. g_TimerSound:
    定时器句柄(之前通过 xTimerCreate 创建的 GameSound 定时器对象),标识要操作的具体定时器。
  2. time_ms:
    新的定时器周期(单位:系统节拍 Tick,但结合上下文通常表示 “毫秒”,需确保与系统配置一致)。
    • 这个值决定了蜂鸣器的持续发声时间:从调用该函数开始,到定时器超时触发回调函数(关闭蜂鸣器)的间隔,就是 time_ms 对应的实际时间。
  3. 0:
    阻塞超时时间(单位:Tick),表示 “立即执行修改操作”:
    • 若为 0,函数会尝试立即修改定时器周期,若暂时无法完成(如定时器正在被其他任务操作),则直接返回失败(而非等待)。
    • 实际使用中,因定时器通常仅由当前任务操作,传 0 可高效执行。

http://www.dtcms.com/a/322798.html

相关文章:

  • jQuery 零基础学习第一天
  • 数据结构—二叉树及gdb的应用
  • 【贪心】P4873 [USACO14DEC] Cow Jog G|省选-
  • MBR分区nvme固态硬盘安装win7--非UEFI启动和GPT分区
  • llm本地部署+web访问+交互
  • Oracle字段操作
  • [TryHackMe]Challenges---Game Zone游戏区
  • 力扣热题100-----118.杨辉三角
  • Kettle ETL 工具存在的问题以及替代方案的探索
  • Arm Development Studio 安全通告:CVE-2025-7427
  • 什么情况下需要JVM调优?
  • Java-file类
  • 力扣 30 天 JavaScript 挑战 第二题笔记
  • 每日算法刷题Day59:8.9:leetcode 队列8道题,用时2h30min
  • 【攻防实战】从外到内全链路攻防实战纪实
  • python---类型别名
  • 1073. 沙漏
  • sqli-labs通关笔记-第40关 GET字符型堆叠注入(单引号括号闭合 手工注入+脚本注入两种方法)
  • J2000平赤道系、瞬时平赤道系与瞬时真赤道系
  • (论文速读)重新思考CNN生成网络中的上采样操作
  • 优先队列,链表优化
  • 2025-08-09通过授权码的方式给exe程序充值
  • 如何搭建ELK
  • C# DataGridView 添加进度条
  • 五、RuoYi-Cloud-Plus 前端项目部署以及如何改后端请求地址。
  • 《从零实现哈希表:详解设计、冲突解决与优化》
  • 09 【C++ 初阶】C/C++内存管理
  • 容器技术基础与实践:从镜像管理到自动运行配置全攻略
  • 【机器学习深度学习】模型选型:如何根据模型的参数算出合适的设备匹配?
  • Java 字符流与字节流详解