uc/os-II中的任务(1)

来源:互联网 发布:软件行业发展前景概述 编辑:程序博客网 时间:2024/05/17 08:33
第二章μC/OS-II中的任务
2.1 任务的基本概念
1.uC/OS II中,同大任务分解成的小任务对应的程序实体就叫“任务”,也叫线程,是一个用来解决用户问题的C函数和与之关联的一些数据结构构成的实体。
2.2uC/OS II的任务由三部分组成:
①任务的程序代码(任务的执行部分)
②任务的堆栈(保存任务工作环境)
③任务控制块(用于保存任务属性)
3.两种任务分类:
用户任务:由应用程序设计者编写的任务,用于解决应用问题.
系统任务:系统提供的任务,为应用程序提供某种服务.
(为了管理方便,把每一个任务看作结点,并链接成一个任务链表。)
目前,UC/OS II最多可对64个任务进行管理。
2.1.1任务的状态
1.一个任务被创建之后,可以处于以下五种状态之一。
这五种状态分别是:
1.       睡眠状态
2.       就绪状态
3.       等待状态
4.       中断服务状态
5.       运行状态
简单介绍各状态的含义及各状态切换的方法。
睡眠状态:睡眠态(DORMANT)指任务驻留在程序空间之中,还没有交给ucos II管理,把任务交给ucos II是通过调用下述两个函数之一:OSTaskCreate()或OSTaskCreateExt()。当任务一旦建立,这个任务就进入就绪态准备运行。任务的建立可以是在多任务运行开始之前,也可以是动态地被一个运行着的任务建立。如果一个任务是被另一个任务建立的,而这个任务的优先级高于建立它的那个任务,则这个刚刚建立的任务将立即得到CPU的控制权。一个任务可以通过调用OSTaskDel()返回到睡眠态,或通过调用该函数让另一个任务进入睡眠态。
就绪状态:系统为任务配备了任务控制块且在任务就绪表中做了任务登记,任务具备了运行的充分条件的状态。
运行状态:任务经调度器判断获得CPU的使用权则为运行状态,任何时刻只有一个任务处于运行状态。
    等待状态: 正在运行的任务可以通过调用两个函数之一将自身延迟一段时间,这两个函数是OSTimeDly()或OSTimeDlyHMSM()。这个任务于是进入等待状态,等待这段时间过去,下一个优先级最高的、并进入了就绪态的任务立刻被赋予了CPU的控制权。等待的时间过去以后,系统服务函数OSTimeTick()使延迟了的任务进入就绪态。正在运行的任务期待某一事件的发生时也要等待,手段是调用以下3个函数之一:OSSemPend(),OSMboxPend(),或OSQPend()。调用后任务进入了等待状态(WAITING)。当任务因等待事件被挂起(Pend),下一个优先级最高的任务立即得到了CPU的控制权。当事件发生了,被挂起的任务进入就绪态。事件发生的报告可能来自另一个任务,也可能来自中断服务子程序。
中断服务状态:正在运行的任务是可以被中断的,除非该任务将中断关了,或者ucos IIⅡ将中断关了。被中断了的任务就进入了中断服务态(ISR)。响应中断时,正在执行的任务被挂起,中断服务子程序控制了CPU的使用权。中断服务子程序可能会报告一个或多个事件的发生,而使一个或多个任务进入就绪态。在这种情况下,从中断服务子程序返回之前,ucos II要判定,被中断的任务是否还是就绪态任务中优先级最高的。如果中断服务子程序使一个优先级更高的任务进入了就绪态,则新进入就绪态的这个优先级更高的任务将得以运行,否则原来被中断了的任务才能继续运行。


2.1.2.用户任务代码的一般结构
1.用户任务代码的一般结构
带有临界段(uc-os-ii定义的宏OS_ENTER_SRITICAL()和os_exot_critical()控制任务何时响应中断,屏蔽中断,两个宏间不会响应中断受保护的代码段)的无限循环 的C语言函数(可传任何类型参数,任务参数为void 类型指针)。
2.用户应用程序的一般结构
用户任务为一个线程/C语言函数,不是被主函数或其他函数调用,主函数负责创建和启动
,由操作系统调度运行。
如:
void MyTask1(void *pdata)
{
for(;;)
{
...
}
}
void main()
{
...
OSInit();       初始化
...
OSTaskCreate(MyTask1,...)    创建用户任务1
...
OSStart();
...
}
2.1.3系统任务
系统任务:①空闲任务(每个应用程序必须使用,为了使CPU在没有任务可执行时有事做)②统计任务(按需求选择使用)
1.空闲任务 / 统计任务
void OS_TaskIdle(void *pdata)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
pdata = pdata; //防止某些编译器报错
for(;;)
{
OS_ENTER_CRITICAL();      //关闭中断
OSIdleCtr ++;           //计数
OS_EXIT_CRITICAL();   //开放中断
}
}
空闲任务OStaskIdle()在不停地给一个32位的名为OSIdleCtr的计数器加1,统计任务用这个计数器确定当前应用软件实际消耗了多少CPU时间(并计算CPU单位时间内被使用时间,结果以百分比形式存在变量OSC-PUUsage中,以便应用程序通过访问它了解CPU利用率)。
    在计数器加1前、后,中断是先关掉,再开启的。因为8位及大多数16位微处理器的32 位数加1需要多条指令,以防止高优先级的任务或中断服务子程序从中打入。
(如果要使用这个统计任务,须在头文件OS_CFG.H中系统配置常数OS_TASK_EN置1,并在穿件统计任务之前调用函数OSStartinit()对统计任务初始化)
2.1.4任务的优先权及优先级别
1.一般,一个应用程序任务数小于64,uc/OS-II把任务的优先权分为64个优先级别(0优先级最高)
2.在文件OS_CFG.H中通过给最低优先级别常数OS_LOWEST_PRIO赋值来说明应用程序中任务优先级别的数目。最低优先级赋给空闲任务,其次统计任务。
3.在调用系统函数OSTaskCreate()时,可通过修改第四个参数prio指定优先级。


2.2任务堆栈
typedef unsigned int OS_STK;   //该类型长度16位
#define TASK_STK_SIZE 512
OS_STK TaskStk[TASK_STK_SIZE ];     //该数组作任务堆栈
INT8U OSTaskCreate(void(*task)(void *pd),      //指向任务的指针
void *pdata,          //传递给任务的参数
OS_STK *ptos, //任务堆栈栈顶的指针
INT8U prio //指定任务优先级别的参数
 )
注意堆栈的增长方向
或者2中情况均写出(为了提高应用程序的可移植性可以在代码OS_CFG.H文件中常数OS_STK_GROWTH作为选择开关,使用户可通过定义该常数的值来选择相应的代码段,以适应不同的堆栈增长方式的需要.):
#define MyTaskStkN 64
OS_STK MytaskStk[MyTaskStkN];
Void main(void)
{
...
#if OS_STK_GROWTH == 1
OSTaskCreate(.......);
#else
..
#endif
....
}
2.2.2任务堆栈的初始化,由OSTaskStkInit()来完成
OS_STK *OSTaskStkInit(
void( *task)(void *pd),
void * pdato,
OS_STK *ptos,
INT16U opt
);


2.3任务控制块及任务控制块链表
 定义:记录任务的堆栈指针,任务的当前状态,任务的优先级别等一些与任务管理有关的属性就叫做任务控制块(OS_TCB)
  任务控制块是一个结构类型数据,当用户应用程序调用OSTaskCreate()函数创建一个用户任务时,这个函数就会对任务控制块中的所有成员赋于该任务相关的数据,并驻留在RAM中.
2.3.1任务控制块结构
typedef struct os_tcb {
    OS_STK        *OSTCBStkPtr;       //指向任务堆栈栈顶的指针
 
#if OS_TASK_CREATE_EXT_EN
    void          *OSTCBExtPtr; //指向任务控制块拓展的指针
    OS_STK        *OSTCBStkBottom; //指向任务堆栈栈底的指针
    INT32U         OSTCBStkSize; //任务堆栈的长度
INT16U         OSTCBOpt; //创建任务时的选择项
    INT16U         OSTCBId; //目前该域未被使用
#endif
 
    struct os_tcb *OSTCBNext; //指向后一个任务控制块的指针
    struct os_tcb *OSTCBPrev;
 
#if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN || OS_SEM_EN
    OS_EVENT      *OSTCBEventPtr; //指向事件控制块的指针
#endif
 
#if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN
    void          *OSTCBMsg; //指向传递给任务消息的指针
#endif
 
    INT16U         OSTCBDly; //任务等待的时限(节拍数)
    INT8U          OSTCBStat; //任务的当前状态标志
    INT8U          OSTCBPrio; //任务优先级别
 
    INT8U          OSTCBX; /
    INT8U          OSTCBY; 用于快速访问就绪表的数据
    INT8U          OSTCBBitX;
    INT8U          OSTCBBitY; /
 
#if OS_TASK_DEL_EN
    BOOLEAN        OSTCBDelReq; //请求删除任务时用到的标志
#endif
} OS_TCB;


OSTCBStat该成员变量可能的值:
OS_STAT_RDY 任务处于就绪状态
OS_STAT_SEM 任务处于等待信号量状态
OS_STAT_MBOX 任务处于等待消息邮箱状态
OS_STAT_Q 任务处于等待消息队列状态
OS_STAT_SUSPEND 任务处于被挂起状态
OS_STAT_MUTEX 任务处于互斥型信号量状态


2.3.2任务控制块链表
1.空任务链表
  因为此链表中这些控制块还没有与具体任务相关联,所以叫做空任务链表。
  大小为ucos-II.H中定义的OS_MAX_TASKS + OS_N_SYS_TASKS(即用户任务最大数+系统任务总数)个。其初始化由系统初始化函数OSInit()完成。其头指针为OSTCBFreeList,其为一个OS_TCB类型的数组。即OS_TCB OSTCBTbl[OS_MAX_TASKS + OS_N_SYS_TASKS];
2.任务链表
每当应用程序调用系统函数OSTaskCreate()或OSTaskCreateExt()创建一个任务的时候,系统就会将空任务链表头指针OSTCBFreeList 指向的任务控制块分配给该任务。在给任务控制块中的成员赋值后,就将其加入OSTCBList所指向的任务控制链表中,于是,就出现了任务链表。
3.任务控制块访问优化:
  为了加快对任务控制块的访问速度,任务链表为双向链表。同时,设置了一个OS_TCB*类型的指针数组OS_TCBTbl[]。其中以任务的优先级为顺序在各数组元素中存放指向该任务控制块的指针。
同样,为了能随时访问正在运行任务的任务控制块,还定义了一个OS_TCB*类型的OSTCBCur,专门用于存放当前正在运行的任务的任务控制块的指针。
4. 任务删除
OSTaskDel()删除任务的过程:把被删除的任务控制块从任务控制块链表中删除,并归还给空任务控制块链表,然后在任务就绪表中将该任务的就绪状态置0。(注:可以通过该函数来删除任务自身或者除了空闲任务之外的其他任务)。


2.3.3任务控制块的初始化
INT8U OSTCBInit(
INT8U prio,     //任务的优先级别,保存在OSTCBPrio 中
OS_STK *ptos,   //任务堆栈栈顶指针,保存在 OSTCBStkPtr中
OS_STK *pbos, //任务堆栈栈底的指针,保存在OSTCBStkBottom中
INT16U id, //任务的标识符,保存在OSTCBId找那个
INT16U stk_size, //任务堆栈的长度,保存在OSTCBStkSize中
void *pext, //任务控制块的拓展指针,保存在OSTCBExtPtr中
INT16U opt, //任务控制块的选择项,保存在OSTCBOpt中
             }
0 0
原创粉丝点击