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

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.xdnf.cn/news/17694.html

相关文章:

  • 腾讯云EdgeOne Pages深度使用指南
  • GPU指令集入门教程
  • 《 C Primer Plus》
  • 常用hook钩子函数
  • 快速了解DBSCAN算法
  • Vue.js设计于实现 - 响应式(三)
  • 音视频学习(五十二):ADTS
  • Graham 算法求二维凸包
  • Python 2025:最新技术趋势与展望
  • 每日五个pyecharts可视化图表-line:从入门到精通 (2)
  • lesson34:深入理解Python线程:从基础到实战优化
  • jupyter notebook如何打开其他盘目录
  • MCP学习与实践
  • [激光原理与应用-222]:机械 - 3D设计与2D设计的异同比较
  • Linux 虚拟机磁盘空间占满-全面清理方案
  • Cesium1.95中如何高效管理 1500 个高频实体
  • 赋值运算符指南
  • 代码可读性与维护性的实践与原则
  • word中,添加新的参考文献后,其他参考文献的交叉引用不能及时更新的解决办法
  • 《Webpack与Vite热模块替换机制深度剖析与策略抉择》
  • 二维前缀和问题
  • 如何在 Ubuntu 24.04 LTS Linux 上安装 MySQL 服务器
  • 电脑本地摄像头做成rtsp流调用测试windows系统中
  • 【大智慧数据】心智开花的时候
  • AI测试助手如何让Bug无处可藏
  • Dify 从入门到精通(第 26/100 篇):Dify 的知识图谱集成
  • 2025最新免费的大模型和免费的大模型API有哪些?(202508更新)
  • 2025年6月电子学会全国青少年软件编程等级考试(Python二级)真题及答案
  • 【Linux指南】Vim的全面解析与深度应用
  • C语言第八章指针四