uCOS-任务(1)
UC/OS-II操作系统内核的主要工作就是对任务进行管理和调度。
1、任务的概念
从应程设计的角度来看,UC/OS-II的任务就是一个线程,就是一个用来解决用户问题的C语言函数和与之相关联的一些数据结构而构成的一个实体。
2、任务的状态
因为在嵌入式系统中只有一个CPU,所以在一个具体时刻只能允许一个任务占用CPU.根据任务是否占用CPU,以及是否处于被中断、等待等情况,任务会处于其中一个任务状态。
5种状态:
·睡眠状态:任务只以代码的形式驻留在程序空间,还没交给操作系统管理。
·就绪状态:系统为任务配备了任务控制块且在任务就绪表中进行了就绪登记。
·运行状态:就绪状态的任务经调度器判断获得了CPU的使用权。
·等待状态:正在运行的任务,需要等待一段时间或需要等待一个事件发生再运行时,该任务就会把CPU的状态叫做中断服务状态。
·中断服务状态:一个正在运行的任务一旦响应中断申请就会中止运行而去执行中断服务程序。
3、任务的组成结构和分类
(1)组成部分:
·任务程序代码:任务的执行部分。
·任务堆栈: 保存任务工作环境。
·任务控制块: 保存任务属性。
(2)种类(两种):
·用户任务:为解决应用问题而编写的。
·系统任务:系统提供的任务,为应用程序来提供某种服务。
一、任务程序代码
(1)用户任务代码
根据嵌入式系统任务的工作特点,任务的执行代码通常是一个无限循环结构,并且在这个循环中可以响应中断,这种结构叫超循环结构。
一般结构
void Task(void *pdata)
{
for(;;)
{
可以被中断的用户代码;
OS_ENTER_CRITICAL(); //进入临界段(关中断)
不可以被中断的用户代码;
OS_EXIT_CRITICAL(); //退出临界段(开中断)
可以被中断的用户代码;
}
}
用户应用程序的结构
主函数main()只负责创建和启动任务,而操作系统负责来调度运行他们。
Void Task1(void *pdata) //定义用户任务1
{
for(;;)
{……}
}
Void Task2(void *pdata) //定义用户任务2
{
for(;;)
{……}
}
Void main()
{
……
OSInit(); //初始化OS
……
OSTaskCreate(Task1,……); //创建用户任务1
OSTaskCreate(Task2,……); //创建用户任务2
……
OSStart(); //启动任务,任务就由操作系统来管理和调度了
……
}
(2)系统任务(空闲任务和统计任务)
UC/OS-II预定义了两个为应用程序服务的系统任务:空闲任务和统计任务。
① 空闲任务OSTaskIdle() :
在多任务系统运行时,系统经常会在某个时间内无用户任务可运行而处于所谓的空闲状态。为了使CPU在没有用户任务可执行时有事可做,UC/OS-II提供了一个叫做空闲任务OSTaskIdle()的系统任务。
void OSTaskIdle (void *pdata)
{
pdata = pdata; //防止对代码编译时出错
for (;;)
{
OS_ENTER_CRITICAL(); //进入临界段(关中断)
OSIdleCtr++; //对系统定义的一个空闲任务运行次数计数器OSdleCtr进行加1操作。
OS_EXIT_CRITICAL(); //退出临界段(开中断)
}
}
注意:UC/OS-II规定一个用户应用程序必须用这个空闲任务。
②系统任务OSTaskStat()
统计任务每秒计算一次CPU在单位时间内被使用的时间,并把计算结果以百分比的形式存放在变量OSCPUsage中,以便应用程序通过访问它来了解CPU的利用率。
如果用户应用程序要使用这个统计任务,则必须把系统配置常数OS_TASK_STAT_EN(见文件OS_CFG.H)设为1,并且必须在创建统计任务之前调用函数OSStatInit()(见文件OS_CORE.C) 对统计任务进行初始化。
程序清单 L3.12 初始化统计任务:
void main (void)
{
OSInit(); /* 初始化uC/OS-II (1)*/
/* 安装uC/OS-II的任务切换向量 */
/* 创建用户起始任务 (2)*/
OSStart(); /* 开始多任务调度 (3)*/
}
void TaskStart (void *pdata)
{
/* 安装并启动uC/OS-II的时钟节拍 (4)*/
OSStatInit(); /* 初始化统计任务 (5)*/
/* 创建用户应用程序任务*/
for (;;)
{
/* 这里是TaskStart()的代码! */
}
}
(3)任务优先级
1、每个任务都必须具有一个唯一的优先级别。
2、任务的优先权分为64个优先级别,每个级别都用一个数字来表示,0表示任务的优先级最高;数字越大表示任务的优先级越低。
3、OS_CFG.H中有一参数OS_LOWEST_PRIO最低优先级别常数,我们可以根据应程的需要,对此常数进行赋值,来决定最低优先级别常数。该常数被定义后,则系统中可供使用的优先级别号就为:0~ OS_LOWEST_PRIO。总共OS_LOWEST_PRIO+1个优先级别号。
4、系统总是把最低优先级别号OS_LOWEST_PRIO自动赋给空闲任务;如果应程中使用了统计任务,系统会把优先级别为OS_LOWEST_PRIO-1的级别号自动赋给统计任务。
5、给某一用户任务定义的优先级别,需要在调用系统函数OSTaskCreat()来创建任务时,用函数的第四个参数prio来指定。
6、由于每个任务都由唯一的优先级别号,所以也用它来作为任务的标识。