ucos II任务管理之一:挂起任务

 

                              Ucos II 任务管理之一

创建好了任务之后,就已经初步跨进了ucos II 的编程了。随着进一步的编程,发现学会创建了任务还是不够的。

在我的项目里,需要实现485通信功能,我创建了任务1用于串口1发送数据,任务2用于串口1接受数据。程序本身的意图是发送完数据后,接着就串口1接受反馈回来的信息。

但当把程序下载到电路板上后就出现问题,不能正常通信,原因就是当任务1在发送数据过程中,cpu时不时会跑到任务2去接受数据,这样就会接受自己发送出去的数据。

 所以mcu21就在想,能不能实现,在任务1执行的时候,任务2不执行。当任务1执行完,任务2才执行,相同地,当任务2执行完了,任务1才能执行。

 答案是肯定的。

 Ucos II  提供了任务挂起,任务恢复两种操作。

 什么叫做挂起任务?什么叫做恢复任务?

 简单来说,挂起任务就是把任务挂起来,cpu不执行它了,恢复任务就是挂起任务的反向操作。就好比你女朋友把你晾起来,不鸟你了,哈哈,知错了吧。

 在我的项目里,任务1执行的时候,我就挂起任务2,当任务1执行完了,我才恢复任务2。这样就解决我接受发送冲突的问题。

 下面详细了解下挂起,恢复操作。

  挂起任务需要使用到OSTaskSuspend()函数,任务可以挂起自己或者其它任务, OSTaskSuspend()只需要一个参数,就是需挂起任务的优先级。

 

程序清单 L 4.16   OSTaskSuspend().

INT8U OSTaskSuspend (INT8U prio)

{

    BOOLEAN   self;

    OS_TCB   *ptcb;

 

 

    if (prio == OS_IDLE_PRIO) {                                               (1)

        return (OS_TASK_SUSPEND_IDLE);

    }

    if (prio >= OS_LOWEST_PRIO && prio != OS_PRIO_SELF) {                                      (2)

        return (OS_PRIO_INVALID);

    }

    OS_ENTER_CRITICAL();

    if (prio == OS_PRIO_SELF) {                                               (3)

        prio = OSTCBCur->OSTCBPrio;

        self = TRUE;

    } else if (prio == OSTCBCur->OSTCBPrio) {                               (4)

        self = TRUE;

    } else {

        self = FALSE;

    }

    if ((ptcb = OSTCBPrioTbl[prio]) == (OS_TCB *)0) {                     (5)

        OS_EXIT_CRITICAL();

        return (OS_TASK_SUSPEND_PRIO);

    } else {

        if ((OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) {         (6)

            OSRdyGrp &= ~ptcb->OSTCBBitY;

        }

        ptcb->OSTCBStat |= OS_STAT_SUSPEND;                                   (7)

        OS_EXIT_CRITICAL();

        if (self == TRUE) {                                                    (8)

            OSSched();

        }

        return (OS_NO_ERR);

    }

}

首先理解下挂起的实现过程。

1.首先,OSTaskSuspend()要确保用户的应用程序不是在挂起空闲任务[L4.16(1)],接着确认用户指定优先级是有效的[L4.16(2)]。记住最大的有效的优先级数(即最低的优先级)是OS_LOWEST_PRIO。注意,用户可以挂起统计任务(statistic)。可能用户已经注意到了,第一个测试[L4.16(1)]在[L4.16(2)]中被重复了。笔者这样做是为了能与μC/OS兼容。第一个测试能够被移除并可以节省一点程序处理的时间,但是,这样做的意义不大,所以笔者决定留下它。

    2.接着,OSTaskSuspend()检验用户是否通过指定OS_PRIO_SELF来挂起调用本函数的任务本身[L4.16(3)]。用户也可以通过指定优先级来挂起调用本函数的任务[L4.16(4)]。在这两种情况下,任务调度程序都需要被调用。这就是笔者为什么要定义局部变量self的原因,该变量在适当的情况下会被测试。如果用户没有挂起调用本函数的任务,OSTaskSuspend()就没有必要运行任务调度程序,因为正在挂起的是较低优先级的任务。

    3.然后,OSTaskSuspend()检验要挂起的任务是否存在[L4.16(5)]。如果该任务存在的话,它就会从就绪表中被移除[L4.16(6)]。在我理解,这是任务挂起函数最关键的地方,所谓任务挂起,简单点来说,就是把任务从就绪表中删除,因为CPU下一次执行的任务是就绪表中优先级最高的任务,当任务不在就绪表中时,也不有可能这个任务还会被执行。下面理解下它的实现过程。每个任务的就绪态标志都放入就绪表中的,就绪表中有两个变量OSRdyGrp和OSRdyTbl[]。在OSRdyGrp中,任务按优先级分组,8个任务为一组。OSRdyGrp中的每一位表示8组任务中每一组中是否有进入就绪态的任务。任务进入就绪态时,就绪表OSRdyTbl[]中的相应元素的相应位也置位。比如说我要把优先级为5的任务从就绪表中删除,我需要的操作是把OSRdyTbl[0]的第五位清零,同时把OSRdyGrp第零位清零。

注意要被挂起的任务有可能没有在就绪表中,因为它有可能在等待事件的发生或延时的期满。在这种情况下,要被挂起的任务在OSRdyTbl[]中对应的位已被清除了(即为0)。再次清除该位,要比先检验该位是否被清除了再在它没被清除时清除它快得多,所以笔者没有检验该位而直接清除它。现在,OSTaskSuspend()就可以在任务的OS_TCB中设置OS_STAT_SUSPEND标志了,以表明任务正在被挂起[L4.16(7)]。最后,OSTaskSuspend()只有在被挂起的任务是调用本函数的任务本身的情况下才调用任务调度程序[L4.16(8)]。

 

你可能感兴趣的:(一步一步学习ucos,II)