首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

ucos在s3c2410上运行过程整体剖析--创建任务到多任务调度及运行(3)

ucos在s3c2410上运行过程整体剖析--创建任务到多任务调度及运行(3)

我们前面提到过,ucos这个工程中为了统一,把所有的外部中断服务程序都写到不同的中断结构体里了。这些中断结构体在ucos初始化的时候有一些简单的初始化。
在系统级任务里调用了这样一个函数:
SetISR_Interrupt(IRQ_TIMER4, TimerTickHandle, NULL);
这个函数就实现了对定时器有关的中断服务程序的初始化操作,并且打开了定时器中断的掩码寄存器标志位。我们知道,一开始我们的arm的cpsr的中断是禁止的,这个是在系统级任务运行时就打开了的(还记得未雨绸缪时的堆栈cpsr的内容不)。现在又打开了定时器中断的掩码寄存器标志位,好了,原来的双层保护都打开了,从现在开始ucos就开始响应定时器中断了。那中断服务程序都干了些什么那?
看下面代码 ,
unsigned int irq=GetISROffsetClr();  //得到中断向量的偏移地址

       irq=fixup_irq(irq);

       if(irq>=NR_IRQS)
              return;
       if(InterruptFunc[irq].InterruptHandlers==NULL){
              InterruptFunc[irq].ack_irq(irq);  //clear pending
              return;
       }

       OSIntEnter();
        // Call interrupt service routine
       InterruptFunc[irq].InterruptHandlers(irq, InterruptFunc[irq].data);
       InterruptFunc[irq].ack_irq(irq);  //clear pending

       OSIntExit();
}
得到中断服务程序的偏移量,即确定是什么外部中断。然后执行响应的中断服务程序,然后进入ucos的中断OSIntEnter();,在这里没干什么,只是对OSIntNesting这个变量加一。然后OSIntExit();,在这里面干的就多了,如果有更高的优先级的任务就绪,那直接切换到高优先级任务去执行,即在这发生中断级任务切换。
最后推出中断。
那定时器中断服务程序(就是那个OSTimeTick()函数)具体都干什么那?
下面是部分代码:
ptcb = OSTCBList;                                  /* Point at first TCB in TCB list               */
        while (ptcb->OSTCBPrio != OS_IDLE_PRIO) { /* Go through all TCBs in TCB list              */
            OS_ENTER_CRITICAL();
            if (ptcb->OSTCBDly != 0) {             /* No, Delayed or waiting for event with TO     */
                if (--ptcb->OSTCBDly == 0) {     /* Decrement nbr of ticks to end of delay       */
                                      /* Check for timeout                            */
                    if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) {
                        ptcb->OSTCBStat   &= ~OS_STAT_PEND_ANY;  /* Yes, Clear status flag   */
                        ptcb->OSTCBPendTO  = TRUE;      /* Indicate PEND timeout    */
                    } else {
                        ptcb->OSTCBPendTO  = FALSE;
                    }

                    if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) {  /* Is task suspended?       */
                        OSRdyGrp               |= ptcb->OSTCBBitY;  /* No,  Make ready */
                        OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
                    }
                }
            }
            ptcb = ptcb->OSTCBNext;       /* Point at next TCB in TCB list                */
            OS_EXIT_CRITICAL();

通过阅读,简单分析你就可以知道这个定时器中断服务程序,就是对所有的通过调用延时函数的任务的TCB进行对OSTCBDly进行减一操作。延时函数OSTimeDly干的活就是把当前任务挂起,并给这个任务的TCB中的OSTCBDly赋值。当这个值减到一就说明这个任务的延时时间到了,把这个任务再置成就绪态,等待调度。

综上所述,我们知道了。我们现在创建的任务都是自己调用OSTimeDly();函数自动放弃cpu的使用权,然后通过定时器中断函数计时,当延时时间到时把任务置为就绪态,等待调度和切换。
在这个例子中,就有两种产生调度的原因,一:任务自愿调用OSTimeDly()产生了一次任务调度和切换,定时器中断服务程序负责对延时计时,当时间到时,置位就绪表,并产生任务调度和切换。

可以发现,其实程序一直都被定时器打断,还有计时cpu大部分时间都被空闲任务占有。因为我们的那三个任务都是执行一段代码后就延时。而空闲任务不延时。它都是在定时器中断服务程序里被迫的让出cpu使用权。请仔细分析这个多任务调度实例,在头脑中形成一个宏观现象,有利于对ucos的整体掌握。

下章,我们仔细分析一下这个任务级任务切换和中断级任务切换时怎么在arm9上实现的,因为这两个函数都是用汇编书写的,又和硬件有一些联系,可能比较难理解一些。我们做详细讲解。下章见。
继承事业,薪火相传
返回列表