网站公告列表

  没有公告

加入收藏
设为首页
联系站长
您现在的位置: 超前科技开发网 >> 文章中心 >> 实时操作系统 >> uCOS-II开发 >> 文章正文
  [推荐]第3章 内核结构(6)         ★★★ 【字体:
第3章 内核结构(6)
作者:邵贝贝    文章来源:本站原创    点击数:    更新时间:2006-11-29    
LPC2368 开发板(LPC2364/LPC2368).
全功能JLINK ARM仿真器.
USB-Blaster下载电缆(支持ALTERA全系列)
LPC2148开发板.
 时钟节拍函数OSTimeTick()的代码如程序清单3.21所示。OSTimtick()以调用可由用户定义的时钟节拍外连函数OSTimTickHook()开始,这个外连函数可以将时钟节拍函数OSTimtick()予以扩展[L3.2(1)]。笔者决定首先调用OSTimTickHook()是打算在时钟节拍中断服务一开始就给用户一个可以做点儿什么的机会,因为用户可能会有一些时间要求苛刻的工作要做。OSTimtick()中量大的工作是给每个用户任务控制块OS_TCB中的时间延时项OSTCBDly减1(如果该项不为零的话)。OSTimTick()从OSTCBList开始,沿着OS_TCB链表做,一直做到空闲任务[L3.21(3)]。当某任务的任务控制块中的时间延时项OSTCBDly减到了零,这个任务就进入了就绪态[L3.21(5)]。而确切被任务挂起的函数OSTaskSuspend()挂起的任务则不会进入就绪态[L3.21(4)]。OSTimTick()的执行时间直接与应用程序中建立了多少个任务成正比。

 

程序清单 L3.21 时钟节拍函数 OSTimtick() 的一个节拍服务

void OSTimeTick (void)

{

    OS_TCB *ptcb;

 

    OSTimeTickHook();                                                         (1)

    ptcb = OSTCBList;                                                         (2)

    while (ptcb->OSTCBPrio != OS_IDLE_PRIO) {                              (3)

        OS_ENTER_CRITICAL();

        if (ptcb->OSTCBDly != 0) {

            if (--ptcb->OSTCBDly == 0) {

                if (!(ptcb->OSTCBStat & OS_STAT_SUSPEND)) {               (4)

                    OSRdyGrp               |= ptcb->OSTCBBitY;               (5)

                    OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;

                } else {

                    ptcb->OSTCBDly = 1;

                }

            }

        }

        ptcb = ptcb->OSTCBNext;

        OS_EXIT_CRITICAL();

    }

    OS_ENTER_CRITICAL();                                                      (6)

    OSTime++;                                                                  (7)

    OS_EXIT_CRITICAL();

}

 

 

OSTimeTick()还通过调用OSTime()[L3.21(7)]累加从开机以来的时间,用的是一个无符号32位变量。注意,在给OSTime加1之前使用了关中断,因为多数微处理器给32位数加1的操作都得使用多条指令。

    中断服务子程序似乎就得写这么长,如果用户不喜欢将中断服务程序写这么长,可以从任务级调用OSTimeTick(),如程序清单L3.22所示。要想这么做,得建立一个高于应用程序中所有其它任务优先级的任务。时钟节拍中断服务子程序利用信号量或邮箱发信号给这个高优先级的任务。

 

程序清单 L3.22 时钟节拍任务 TickTask() 作时钟节拍服务.

void TickTask (void *pdata)

{

    pdata = pdata;

    for (;;) {

        OSMboxPend(...);    /* 等待从时钟节拍中断服务程序发来的信号 */

        OSTimeTick();

    }

}

 

用户当然需要先建立一个邮箱(初始化成NULL)用于发信号给上述任何告知时钟节拍中断已经发生了(程序清单L3.23)。

 

程序清单L3.23时钟节拍中断服务函数OSTickISR()做节拍服务。

void OSTickISR(void)

{

    保存处理器寄存器的值;

    调用OSIntEnter()或是将OSIntNesting1;

 

    发送一个消息(例如, (void *)1)到时钟节拍的邮箱;

 

    调用OSIntExit();

    恢复处理器寄存器的值;

    执行中断返回指令;

}

 

 

3.11     μC/OS-Ⅱ初始化

    在调用μC/OS-Ⅱ的任何其它服务之前,μC/OS-Ⅱ要求用户首先调用系统初始化函数OSIint()。OSIint()初始化μC/OS-Ⅱ所有的变量和数据结构(见OS_CORE.C)。

    OSInit()建立空闲任务idle task,这个任务总是处于就绪态的。空闲任务OSTaskIdle()的优先级总是设成最低,即OS_LOWEST_PRIO。如果统计任务允许OS_TASK_STAT_EN和任务建立扩展允许都设为1,则OSInit()还得建立统计任务OSTaskStat()并且让其进入就绪态。OSTaskStat的优先级总是设为OS_LOWEST_PRIO-1。

    图F3.7表示调用OSInit()之后,一些μC/OS-Ⅱ变量和数据结构之间的关系。其解释是基于以下假设的:

l         在文件OS_CFG.H中,OS_TASK_STAT_EN是设为1的。

l         在文件OS_CFG.H中,OS_LOWEST_PRIO是设为63的。

l         在文件OS_CFG.H中, 最多任务数OS_MAX_TASKS是设成大于2的。

以上两个任务的任务控制块(OS_TCBs)是用双向链表链接在一起的。OSTCBList指向这个链表的起始处。当建立一个任务时,这个任务总是被放在这个链表的起始处。换句话说,OSTCBList总是指向最后建立的那个任务。链的终点指向空字符NULL(也就是零)。

因为这两个任务都处在就绪态,在就绪任务表OSRdyTbl[]中的相应位是设为1的。还有,因为这两个任务的相应位是在OSRdyTbl[]的同一行上,即属同一组,故OSRdyGrp中只有1位是设为1的。

    μC/OS-Ⅱ还初始化了4个空数据结构缓冲区,如图F3.8所示。每个缓冲区都是单向链表,允许μC/OS-Ⅱ从缓冲区中迅速得到或释放一个缓冲区中的元素。注意,空任务控制块在空缓冲区中的数目取决于最多任务数OS_MAX_TASKS,这个最多任务数是在OS_CFG.H文件中定义的。μC/OS-Ⅱ自动安排总的系统任务数OS_N_SYS_TASKS(见文件μC/OS-Ⅱ.H)。控制块OS_TCB的数目也就自动确定了。当然,包括足够的任务控制块分配给统计任务和空闲任务。指向空事件表OSEventFreeList和空队列表OSFreeList的指针将在第6章,任务间通讯与同步中讨论。指向空存储区的指针表OSMemFreeList将在第7章存储管理中讨论。

3.12     μC/OS-Ⅱ的启动

       多任务的启动是用户通过调用OSStart()实现的。然而,启动μC/OS-Ⅱ之前,用户至少要建立一个应用任务,如程序清单L3.24所示。

 

程序清单 L3.24 初始化和启动μC/OS-Ⅱ

void main (void)

{

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

    .

    .

    通过调用OSTaskCreate()OSTaskCreateExt()创建至少一个任务;

    .

    .

    OSStart();          /* 开始多任务调度!OSStart()永远不会返回 */

}

 

3.7 调用OSInit()之后的数据结构

3.8 空缓冲区

 

    OSStart()的代码如程序清单L3.25所示。当调用OSStart()时,OSStart()从任务就绪表中找出那个用户建立的优先级最高任务的任务控制块[L3.25(1)]。然后,OSStart()调用高优先级就绪任务启动函数OSStartHighRdy()[L3,25(2)](见汇编语言文件OS_CPU_A.ASM),这个文件与选择的微处理器有关。实质上,函数OSStartHighRdy()是将任务栈中保存的值弹回到CPU寄存器中,然后执行一条中断返回指令,中断返回指令强制执行该任务代码。见9.04.01节,高优先级就绪任务启动函数OSStartHighRdy()。那一节详细介绍对于80x86微处理器是怎么做的。注意,OSStartHighRdy()将永远不返回到OSStart()

 

程序清单 L3.25 启动多任务.

void OSStart (void)

{

    INT8U y;

    INT8U x;

 

    if (OSRunning == FALSE) {

        y             = OSUnMapTbl[OSRdyGrp];

        x             = OSUnMapTbl[OSRdyTbl[y]];

        OSPrioHighRdy = (INT8U)((y << 3) + x);

        OSPrioCur     = OSPrioHighRdy;

        OSTCBHighRdy  = OSTCBPrioTbl[OSPrioHighRdy];                      (1)

        OSTCBCur      = OSTCBHighRdy;

        OSStartHighRdy();                                                     (2)

    }

}

 

多任务启动以后变量与数据结构中的内容如图F3.9所示。这里笔者假设用户建立的任务优先级为6,注意,OSTaskCtr指出已经建立了3个任务。OSRunning已设为“真”,指出多任务已经开始,OSPrioCurOSPrioHighRdy存放的是用户应用任务的优先级,OSTCBCurOSTCBHighRdy二者都指向用户任务的任务控制块。

3.13     获取当前μC/OS-Ⅱ的版本号

    应用程序调用OSVersion()[程序清单L3.26]可以得到当前μC/OS-Ⅱ的版本号。OSVersion()函数返回版本号值乘以100。换言之,200表示版本号2.00。

 

程序清单 L3.26 得到μC/OS-Ⅱ当前版本号

INT16U OSVersion (void)

{

    return (OS_VERSION);

}

 

 

 

    为找到μC/OS-Ⅱ的最新版本以及如何做版本升级,用户可以与出版商联系,或者查看μC/OS-Ⅱ得正式网站WWW. uCOS-II.COM

3.9调用OSStart()以后的变量与数据结构

3.14     OSEvent???()函数

读者或许注意到有4个OS_CORE.C中的函数没有在本章中提到。这4个函数是OSEventWaitListInit(),OSEventTaskRdy(),OSEventTaskWait(),OSEventTO()。这几个函数是放在文件OS_CORE.C中的,而对如何使用这个函数的解释见第6章,任务间的通讯与同步。

 

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

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

  • 下一篇文章:
  • 发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
    最新热点 最新推荐 相关文章
    第4章 任务管理
    第3章 内核结构(5)
    第3章 内核结构(4)
    第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号