IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> ucos任务调度原理 -> 正文阅读

[嵌入式]ucos任务调度原理

本文主要详细讲解ucos如何实现任务调度。不讲解涉及任务控制块和事件控制块相关实现逻辑。我们知道ucos是一种嵌入式实时多任务操作系统。已经广泛使用在航空航天电子产品的各种应用中,为了更好的了解ucos的任务调试原理,我们从以下几点进行分析。

一、两个相关的C函数。

1 堆栈的初始化函数,主要是完成堆栈的初始化

我们可以把堆栈分成三个部分空间。第一个部分空间保存xPSR,PC,R14,R12,R0-R3,在任务进行上下文切换时,CPU会自动将这些寄存器的值保存到堆栈的第一个部分空间。

第二个部分空间保存R4-R11,这部分寄存器需要使用程序手动保存。第三个部分空间是应用程序在运行过程中使用,比如局部变量的存储。

2 任务控制块初始化函数。主要完成任务控制块的初始化。

INT8U? OS_TCBInit (INT8U prio, OS_STK *ptos, OS_STK *pbos, INT16U id, INT32U stk_size, void *pext, INT16U opt)

其中函数的一个功能是将堆栈第三个部分空间的栈顶地址存储在任务控制块的(OS_TCB*)0->OSTCBStkPtr中。

完成这两个函数的初始化后,当前任务堆栈空间中的值如下图所示:

二、os_cpu_a.asm文件。

1)开关中断源函数的实现。

2)初次触发任务调度函数。

3)OS自己使能调度。其实是触发pendSV中断,让CPU执行PendSV_Handler函数。

4)OS自己在中断处理函数中使能调度。

5)OS上下文切换,即运行任务的切换实现。

下面我从两个方面总结一下任务调试的过程。

  • 初次任务调度。

初次启动任务时,需要调用OSStartHighRdy函数。流程如下:

  1. 先将PendSV的中断优先级配置成0xFF。保证其为最低优先级。
  2. 将PSP寄存器清0。
  3. OSRunning = 1。
  4. 触发pendSV中断。
  5. 开总中断。
  6. 等待pendSV中断发生。
  7. 当pendSV中断发生后,pendSV_Handler被调用。
  8. 关掉总中断。(任务切换需关闭中断,防止被打断影响切换过程)
  9. 判断PSP寄存器是否为0,为0则是第一次调度,跳转到PendSV_Handler_Nosave。
  10. 调用OSTaskSwHook子函数,在调用之前需要保存一下R14(LR)的值,因为当通过BL和BLX指令调用子程序时,硬件自动将子程序的返回地址保存在R14中,子程序返回时,把R14的值复制到PC,实现子程序的返回。
  11. OSPrioCur = OSPrioHighRdy; OSTCBCur? = OSTCBHighRdy;
  12. 此时R0中就是当前任务OSTCBCur->OSTCBStkPtr指针,即第三部分空间的ptos位置。
  13. 将R0即OSTCBCur->OSTCBStkPtr地址的数据还原到R4-R11(第一次调度其实没有意义,因为之前还没有任务运行,堆栈的东西是无效的)
  14. 将R0即OSTCBCur->OSTCBStkPtr地址加0x20,让R0指向第一部分空间,即栈顶位置。
  15. 将当前任务的栈顶指针保存到PSP寄存器中。
  16. 打开总中断后返回。
  17. CPU会根据堆栈中的PC指针执行任务,完成调度。
  • 非初次任务调度。

非初次调度时,OS需调度OSCtxSw或OSIntCtxSw触发pendSV中断。

  1. 当pendSV中断发生后,pendSV_Handler被调用。
  2. 关掉总中断。(任务切换需关闭中断,防止被打断影响切换过程)
  3. 判断PSP寄存器是否为0,若为非0,则表示非初次调度,PSP装的值是当前任务栈顶的指针。此时xPSR,PC,R14,R12,R0-R3寄存器已被CPU自动保存在的堆栈第一部分空间中。
  4. 将R0即PSP保存的地址减0x20,让R0指向堆栈第二部分空间尾部,即R4的位置。
  5. 保存R4-R11的值到堆栈第二部分空间中。
  6. 让OSTCBCur->OSTCBStkPtr指向当前堆栈指针SP,即PSP-0x20位置。
  7. 调用OSTaskSwHook子函数,在调用之前需要保存一下R14(LR)的值,因为当通过BL和BLX指令调用子程序时,硬件自动将子程序的返回地址保存在R14中,子程序返回时,把R14的值复制到PC,实现子程序的返回。
  8. OSPrioCur = OSPrioHighRdy; OSTCBCur? = OSTCBHighRdy;
  9. 此时R0中就是当前新任务OSTCBCur->OSTCBStkPtr指针,即第三部分空间的ptos位置。
  10. 将R0即新任务OSTCBCur->OSTCBStkPtr地址的数据还原到R4-R11。
  11. 将R0即新任务OSTCBCur->OSTCBStkPtr地址加0x20,让R0指向第一部分空间,即栈顶位置。
  12. 将当前新任务的栈顶指针保存到PSP寄存器中。
  13. 打开总中断后返回。
  14. CPU会根据新任务堆栈中的PC指针执行任务,完成调度。
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-08-06 11:00:44  更:2022-08-06 11:00:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 22:30:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码