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

FreeRTOS学习:资源管理:互斥操作的本质

屏蔽中断

屏蔽中断有两套宏:任务中使用、ISR中使用:

  • 任务中使用:taskENTER_CRITICA()/taskEXIT_CRITICAL()
  • ISR中使用:taskENTER_CRITICAL_FROM_ISR()/taskEXIT_CRITICAL_FROM_ISR()

在 taskENTER_CRITICA()/taskEXIT_CRITICAL() 之间:

  • 低优先级的中断被屏蔽了:优先级低于、等于 configMAX_SYSCALL_INTERRUPT_PRIORITY
  • 高优先级的中断可以产生:优先级高于 configMAX_SYSCALL_INTERRUPT_PRIORITY
    • 但是,这些中断ISR里,不允许使用FreeRTOS的API函数
  • 任务调度依赖于中断、依赖于API函数,所以:这两段代码之间,不会有任务调度产生

这套 taskENTER_CRITICA()/taskEXIT_CRITICAL() 宏,是可以递归使用的,它的内部会记录嵌套的深度,只有嵌套深度变为0时,调用 taskEXIT_CRITICAL() 才会重新使能中断。

使用 taskENTER_CRITICA()/taskEXIT_CRITICAL() 来访问临界资源是很粗鲁的方法:

  • 中断无法正常运行
  • 任务调度无法进行
  • 所以,之间的代码要尽可能快速地执行

在 taskENTER_CRITICA_FROM_ISR()/taskEXIT_CRITICAL_FROM_ISR() 之间:

  • 低优先级的中断被屏蔽了:优先级低于、等于 configMAX_SYSCALL_INTERRUPT_PRIORITY
  • 高优先级的中断可以产生:优先级高于 configMAX_SYSCALL_INTERRUPT_PRIORITY
    • 但是,这些中断ISR里,不允许使用FreeRTOS的API函数
  • 任务调度依赖于中断、依赖于API函数,所以:这两段代码之间,不会有任务调度产生

---------------------------------------------------------------------------------------------------------------------------------

暂停调度器

如果有别的任务来跟你竞争临界资源,你可以把中断关掉:这当然可以禁止别的任务运行,但是这代价太大了。它会影响到中断的处理。

如果只是禁止别的任务来跟你竞争,不需要关中断,暂停调度器就可以了:在这期间,中断还是可以发生、处理。

使用这2个函数来暂停、恢复调度器:

这套 vTaskSuspendScheduler()/xTaskResumeScheduler() 宏,是可以递归使用的,它的内部会记录嵌套的深度,只有嵌套深度变为0时,调用 taskEXIT_CRITICAL() 才会重新使能中断。

---------------------------------------------------------------------------------------------------------------------------------

“极简版互斥锁” 

任务A和B调用

任务时间轴

A

  1. 先关闭调度器
  2. Bcanuse值--  1-1=0
  3. 开启任务调度器

此时A无论如何都是可以使用LCD

由于任务A开启了调度器导致被优先级高的任务B抢占资源

  1. B也是先关闭调度器
  2. Bcanuse值—  0-1=-1
  3. 不开启调度器
  4. Bcanuse值++      -1+1=0

B此时不能够使用LCD

任务 A 执行阶段

  1. A:关闭调度器 → 冻结任务切换(B 无法抢占,哪怕优先级高)。
  2. A:bCanUse-- → 1→0 → 标记 “开始占用 LCD”。
  3. A:使用 LCD(临界资源) → 因调度器关闭,B 无法干扰。
  4. A:开启调度器 → 调度器恢复,触发 “优先级检查”:
    • 若 B 优先级更高 → B 立即抢占 A,A 被暂停;
    • 若 B 优先级≤A → A 继续执行,B 不抢占。

任务 B 抢占后执行阶段(假设 B 优先级更高)

  1. B:关闭调度器 → (但此时 A 可能还没完全释放?不,A “开启调度器” 后已释放调度器锁,B 可独立关调度器 )。
  2. B:bCanUse-- → 0→-1 → 检查bCanUse == -1 → 进入else。
  3. B:bCanUse++ → -1→0 → 标记 “未抢到资源”,返回-1,无法使用 LCD。
  4. B 执行结束 → 调度器再次检查,若 A 仍有未完成逻辑,A 继续执行。

---------------------------------------------------------------------------------------------------------------------------------

A和B两个函数调用,中断也调用

中断(ISR)是 “比任务优先级更高的抢占源” :就算任务关了调度器,中断仍可能打断任务,抢占临界资源(比如 LCD )。

所以,想彻底独占资源,既要关调度器(防任务抢),又要关中断(防中断抢) 。

 RTOS 里 “调度器” 和 “中断” 的底层关联:“任务调度的触发,依赖中断(如时钟中断);关中断后,调度器无法主动调度任务”

无论是任务A和B,哪个调用

  1. 先关闭中断
  2. bCanUse--  1-1=0

由于关闭了中断,在这里进行操作时,就不会被其他任务打断,其他中断也不能被打断。关中断后,调度器无法主动调度任务”

  1. 再开启中断

在任务里面,中断肯定都是开启的

---------------------------------------------------------------------------------------------------------------------------------

但是在中断里,中断可能是关闭的,可能是开启的,所以

  1. 保存,关闭中断
  2. 恢复中断
  3. 恢复

---------------------------------------------------------------------------------------------------------------------------------

写事件组的中断

实际上就是写事件组,写Timer队列,唤醒TimerTask任务

实际上通过Timer任务进行写事件值

写事件值时,在任务里进行修改的,即使是通过中断触发,但是也是在任务里写的,所以对事件值的保护,没有必要进行关闭中断,当需要修改事件值时,只需要关闭调度器就可以了。

---------------------------------------------------------------------------------------------------------------------------------

解决DHT11经常出错的问题

想要在挡球板任务的顶上中间位置,每隔二秒显示温度,湿度。

想要每隔两秒显示,就使用定时器

可以正常读取,但是为什么使用MPU6050时,有时会导致显示err?

因为MPU6050的优先级的比较高,当DHT11在读取时,被切换。那么DHT11的时序被打断。读取 DHT11 数据的任务被延迟执行,错过了 DHT11 响应的时间窗口,从而无法正确获取温湿度数据。从而显示错误。

所以想要保证DHT11的任务不会出错,就要使用暂停调度器,和恢复调度器

那么当DHT11读取数据时,暂停调度器能阻止 “任务级抢占”

---------------------------------------------------------------------------------------------------------------------------------

三个红框都运用了I2C,I2C总线竞争

多任务 + I2C 的核心风险是 “总线竞争”,需用互斥锁隔离访问,否则会导致数据混乱、任务阻塞、系统实时性下降。

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

相关文章:

  • SymPy中的atan与atan2函数:原理、区别与应用
  • LeetCode 分类刷题:713. 乘积小于 K 的子数组
  • 【Python】常用内置模块
  • SpringCloud详细笔记
  • JavaScript垃圾回收机制
  • 运维学习Day20——MariaDB数据库管理
  • 《 C Primer Plus》
  • 【Linux指南】Vim的全面解析与深度应用
  • 【webPack|Vite】了解常用配置,主要差异
  • 生产工具革命:定制开发开源AI智能名片S2B2C商城小程序重构商业生态的范式研究
  • MyBatis的xml中字符串类型判空与非字符串类型判空处理方式
  • python中re模块详细教程
  • 状态机浅析
  • nginx下lua的实现机制、Lua错误处理、面向对象
  • Flutter 与 Android NDK 集成实战:实现高性能原生功能
  • 结构化记忆、知识图谱与动态遗忘机制在医疗AI中的应用探析(上)
  • 随机向量正交投影定理(Orthogonal Projection Theorem, OPT)_学习笔记
  • LLaMA-Adapter Efficient Fine-tuning of Language Models with Zero-init Attention
  • C++高频知识点(二十)
  • 数据库删除术:逻辑删除 vs 物理删除,选错毁所有
  • Flink提交流程全解析:从模式到实践
  • Java高并发场景下的缓存穿透问题定位与解决方案
  • 计算机网络:子网的起始地址就是默认的网络地址吗?
  • Flink SQL 中的水印机制
  • 26.Scikit-learn实战:机器学习的工具箱
  • Unity笔记(四)——Camera、碰撞检测函数、刚体加力、音频
  • CSDN 五周年创作纪念日(PS:vnjohn)
  • C++设计模式单例模式(饿汉、懒汉模式)
  • 基于 RabbitMQ 死信队列+TTL 实现延迟消息+延迟插件基本使用
  • 检索召回率优化探究五(BGE-M3 混合检索):基于LangChain0.3 集成Milvu2.5 向量数据库构建的智能问答系统