用户任务代码的一般结构:
根据嵌入式系统任务的工作特点,任务的执行代码通常是一个无限循环结构,并且在这个循环中可以响应中断,这种结构也叫做超循环结构。
一个用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通常也用任务的优先级别来作为这个任务的标识。