µC/OS-III 任务切换

本文详细解释了µC/OS-III中PendSV异常的作用、如何挂起和触发任务切换,以及OSIntExit()和OSSched()函数在任务切换过程中的角色。重点强调了任务切换在RTOS中的重要性和实现原理。
摘要由CSDN通过智能技术生成

目录

1 PendSV 异常

2 µC/OS-III 何时触发任务切换

3 µC/OS-III 如何触发任务切换

3.1 函数 OSSched()

3.2 函数 OSIntExit()

3.3 挂起 PendSV 异常

4 µC/OS-III 如何进行任务切换


RTOS 的核心是任务管理,而任务切换是任务管理的重中之重,系统中任务切换的过程是决定操作系统运行效率和稳定性的因素之一,尤其是对于实时操作系统。

1 PendSV 异常

        PendSV( Pended Service Call ,可挂起服务调用)异常,是一个对 RTOS 非常重要的异常。 正如 PendSV 异常的名称一样, PendSV 异常是一个可以挂起的异常,这主要体现在 PendSV 异 常能够被挂起而延迟执行,那么 RTOS 就能够利用 PendSV 异常的这一特点,等待 CPU 处理完其他重要的事务后,再处理 PendSV 异常。
        利用 PendSV 异常的可挂起特点, µC/OS-III PendSV 的中断优先级配置为最低的中断优 先级,这么一来,PendSV 异常的中断服务函数就会在其他所有中断处理完成后才被执行。 µC/OS-III 就是将任务切换的过程放到 PendSV 异常的中断服务函数中处理的。
        要挂起 PendSV 异常(触发 PendSV 异常)也非常简单,只需将 ICSR 寄存器(中断控制状 态寄存器)中断的 PENDSVSET 为置 1 ,即可挂起 PendSV 异常,再挂起 PendSV 异常 PendSV 的中断服务函数并不会立马被执行,但也不会被忽略,而是会等 CPU 处理完所有中断优先级不 小于 PendSV 异常中断优先级的中断后,在再处理 PendSV 异常的中断处理函数。

2 µC/OS-III 何时触发任务切换

        µC/OS-III 要触发任务切换无需在应用程序代码中做任务特殊的处理,因为 µC/OS-III 是一 个抢占式的内核,系统会保证当前执行的任务,一定是系统中任务优先级最高的就绪态任务, 因此 µC/OS-III 会在一定的条件下自动触发任务切换, µC/OS-III 自动触发任务切换的条件,如下表所示:
                                                    条件
任务向另外一个任务发送信号或消息
任务调用延时函数(函数 OSTimeDly() 或函数 OSTimeDlyHMSM()
任务等待一个还未发生的事件发生
任务的挂起状态被终止
任务被创建
任务被删除
内核对象被删除
任务修改了自身或其他任务的任务优先级
任务调用函数 OSTaskSuspend() 挂起自身
任务调用函数 OSTaskResue() 恢复其他被函数 OSTaskSuspend() 挂起的任务
中断嵌套结束
使用函数 OSSchedUnblock() 解锁任务调度器
任务调用函数 OSSchedRoundRobinYield() 弃用剩余的时间片
在应用程序中调用函数 OSSched()
        当上表中的条件触发时,µC/OS-III 就会自动地触发任务切换。当然,要注意的是,触发任务切换并不一定会切换任务,而仅仅是保证系统运行的任务为系统中任务优先级最高的就绪态任务。

3 µC/OS-III 如何触发任务切换

        在表 中的条件发生后, µC/OS-III 就会自动地触发任务切换。在 µC/OS-III 中有两个用于触发任务切换的函数,分别为函数 OSSched() 和函数 OSIntExit() ,这两个函数的不同在于,函数OSSched() 是在任务中使用的,而函数 OSIntExit() 是用于中断中的。

3.1 函数 OSSched()

        函数 OSSched() 用于在任务中触发任务切换,一般情况下,该函数会在满足表 中的条件(除中断嵌套结束和在应用程序中调用函数 OSSched() )时,被 µC/OS-III 自动调用。当然, 应用程序也可以在任务中调用 OSSched() ,手动触发任务切换。

3.2 函数 OSIntExit()

函数 OSIntExit() 用于告诉 µC/OS-III 一个中断的中断服务函数执行完毕,并在需要的时候进行任务切换。

3.3 挂起 PendSV 异常

        通过函数 OSSched() 和函数OSIntExit()分别调用了函数 OS_TASK_SW() 和函数 OSIntCtxSw() 挂起 PendSV 异常,以触发任 务切换。
        首先看一下函数 OS_TASK_SW() ,此函数实际上是一个定义在文件 os_cpu.h 中的宏定义, 具体的定义如下所示:
#define OS_TASK_SW() OSCtxSw()
        可以看到,函数 OS_TASK_SW() 被定义为 OSCtxSw() ,而函数 OSCtxSw() 与函数 OSIntCtxSw()是被定义在文件 os_cpu_a.asm 中用于表示同一段汇编代码的标号,如下所示:
NVIC_INT_CTRL EQU 0xE000ED04 ; 中断控制状态寄存器的地址
NVIC_PENDSVSET EQU 0x10000000 ; PENDSVSET 位掩码
OSCtxSw
OSIntCtxSw
; 将 ICSR 寄存器中的 PENDSVSET 位置 1
; 挂起 PendSV 异常
 LDR R0, =NVIC_INT_CTRL
 LDR R1, =NVIC_PENDSVSET
 STR R1, [R0]
 BX LR
        从上面的代码中可以看出,函数 OSCtxSw() 与函数 OSIntCtxSw() 就用于挂起 PendSV 异常 的,因为 PendSV 异常的中断优先级被设置为最低的中断优先级,因此在所有中断的中断服务函数处理完成后,就会跳转到 PendSV 异常的中断服务函数中,在 PendSV 的中断服务函数中就进行了任务切换的操作。

4 µC/OS-III 如何进行任务切换

        通过上一小节的分析,了解了在函数 OSSched() 和函数 OSIntExit() 中会挂起 PendSV 异常,那么 PendSV 异常就能够在所有中断的中断服务函数处理完成后,执行任务切换的操作。 µC/OS-III 提供了 PendSV 异常的中断服务函数,以完成任务切换的操作。
        任务切换的核心就是任务栈中数据的入栈与出栈。入栈操作能 够保存当前任务在任务切换前的上下文信息,而出栈操作则是将切换后任务的上下文信息从任 务的任务栈总恢复出来,这样任务才能够正常运行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值