uCOS-II的任务介绍

任务介绍

从任务的存储结构来看,uCOS-II的任务由三个组成部分构成:任务程序代码,任务堆栈和任务控制块。其中,任务控制块用来保存任务属性;任务堆栈用来保存任务工作环境;任务程序代码是任务的执行部分。


uCOS-II的任务组成

uCOS-II的任务有两种:用户任务和系统任务。由应用程序设计者编写的任务,叫做用户任务;由系统提供的任务叫做系统任务。用户任务是为解决应用问题而编写的;系统任务是为应用程序来提供某种服务的。

目前uCOS-II可支持多达64个任务(包括用户任务和系统任务)进行管理。

为了管理上的方便,uCOS-II把每一个任务都作为一个节点,然后把它们链接成下图所示的一个任务链表。

 uCOS-II的任务在内存中的结构

 

任务的状态:

因为在嵌入式系统中只有一个CPU,所以在一个具体时刻只能允许一个任务占用CPU。根据任务是否占用CPU,以及是否处于被中断,等待等情况,任务在uCOS-II中可能处于下图5种状态之一。

 


 

 

 任务的5种状态

任务在不同状态之间的转换:

 


 

任务状态的转换

 


用户任务代码的一般结构

   根据嵌入式系统任务的工作特点,任务的执行代码通常是一个无限循环结构,并且在这个循环中可以响应中断,这种结构也叫做超循环结构。

 

一个用C语言编写的任务(超循环结构的任务示意性代码):

void MyTask( void *pdata )

{

       for(;;)

       {

              可以被中断的用户代码;

              OS_ENTER_CRITICAL();    //进入临界段(关中断)

             不可以被中断的用户代码;

              OS_EXIT_CRITICAL();       //退出临界段(开中断)

              可以被中断的用户代码;

       }

}

 

     从程序设计的角度来看,一个uCOS-II任务的代码就是一个C语言函数.为了可以传递各种不同类型的数据甚至是函数,任务的参数是一个void类型的指针.

 

     为了有效地对中断进行控制,在任务的代码里可使用uCOS-II定义的宏OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()来控制任务何时响应中断,何时屏蔽中断。在运行这两个宏之间的代码时是不会响应中断的,这种受保护的代码段叫做临界段。在具体应用中可以根据实际需要在一个任务中使用这对宏设置多个临界段。

     因此可以说,uCOS-II任务的代码结构是一个带有临界段的无限循环。

 

用户应用程序的一般结构

    从程序代码上来看,用户任务似乎就是一个C语言函数,但是这个函数不是一般的C语言函数,它是一个任务(线程)。因此,它不是被主函数或其他函数调用的,主函数main()只负责创建和启动它们,而由操作系统负责来调度运行它们。从代码上来看,用户应用程序的代码大体上如下面所示:

用户应用程序的结构。


  void MyTask1( void *pdata )     // 定义用户任务1

  {

       for(;;)

       {

              ......

       }

  }

  void MyTask2( void *pdata )     // 定义用户任务2

  {

       for(;;)

       {

              ......

       }

  }


  void MyTask3( void *pdata )     // 定义用户任务3

  {

       for(;;)

       {

              ......

       }

  } 

 

  void main()

  {

       ......

      OSInit();               //初始化uCOS-II

       ......

       OSTaskCreate(MyTask1,......);     //创建用户1

       OSTaskCreate(MyTask2,......);     //创建用户2

       OSTaskCreate(MyTask3,......);     //创建用户3

       ......

       OSStart();                    //启动任务

       ......

  }

系统任务

     uCOS-II预定义了两个为应用程序服务的系统任务: 空闲任务和统计任务。其中空闲任务是每个应用程序必须使用的,而统计任务则

是应用程序可以根据实际需要来选择使用的。

空闲任务

      在多任务系统运行时,系统经常会在某个时间内无用户任务可运行而处于所谓的空闲状态。 为了使CPU在没有用户任务可执行

时有事可做,uCOS-II提供了一个叫做空闲任务OSTaskIdle()的系统任务。空闲任务的代码如下:
    
    void OSTaskIdle( void *pdata)
    {
          #if OS_CRITICAL_METHOD == 3
            OS_CPU_SR cpu_sr;
         #endif
 
          pdata = pdata;  //防止某些编译器报错

          for(;;)
         {
            OS_ENTER_CRITICAL();  //关闭中断
            OSIdleCtr++;   //计数
            OS_EXIT_CRITICAL();  //开放中断
          }
    } 

 

这里有一行代码为 pdata = pdata,之所以安排了这样一行代码,是因为在这个任务中没有用到参数pdata。对于某些C编译器,在对代

码进行编译时会对这种情况报错(说定义了参数却没有使用),有了这行代码,编译器就不会报错了。
从上面的代码中可以看到,这个空闲任务几乎不做什么事情,只是对系统定义的一个空闲任务运行次数计数器OSIdleCtr进行加1操作。

当然,如果用户认为有必要,那么也可在空闲任务中编写一些做用户工作的代码。
   uCOS-II规定,一个用户应用程序必须使用这个空闲任务,而且这个任务是不能用软件来删除的。

统计任务

      uCOS-II提供的另一个系统任务是 统计任务OSTaskStat()。这个统计任务 每秒计算一次CPU在单位时间内被使用的时间,并把计算结

果以百分比的形式存放在变量OSCPUUsage中,以便应用程序通过访问它来了解CPU的利用率,所以该系统任务OSTaskStat()叫做统计任

务。

     用户应用程序是否使用统计任务,用户可以根据应用程序的实际需要来进行选择。如果用户应用程序要使用这个统计任务,则必须把定义在系统头文件OS_CFG.H中的系统配置常数OS_TASK_STAT_EN设置为1,并且必须在创建统计任务之前调用函数OSStatInit()对统计任务进行初始化。

 

任务的优先权及优先级别

      前面已提及uCOS-II的每个任务都必须具有一个惟一的优先级别。uCOS-II把任务的优先权分为64个优先级别,每一个级别都用一个数字来表示。数字0表示任务的优先级别最高;数字越大则表示任务的优先级别越低。

     通常一个应用程序的任务数小于64。为了节省内存,用户可以根据应用程序的需要,在文件OS_CFG.H中通过给表示最低优先级别的常数OS_LOWEST_PRIO赋值的方法,来说明程序中任务优先级别的数目。该常数一旦被定义,就意味着系统中可供使用的优先级别为0,1,2,...,OS_LOWEST_PRIO,共OS_LOWEST_PRIO+1个。同时也限制了应用程序中任务的总数最多不能超OS_LOWEST_PRIO+1个。固定地,系统总是把最低优先级别OS_LOWEST_PRIO自动赋给空闲任务。如果应用程序中还使用了统计任务,则系统会把优先级别OS_LOWEST_PRIO-1自动赋给统计任务,因此用户任务可以使用的优先级别是0,1,2,...,OS_LOWEST_PRIO-2,共OS_LOWEST_PRIO-1个。


例:

如果希望应用程序中任务的优先级别为28个,则表示最低优先级别的常数OS_LOWEST_PRIO值应该是多少?如果应用程序中使用了系统提供的空闲任务和统计任务,则该应用程序最多可以安排多少个任务?

 答:表示最低优先级别的常数OS_LOWEST_PRIO值应该为27,优先级别分别为0,1,2,3,...,27;由于系统空闲任务占用了优先级别27,统计任务占用了优先级别26,则应用程序中最多可以安排优先级别分别为0,1,2,...,25的26个任务。

   给某一个用户任务的定义优先级别,需要在调用系统函数OSTaskCreate()来创建任务时,用该函数的第4个参数prio来指定。
  由于每个任务都具有惟一的优先级别,因此uCOS-II通常也用任务的优先级别来作为这个任务的标识。

http://blog.csdn.net/sunrier/article/details/6462335

http://blog.csdn.net/sunrier/article/details/6462637

任务应用实例

基于linux平台的ucos 2.86应用程序示例如下:主要是根据ucos中的API创建俩个简单的task。
其代码结构为:

#include <stdio.h>  
#include <stdlib.h>  
#include "ucos_ii.h"  
  
/* Function common to all tasks */  
  
void MyTask( void *p_arg )  
{  
    char* sTaskName = (char*)p_arg;  
  
#if OS_CRITICAL_METHOD == 3   
    OS_CPU_SR     cpu_sr = 0;  
#endif  
  
    while(1)  
    {  
        /* printf uses mutex to get terminal access, therefore must enter critical section */  
        OS_ENTER_CRITICAL();  
        printf( "Name: %s\n", sTaskName );  
        OS_EXIT_CRITICAL();  
  
        /* Delay so other tasks may execute. */  
        OSTimeDly(50);  
    }/* while */  
  
}  
int main (void)  
{  
    /* pthreads allocates its own memory for task stacks. This UCOS linux port needs a minimum stack size 
        in order to pass the function information within the port. */  

    INT8U Stk1[ OSMinStkSize() ];  
    INT8U Stk2[ OSMinStkSize() ];  
    char sTask1[] = "Task 1";  
    char sTask2[] = "Task 2";  
    OSInit();  
    OSTaskCreate( MyTask, sTask1, (void*)Stk1, 4 );  
    OSTaskCreate( MyTask, sTask2, (void*)Stk2, 5 );  
    OSStart();  
    return 0;  
}  


上面的运行的结果类似如下:

http://blog.csdn.net/suiyuan19840208/article/details/11850065