网站公告列表

  没有公告

加入收藏
设为首页
联系站长
您现在的位置: 超前科技开发网 >> 文章中心 >> 实时操作系统 >> uCOS-II开发 >> 文章正文
  [推荐]第3章 内核结构(4)         ★★★ 【字体:
第3章 内核结构(4)
作者:邵贝贝    文章来源:本站原创    点击数:    更新时间:2006-11-29    
LPC2368 开发板(LPC2364/LPC2368).
全功能JLINK ARM仿真器.
USB-Blaster下载电缆(支持ALTERA全系列)
LPC2148开发板.

3.9          μC/OS中的中断处理

 

μC/OS中,中断服务子程序要用汇编语言来写。然而,如果用户使用的C语言编译器支持在线汇编语言的话,用户可以直接将中断服务子程序代码放在C语言的程序文件中。中断服务子程序的示意码如程序清单L3.15所示。

 

程序清单 L3.15 μC/OS-II中的中断服务子程序.

用户中断服务子程序:                                                            

    保存全部CPU寄存器;                                      (1)                     

调用OSIntEnterOSIntNesting直接加1               (2)

    执行用户代码做中断服务;                                 (3)                  

    调用OSIntExit()                                     (4)                     

    恢复所有CPU寄存器;                                     (5)                      

    执行中断返回指令;                                      (6)         

 

 

用户代码应该将全部CPU寄存器推入当前任务栈[L3.15(1)]。注意,有些微处理器,例如Motorola68020(及68020以上的微处理器),做中断服务时使用另外的堆栈。

μC/OS-Ⅱ可以用在这类微处理器中,当任务切换时,寄存器是保存在被中断了的那个任务的栈中的。

    μC/OS-Ⅱ需要知道用户在做中断服务,故用户应该调用OSIntEnter(),或者将全程变量OSIntNesting[L3.15(2)]直接加1,如果用户使用的微处理器有存储器直接加1的单条指令的话。如果用户使用的微处理器没有这样的指令,必须先将OSIntNesting读入寄存器,再将寄存器加1,然后再写回到变量OSIatNesting中去,就不如调用OSIatEnter()。OSIntNesting是共享资源。OSIntEnter()把上述三条指令用开中断、关中断保护起来,以保证处理OSIntNesting时的排它性。直接给OSIntNesting加1比调用OSIntEnter()快得多,可能时,直接加1更好。要当心的是,在有些情况下,从OSIntEnter()返回时,会把中断开了。遇到这种情况,在调用OSIntEnter()之前要先清中断源,否则,中断将连续反复打入,用户应用程序就会崩溃!

    上述两步完成以后,用户可以开始服务于叫中断的设备了[L3.15(3)]。这一段完全取决于应用。μC/OS-Ⅱ允许中断嵌套,因为μC/OS-Ⅱ跟踪嵌套层数OSIntNesting。然而,为允许中断嵌套,在多数情况下,用户应在开中断之前先清中断源。

    调用脱离中断函数OSIntExit()[L3.15(4)]标志着中断服务子程序的终结,OSIntExit()将中断嵌套层数计数器减1。当嵌套计数器减到零时,所有中断,包括嵌套的中断就都完成了,此时μC/OS-Ⅱ要判定有没有优先级较高的任务被中断服务子程序(或任一嵌套的中断)唤醒了。如果有优先级高的任务进入了就绪态,μC/OS-Ⅱ就返回到那个高优先级的任务,OSIntExit()返回到调用点[L3.15(5)]。保存的寄存器的值是在这时恢复的,然后是执行中断返回指令[L3.16(6)]。注意,如果调度被禁止了(OSIntNesting>0),μC/OS-Ⅱ将被返回到被中断了的任务。

    以上描述的详细解释如图F3.5所示。中断来到了[F3.5(1)]但还不能被被CPU识别,也许是因为中断被μC/OS-Ⅱ或用户应用程序关了,或者是因为CPU还没执行完当前指令。一旦CPU响应了这个中断[F3.5(2)],CPU的中断向量(至少大多数微处理器是如此)跳转到中断服务子程序[F3.5(3)]。如上所述,中断服务子程序保存CPU寄存器(也叫做 CPU context)[F3.5(4)],一旦做完,用户中断服务子程序通知μC/OS-Ⅱ进入中断服务子程序了,办法是调用OSIntEnter()或者给OSIntNesting直接加1[F3.5(5)]。然后用户中断服务代码开始执行[F3.5(6)]。用户中断服务中做的事要尽可能地少,要把大部分工作留给任务去做。中断服务子程序通知某任务去做事的手段是调用以下函数之一:OSMboxPost(),OSQPost(),OSQPostFront(),OSSemPost()。中断发生并由上述函数发出消息时,接收消息的任务可能是,也可能不是挂起在邮箱、队列或信号量上的任务。用户中断服务完成以后,要调用OSIntExit()[F3.5(7)]。从时序图上可以看出,对被中断了的任务说来,如果没有高优先级的任务被中断服务子程序激活而进入就绪态,OSIntExit()只占用很短的运行时间。进而,在这种情况下,CPU寄存器只是简单地恢复[F3.5(8)]并执行中断返回指令[F3.5(9)]。如果中断服务子程序使一个高优先级的任务进入了就绪态,则OSIntExit()将占用较长的运行时间,因为这时要做任务切换[F3.5(10)]。新任务的寄存器内容要恢复并执行中断返回指令[F3.5(12)]

3.5 中断服务

 

       进入中断函数OSIntEnter()的代码如程序清单L3.16所示,从中断服务中退出函数OSIntExit()的代码如程序清单L3.17所示。如前所述,OSIntEnter()所做的事是非常少的。

 

程序清单 L3.16 通知μC/OS-Ⅱ,中断服务子程序开始了.

void OSIntEnter (void)

{

    OS_ENTER_CRITICAL();

    OSIntNesting++;

    OS_EXIT_CRITICAL();

}

 

 

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

void OSIntExit (void)

{

    OS_ENTER_CRITICAL();                                                      (1)

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

        OSIntExitY    = OSUnMapTbl[OSRdyGrp];                               (3)

        OSPrioHighRdy = (INT8U)((OSIntExitY << 3) +

                        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()调整栈结构

 

有的微处理器,像Motorola 68HC11中断发生时CPU寄存器是自动入栈的,且要想允许中断嵌套的话,在中断服务子程序中要重新开中断,这可以视作一个优点。确实,如果用户中断服务子程序执行得非常快,用户不需要通知任务自身进入了中断服务,只要不在中断服务期间开中断,也不需要调用OSIntEnter()或OSIntNesting加1。程序清单L3。18中的示意代码表示这种情况。一个任务和这个中断服务子程序通讯的唯一方法是通过全程变量。

 

程序清单 L3.18 Motorola 68HC11中的中断服务子程序

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

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

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

    执行中断返回指令;

欢迎进入超前MCU技术论坛对 第3章 内核结构(4)进行讨论!

文章录入:armopen    责任编辑:armopen 
  • 上一篇文章:

  • 下一篇文章:
  • 发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
    最新热点 最新推荐 相关文章
    第4章 任务管理
    第3章 内核结构(6)
    第3章 内核结构(5)
    第3章 内核结构(3)
    第3章 内核结构(2)
    第3章 内核结构(1)
    第2章 实时系统概念(9)
    第2章 实时系统概念(8
    第2章 实时系统概念(7)
    第2章 实时系统概念(6)
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)
    Copyright 2003-2006 www.mcu123.com© All Rights Reserved
    版权所有 © 超前科技开发网
    粤ICP备05005262号