UC/OS-II-1.1

1.093<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

3中使用了许多uCOS-II提供的附加功能。任务3使用了OSTaskCreateExt()TCB的扩展数据结构,用户定义的任务切换对外接口函数(OSTaskSwHook(),用户定义的统计任务(statistic task )的对外接口函数(OSTaskStatHook()以及消息队列。例3的磁盘文件是\SOFTWARE\uCOS-II\EX3_x86L,它包括9个任务。除了空闲任务(idle task)和统计任务(statistic task ),还有7个任务。与例1,例2一样,TaskStart()main()函数建立,其功能是建立其他任务,并显示统计信息。

1.09.01 main()

main()函数[程序清单L1.19]和例2中的相不多,不同的是在用户定义的TCB扩展数据结构中可以保存每个任务的名称[程序清单L1.19(1)](扩展结构的声明在INCLUDES.H中定义,也可参看程序清单L1.20)。笔者定义了30个字节来存放任务名(包括空格)[程序清单L1.20(1)]。本例中没有用到堆栈检查操作,TaskStart()中禁止该操作[程序清单L1.19(2)]

 

程序清单 L 1.19 3main()函数

void main (void)

{

    PC_DispClrScr(DISP_FGND_WHITE + DISP_BGND_BLACK);

    OSInit();

    PC_DOSSaveReturn();

    PC_VectSet(uCOS, OSCtxSw);

    PC_ElapsedInit();

 

    Strcpy(TaskUserData[TASK_START_ID].TaskName, "StartTask");          (1)

    OSTaskCreateExt(TaskStart,

                    (void *)0,

                    &TaskStartStk[TASK_STK_SIZE-1],

                    TASK_START_PRIO,

                    TASK_START_ID,

                    &TaskStartStk[0],

                    TASK_STK_SIZE,

                    &TaskUserData[TASK_START_ID],

                    0);                                                         (2)

    OSStart();

}

程序清单 L 1.20 TCB扩展数据结构。

typedef struct {

    char    TaskName[30];                                                     (1)

    INT16U  TaskCtr;

    INT16U  TaskExecTime;

    INT32U  TaskTotExecTime;

} TASK_USER_DATA;

 

1.09.02任务

TaskStart()的伪码如程序清单L1.21所示,与例23处不同:

l         为任务123建立了一个消息队列[程序清单L1.21(1)]

l         每个任务都有一个名字,保存在任务的TCB扩展数据结构中[程序清单L1.21(2)]

l         禁止堆栈检查。

 

程序清单 L 1.21 TaskStart()的伪码。

void TaskStart (void *data)

{

    Prevent compiler warning by assigning ‘data’ to itself;

    Display a banner and non-changing text;

    Install uC/OS-II’s tick handler;

    Change the tick rate to 200 Hz;

    Initialize the statistics task;

    Create a message queue;                                                   (1)

    Create a task that will display the date and time on the screen;

    Create 5 application tasks with a name stored in the TCB ext.;      (2)

    for (;;) {

        Display #tasks running;

        Display CPU usage in %;

        Display #context switches per seconds;

        Clear the context switch counter;

        Display uC/OS-II’s version;

        If (Key was pressed) {

            if (Key pressed was the ESCAPE key) {

                Return to DOS;

            }

        }

        Delay for 1 second;

    }

}

任务1向消息队列发送一个消息[程序清单L1.22(1)],然后延时等待消息发送完成[程序清单L1.22(2)]。这段时间可以让接收消息的任务显示收到的消息。发送的消息有三种。

程序清单 L 1.22 任务1

void  Task1 (void *data)

{

    char one   = '1';

    char two   = '2';

    char three = '3';

 

 

    data = data;

    for (;;) {

        OSQPost(MsgQueue, (void *)&one);                                   (1)

        OSTimeDlyHMSM(0, 0, 1,   0);                                        (2)

        OSQPost(MsgQueue, (void *)&two);

        OSTimeDlyHMSM(0, 0, 0, 500);

        OSQPost(MsgQueue, (void *)&three);

        OSTimeDlyHMSM(0, 0, 1,   0);

    }

}

任务2处于等待消息的挂起状态,且不设定最大等待时间[程序清单L1.23(1)]。所以任务2将一直等待直到收到消息。当收到消息后,任务2显示消息并且延时500mS[程序清单L1.23(2)],延时的时间可以使任务3检查消息队列。

程序清单 L 1.23 任务2

void  Task2 (void *data)

{

    INT8U *msg;

    INT8U  err;

 

 

    data = data;

    for (;;) {

        msg = (INT8U *)OSQPend(MsgQueue, 0, &err);                         (1)

        PC_DispChar(70, 14, *msg, DISP_FGND_YELLOW+DISP_BGND_BLUE);     (2)

        OSTimeDlyHMSM(0, 0, 0, 500);                                         (3)

    }

}

任务3同样处于等待消息的挂起状态,但是它设定了等待结束时间250mS[程序清单L1.24(1)]。如果有消息来到,任务3将显示消息号[程序清单L1.24(3)],如果超过了等待时间,任务3就显示“T”(意为timeout[程序清单L1.24(2)]

 

程序清单 L 1.24任务3

void  Task3 (void *data)

{

    INT8U *msg;

    INT8U  err;

 

 

    data = data;

    for (;;) {

        msg = (INT8U *)OSQPend(MsgQueue, OS_TICKS_PER_SEC/4, &err);     (1)

        If (err == OS_TIMEOUT) {

            PC_DispChar(70,15,'T',DISP_FGND_YELLOW+DISP_BGND_RED);       (2)

        } else {

            PC_DispChar(70,15,*msg,DISP_FGND_YELLOW+DISP_BGND_BLUE);    (3)

        }

    }

}

 

任务4的操作只是从邮箱发送[程序清单L1.25(1)]和接收[程序清单L1.25(2)],这使得用户可以测量任务在自己PC上执行的时间。任务410mS执行一次[程序清单L1.25(3)]

 

程序清单 L 1.25 任务4

void  Task4 (void *data)

{

    OS_EVENT *mbox;

    INT8U     err;

 

 

    data = data;

    mbox = OSMboxCreate((void *)0);

    for (;;) {

        OSMboxPost(mbox, (void *)1);                                        (1)

        OSMboxPend(mbox, 0, &err);                                           (2)

        OSTimeDlyHMSM(0, 0, 0, 10);                                          (3)

    }

}

 

任务5除了延时一个时钟节拍以外什么也不做[程序清单L1.26(1)]。注意所有的任务都应该调用uCOS-II的函数,等待延时结束或者事件的发生而让出CPU。如果始终占用CPU,这将使低优先级的任务无法得到CPU

程序清单 L 1.26 任务5

void  Task5 (void *data)

{

    data = data;

    for (;;) {

        OSTimeDly(1);                                                          (1)

    }

}

同样, TaskClk()函数[程序清单L1.18]显示当前日期和时间。

1.09.03注意

有些程序的细节只有请您仔细读一读EX3L.C才能理解。EX3L.C中有OSTaskSwHook()函数的代码,该函数用来测量每个任务的执行时间,可以用来统计每一个任务的调度频率,也可以统计每个任务运行时间的总和。这些信息将存储在每个任务的TCB扩展数据结构中。每次任务切换的时候OSTaskSwHook()都将被调用。

每次任务切换发生的时候,OSTaskSwHook()先调用PC_ElapsedStop()函数[程序清单L1.27(1)] 来获取任务的运行时间[程序清单L1.27(1)]PC_ElapsedStop()要和PC_ElapsedStart()一起使用,上述两个函数用到了PC的定时器2timer 2)。其中PC_ElapsedStart()功能为启动定时器开始记数;而PC_ElapsedStop()功能为获取定时器的值,然后清零,为下一次计数做准备。从定时器取得的计数将拷贝到time变量[程序清单L1.27(1)]。然后OSTaskSwHook()调用PC_ElapsedStart()重新启动定时器做下一次计数[程序清单L1.27(2)]。需要注意的是,系统启动后,第一次调用PC_ElapsedStart()是在初始化代码中,所以第一次任务切换调用PC_ElapsedStop()所得到的计数值没有实际意义,但这没有什么影响。如果任务分配了TCB扩展数据结构[程序清单L1.27(4)],其中的计数器TaskCtr进行累加[程序清单L1.27(5)]TaskCtr可以统计任务被切换的频繁程度,也可以检查某个任务是否在运行。TaskExecTime [程序清单L1.27(6)]用来记录函数从切入到切出的运行时间,TaskTotExecTime[程序清单L1.27(7)]记录任务总的运行时间。统计每个任务的上述两个变量,可以计算出一段时间内各个任务占用CPU的百分比。OSTaskStatHook()函数会显示这些统计信息。

 

程序清单 L 1.27 用户定义的OSTaskSwHook()

void OSTaskSwHook (void)

{

    INT16U          time;

    TASK_USER_DATA *puser;

 

 

    time  = PC_ElapsedStop();                                                (1)

    PC_ElapsedStart();                                                        (2)

    puser = OSTCBCur->OSTCBExtPtr;                                          (3)

    if (puser != (void *)0) {                                                (4)

        puser->TaskCtr++;                                                     (5)

        puser->TaskExecTime     = time;                                      (6)

        puser->TaskTotExecTime += time;                                     (7)

    }

}

本例中的统计任务(statistic task)将调用对外接口函数OSTaskStatHook()(设置OS_CFG.H文件中的OS_TASK_STAT_EN1允许对外接口函数)。统计任务每秒运行一次,本例中OSTaskStatHook()用来计算并显示各任务占用CPU的情况。

OSTaskStatHook()函数中首先计算所有任务的运行时间[程序清单L1.28(1)]DispTaskStat()用来将数字显示为ASCII字符[程序清单L1.28(2)]。然后是计算每个任务运行时间的百分比[程序清单L1.28(3)],显示在合适的位置上 [程序清单L1.28(4)]

程序清单 L 1.28 用户定义的OSTaskStatHook().

void OSTaskStatHook (void)

{

    char   s[80];

    INT8U  i;

    INT32U total;

    INT8U  pct;

 

 

    total = 0L;

    for (I = 0; i < 7; i++) {

        total += TaskUserData[i].TaskTotExecTime;                          (1)

        DispTaskStat(i);                                                      (2)

    }

    if (total > 0) {

        for (i = 0; i < 7; i++) {

            pct = 100 * TaskUserData[i].TaskTotExecTime / total;         (3)

            sprintf(s, "%3d %%", pct);

            PC_DispStr(62, i + 11, s, DISP_FGND_YELLOW);                  (4)

        }

    }

    if (total > 1000000000L) {

        for (i = 0; i < 7; i++) {

            TaskUserData[i].TaskTotExecTime = 0L;

        }

    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值