微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > μC/OS-II的内核结构

μC/OS-II的内核结构

时间:10-08 来源:互联网 点击:

程序清单 L3.17 通知μC/OS-Ⅱ,脱离了中断服务

voidOSIntExit(void)

{

OS_ENTER_CRITICAL();(1)

if((--OSIntNesting|OSLockNesting)==0){(2)

OSIntExitY=OSUnMapTbl[OSRdyGrp];(3)

OSPrioHighRdy=(INT8U)((OSIntExitY3)+

OSUnMapTbl[OSRdyTbl[OSIntExitY]]);

if(OSPrioHighRdy!=OSPrioCur){

OSTCBHighRdy=OSTCBPrioTbl[OSPrioHighRdy];

OSCtxSwCtr++;

OSIntCtxSw();(4)

}

}

OS_EXIT_CRITICAL();

}

OSIntExit()看起来非常像OSSched()。但有三点不同。第一点,OSIntExit()使中断

嵌套层数减1[L3.17(2)]而调度函数OSSched()的调度条件是:中断嵌套层数计数器和锁定

嵌套计数器(OSLockNesting)二者都必须是零。第二个不同点是,OSRdyTbl[]所需的检索

值Y是保存在全程变量OSIntExitY中的[L3.17(3)]。这是为了避免在任务栈中安排局部变

量。这个变量在哪儿和中断任务切换函数OSIntCtxSw()有关,(见9.04.03节,中断任务

切换函数)。最后一点,如果需要做任务切换,OSIntExit()将调用OSIntCtxSw()[L3.17

(4)]而不是调用OS_TASK_SW(),正像在OSSched()函数中那样。

调用中断切换函数OSIntCtxSw()而不调用任务切换函数 OS_TASK_SW(),有两个原因,

首先是,如程序清单中L3.5(1)和图F3.6(1)所示,一半的工作,即CPU寄存器入栈的工作

已经做完了。第二个原因是,在中断服务子程序中调用OSIntExit()时,将返回地址推入

了堆栈[L3.15(4)和F3.6(2)]。OSIntExit()中的进入临界段函数OS_ENTER_CRITICAL()或

许将CPU的状态字也推入了堆栈L3.7(1)和F3.6(3)。这取决于中断是怎么被关掉的(见第8

章移植μC/OS-Ⅱ)。最后,调用OSIntCtxSw()时的返回地址又被推入了堆栈[L3.17(4)和

F3.1(4)],除了栈中不相关的部分,当任务挂起时,栈结构应该与μC/OS-Ⅱ所规定的完全

一致。OSIntCtxSw()只需要对栈指针做简单的调整,如图F3.6(5)所示。换句话说,调整

栈结构要保证所有挂起任务的栈结构看起来是一样的。

图3.6中断中的任务切换函数OSIntCtxSw()调整栈结构

有的微处理器,像Motorola68HC11中断发生时CPU寄存器是自动入栈的,且要想允许

中断嵌套的话,在中断服务子程序中要重新开中断,这可以视作一个优点。确实,如果用

户中断服务子程序执行得非常快,用户不需要通知任务自身进入了中断服务,只要不在中

断服务期间开中断,也不需要调用OSIntEnter()或OSIntNesting加1。程序清单L3。18

中的示意代码表示这种情况。一个任务和这个中断服务子程序通讯的唯一方法是通过全程

变量。

程序清单 L3.18Motorola68HC11中的中断服务子程序

M68HC11_ISR:/* 快中断服务程序,必须禁止中断*/

所有寄存器被CPU自动保存;

执行用户代码以响应中断;

执行中断返回指令;

3.10 时钟节拍

μC/OS需要用户提供周期性信号源,用于实现时间延时和确认超时。节拍率应在每秒

10次到100次之间,或者说10到100Hz。时钟节拍率越高,系统的额外负荷就越重。时钟

节拍的实际频率取决于用户应用程序的精度。时钟节拍源可以是专门的硬件定时器,也可

以是来自50/60Hz交流电源的信号。

用户必须在多任务系统启动以后再开启时钟节拍器,也就是在调用OSStart()之后。

换句话说,在调用OSStart()之后做的第一件事是初始化定时器中断。通常,容易犯的错

误是将允许时钟节拍器中断放在系统初始化函数OSInit()之后,在调启动多任务系统启动

函数OSStart()之前,如程序清单L3.19所示。

程序清单L3.19启动时钟就节拍器的不正确做法.

voidmain(void)

{

.

.

OSInit();/* 初始化uC/OS-II*/

.

.

/* 应用程序初始化代码 ...*/

/*... 通过调用OSTaskCreate()创建至少一个任务 */

.

.

允许时钟节拍(TICKER)中断;/* 千万不要在这里允许时钟节拍中断!!! */

.

.

OSStart();/* 开始多任务调度 */

}

这里潜在地危险是,时钟节拍中断有可能在μC/OS-Ⅱ启动第一个任务之前发生,此时μC/OS-Ⅱ是处在一种不确定的状态之中,用户应用程序有可能会崩溃。

μC/OS-Ⅱ中的时钟节拍服务是通过在中断服务子程序中调用OSTimeTick()实现的。

时钟节拍中断服从所有前面章节中描述的规则。时钟节拍中断服务子程序的示意代码如程序清单L3.20所示。这段代码必须用汇编语言编写,因为在C语言里不能直接处理CPU的寄存器。

程序清单L3.20时钟节拍中断服务子程序的示意代码

voidOSTickISR(void)

{

保存处理器寄存器的值;

调用OSIntEnter()或是将OSIntNesting加1;

调用OSTimeTick();

调用OSIntExit();

恢复处理器寄存器的值;

执行中断返回指令;

}

时钟节拍函数OSTimeTick()的代码如程序清单3.21所示。OSTimtick()以调用可由用户定义的时钟节拍外连函数

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top