侧边栏壁纸
博主头像
thinkTV博主等级

喜爱动漫的二刺螈一枚,摩托车云爱好者(快要有车了)。 懂一点技术的在读生物医学工程研究生( •̀ ω •́ )✧,多多指教。

  • 累计撰写 128 篇文章
  • 累计创建 18 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

UCOSIII 任务调度

thinkTV
2023-07-14 / 0 评论 / 0 点赞 / 286 阅读 / 1,535 字 / 正在检测是否收录...

1. UCOSIII的初始化

OSInit ( )
作用:用于初始化µC/OSIII ,必须在调用任何其他µC/OSIII函数之前调用它,仅调用一次即可

该函数内部实现,如下:

  1. 对一些全局变量赋初始值
  2. 初始化就绪列表以及Tick列表等
  3. 创建三个任务:空闲任务(必须创建),统计任务(条件创建),软件定时器任务(条件创建)

图片-1689315997110

2. 开启任务调度器

OSStart ( )

作用: 用于启动任务调度器,任务调度器启动后, UCOSIII 便会开始进行任务调度
该函数内部实现,如下:

  1. 进行一些安全关键代码判断
  2. 获取当前最高优先级任务
  3. 将调度器运行状态标志设置为开启状态
  4. 获取最高优先级任务的任务控制块
  5. 调用函数OSStartHighRdy( ) ,启动第一个任务

前导置零指令

CPU_CntLeadZeros ( OSPrioTbl[0]) ,其中OSPrioTbl[0]为32位的变量

图片-1689340504615

函数OS_PrioGetHighest ( ) 通过前导置零指令获得最高优先级

3. 启动第一个任务

  • 假设我们要启动的第一个任务是任务A,那么就需要将任务A的寄存器值恢复到CPU寄存器
  • 任务A的寄存器值,在一开始创建任务时就保存在任务堆栈里边

注意:

  1. 中断产生时,硬件自动将xPSR,PC(R15),LR(R14),R12,R3-R0出/入栈;而R4~R11需要手动出/入栈
  2. 进入中断后硬件会强制使用MSP指针 ,此时LR(R14)的值将会被自动被更新为特殊的EXC_RETURN

任务创建后对应任务的堆栈情况

  1. 寄存器xPSR被初始为0x01000000,其中bit24被置1,表示使用Thumb指令
  2. 寄存器PC被初始化为任务函数指针vTask_A,这样当某次任务切换后,任务A获得CPU控制权,任务函数vTask_A被出栈到PC寄存器,之后会执行任务A的代码
  3. LR寄存器初始化为函数指针OS_TaskReturn ,这是由移植层提供的一个出错处理函数。
  4. 子函数的调用通过寄存器R0~R3传递参数,创建任务时,我们传入的参数被保存到R0中,用来向任务函数传递参数

图片-1689390428580

OSStartHighRdy( )作用:该函数用于启动第一个任务

该函数内部实现,如下:

  • 屏蔽中断,防止在启动第一个任务时被打断
  • 将PendSV设置为最低优先级
  • 将PSP清0,PSP将用于任务栈
  • 将MSP设置为OS_CPU_ExceptStkBas,指向异常栈的栈底(按 8 字节对齐)
  • 获取当前最高优先级的任务它的任务优先级,以及任务控制块
  • 将最高优先级任务的任务栈出栈
  • 开中断,并跳转到第一个运行任务的任务函数执行

MSP与PSP简介

程序在运行过程中需要一定的栈空间来保存局部变量等一些信息。当有信息保存到栈中时,MCU 会自动更新 SP 指针,ARM Cortex-M 内核提供了两个栈空间

图片-1689395452162

在UCOS-III中,中断使用MSP(主堆栈),中断以外使用PSP(进程堆栈)

出栈/压栈汇编指令详解

  1. 出栈(恢复现场),方向:从下往上(低地址往高地址):假设r0地址为0x04汇编指令示例:
LDMFD r0!, {r4-r6}   /* 任务栈r0地址由低到高,将r0存储地址里面的内容手动加载到 CPU寄存器r4、r5、r6 */
  • r0地址(0x04)内容加载到r4,此时地址r0 = r0+4 = 0x08
  • r0地址(0x08)内容加载到r5,此时地址r0 = r0+4 = 0x0C
  • r0地址(0x0C)内容加载到r6,此时地址r0 = r0+4 = 0x10
  1. 压栈(保存现场),方向:从上往下(高地址往低地址):假设r0地址为0x10汇编指令示例:
STMFD r0!, {r4-r6} }   /* r0的存储地址由高到低递减,将r4、r5、r6里的内容存储到r0的任务栈里面。 */
  • 地址:r0 = r0-4 = 0x0C,将r6的内容(寄存器值)存放到r0所指向地址(0x0C)
  • 地址:r0 = r0-4 = 0x08,将r5的内容(寄存器值)存放到r0所指向地址(0x08)
  • 地址:r0 = r0-4 = 0x04,将r4的内容(寄存器值)存放到r0所指向地址(0x04)

4. 任务切换

任务切换的本质:就是CPU寄存器的切换。、

假设当由任务A切换到任务B时,主要分为两步:

  • 第一步:需暂停任务A的执行,并将此时任务A的寄存器保存到任务堆栈,这个过程叫做保存现场;
  • 第二步:将任务B的各个寄存器值(被存于任务堆栈中)恢复到CPU寄存器中,这个过程叫做恢复现场;

对任务A保存现场,对任务B恢复现场,这个整体的过程称之为:上下文切换

图片-1689397127824

注意:任务切换的过程在PendSV中断服务函数里边完成

PendSV中断如何触发

  • 执行UCOS-III提供的相关API函数:OSCtxSw()和 OSIntCtxSw()
  • 本质:通过向中断控制和状态寄存器 ICSR 的bit28 写入 1 挂起 PendSV 来启动 PendSV 中断

触发PendSV中断的两个函数由以下API函数调用:

图片-1689397247069

图片-1689398147627

EXC_RETURN合法值

R14 是链接寄存器 LR,在 ISR 中,它记录了异常返回值 EXC_RETURN

图片-1689398178610

  • 注意:在M4、M7系列中,bit4用于判断是否使用浮点单元,1不使用,0使用
  • 所以EXC_RETURN 只有 6 个合法的值(M4、M7),如下表所示:

图片-1689398198887

0

评论区