三.UC/OS-Ⅱ任务管理

三.UC/OS-Ⅱ任务管理

目录

三.UC/OS-Ⅱ任务管理

1.UC/OS –II中的任务

UC/OS-II开关中断的方法 

2. 任务状态

1.睡眠态又称(休眠状态)(task dormant) 

 2.就绪态(task ready)

3. 运行态(task running)

4.等待状态(task waiting) 

5.中断服务态(ISR running) 

 3.任务控制块(TCB)

Ucos-II任务代码的一般框架 

4. 空任务列表

5.任务级的任务调度--OSSched 

7.就绪表 

 1.根据优先级找到任务在就绪任务表中的位置

1.入表操作:

2.出表操作:

3.查表操作:

8.任务调度器(task scheduler)

​编辑

 9.任务切换的机理 

10. 调度时机

1.用函数OSTaskCreate( )创建任务

 2.uC/OS-II的任务框架

3. 试写出OSStartHighRdy( )函数的示意代码



1.UC/OS –II中的任务

  1. uC/OS –II 2.5版本支持64个任务,每个任务一个特定的优先级。数字越小,优先级越高
  2. 系统总是运行进入就绪态优先级最高的任务
  3. 任务优先级号就是任务编号(ID).优先级号也被一些内核功能函数调用。如OsTaskChangePrio( )及OsTaskDel( ).
  4. 系统占用了8个任务,保留优先级为0、1、2、3、OS_LOWEST_PRIO-3、 OS_LOWEST_PRIO-2、 OS_LOWEST_PRIO-1、 OS_LOWEST_PRIO-0
  5. 即:建议不使用上述最高4个和最低4个优先级,用户任务仍可达56个

UC/OS-II开关中断的方法 

UC/OS-II定义了两个宏调用来开关中断:

  • OS_ENTER_CRITICAL( ) (禁止中断的宏)
  • OS_EXIT_CRITICAL( )   (启用中断的宏)

 通常成对出现

2. 任务状态

在任一给定的时刻,任务的状态一定是以下五种状态之一:
  1. 睡眠态(task dormant
  2. 就绪态(task ready
  3. 运行态(task running
  4. 等待状态(task waiting
  5. 中断服务态(ISR running)

1.睡眠态又称(休眠状态)(task dormant) 

  • 指任务驻留在程序空间(ROMRAM),还没有交给系统来管理的状态
  • 任务交给系统通过调用以下函数之一来实现: 

OSTaskCreate()

OSTaskCreateExt()

  • 告知系统:
  1. 任务的起始地址
  2. 任务建立时,用户给任务赋予的优先级
  3. 任务要使用的栈空间大小等

 2.就绪态(task ready)

  • 任务一旦创建就进入就绪态,准备运行
  • 任务的创建可以是在多任务开始之前,也可以动态地由一个运行着的任务创建
  • 若刚创建任务的优先级高于创建它的任务的优先级,它将立即获得cpu的使用权
  • 任务可通过OSTaskDel()返回睡眠态;或调用该函数让另一个任务进入睡眠态

3. 运行态(task running)

  • 就绪的任务只有当所有优先级高于它的任务都转为等待状态,或被删除后,才能进入运行态
  • 任何时刻只有一个任务处于运行态
  • 调用OSStart()可以启动多任务。该函数只能在启动时调用一次
  • OSStart()运行用户初始化代码中已经建立的、进入就绪态的优先级最高的任务

4.等待状态(task waiting) 

  • 正在运行的任务可以通过下面的调用进入等待状态。延迟时间到,立即强制执行任务切换,让下一个优先级最高、并进入就绪态的任务执行。
OSTimeDly ()
OSTimeDlyHMSM ()
  • 等待时间过去后,系统服务(内部)函数OSTimeTick()使延迟了的任务进入就绪态用户无需在应用程序代码中调用这个函数
  • 正在运行的任务可能需要通过调用函数等待某一事件发生。如果该事件并未发生,任务就进入等待状态
OSFlagPend (); OSMutexPend ()
OSSemPend (); OSMboxPend ()
当事件发生或等待超时,被挂起的任务就进入就绪态

5.中断服务态(ISR running) 

  • 正在执行的任务是可以被中断的,除非该任务将中断关闭,或系统将中断关闭。被中断的任务便进入了中断服务态。
  • 响应中断后,正在运行的任务被挂起,中断服务子程序控制了CPU的使用权
  • 中断服务子程序可能会报告一个或多个事件的发生,而使一个或多个任务进入就绪态
  • 上述情况下,从中断服务子程序返回之前,uC/OS II 要判定:
被中断的任务是否还是就绪态任务中优先级最高的
如果中断服务子程序使另一个优先级更高的任务进入了就绪态,则新进入就绪态的这个优先级更高的任务将得以运行;否则,原来被中断了的任务将继续运行。

当所有的任务都在等待时间发生或等待延迟时间结束时,uC/OS II 执行被称为空闲任务(Idle Task)的内部函数,即:OSTaskIdle() 

任务状态转换图:

 3.任务控制块(TCB)

  • 任务控制块 OS_TCB是一个数据结构,保存该任务的相关参数,包括任务堆栈指针、状态、优先级、任务表位置、任务链表指针等
  • 所有的任务控制块分为两条链表:

空闲链表

使用链表

  • 当任务的CPU使用权被剥夺时,系统用它来保存该任务的状态全部驻留在RAM
typedef struct os_tcb {
    OS_STK        *OSTCBStkPtr(当前任务堆栈栈顶指针);
#if OS_TASK_CREATE_EXT_EN>0
    void          *OSTCBExtPtr; (指向用户定义的任务控制块扩展) 
    OS_STK        *OSTCBStkBottom;(指向任务堆栈栈底指针)
    INT32U         OSTCBStkSize;(存有栈中可容纳的指针元数目)
    INT16U         OSTCBOpt; 
    INT16U         OSTCBId; (存储任务的识别码ID,备用)
#endif
    struct os_tcb *OSTCBNext; (任务控制块OS-TCB双向链表的后链接)
    struct os_tcb *OSTCBPrev; (任务控制块OS-TCB双向链表的前链接)
#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;

Ucos-II任务代码的一般框架 

void MyTask( void *pdata )
{
   for(;;)
    {
       可以被中断的用户代码;
       OS_ENTER_CRITICAL();  //进入临界段(关中断)
       不可以被中断的用户代码;
       OS_EXIT_CRITICAL();    //退出临界段(开中断)
       可以被中断的用户代码;
    }
}

4. 空任务列表

  • 所有的任务控制块都被放置在任务控制块列表数组OSTCBTbl[ ]
  • 系统初始化时,所有任务控制块被链接成空任务控制块的单向链表
  • 任务建立后,空任务控制块指针OSTCBFreeList指向的任务控制块就赋给了该任务,然后OSTCBFreeList的值调整为指向链表中的下一个空任务控制块
  • 任务一旦被删除,任务控制块就还给空任务链表 

5.任务级的任务调度--OSSched 

  • UC/OS占先式实时多任务内核,优先级最高的任务一旦准备就绪,则拥有CPU的所有权即开始投入运行。
  • UC/OS不支持时间片轮转法,每个任务的优先级要求不一样且是唯一的。因此,任务调度就是:查找准备就绪的最高优先级的任务并进行上下文切换。
  • UC/OS任务调度所花的时间为常数,与应用程序中建立的任务数无关。

7.就绪表 

根据就绪表确定最高优先级两个关键:

  1. 优先级数分解为高三位和低三位分别确定
  2. 高优先级有着小的优先级号 

 1.根据优先级找到任务在就绪任务表中的位置

把优先级转换为2进制 得到8位二进制数,其中D_{0}D_{1}D_{2}的值表示OSRdyTbl [ n ]D_{3}D_{4}D_{5}的值表示OSRdyGrp [ n ]。如下图所示:

任务就绪表的三种基本操作包括:插入任务到任务就绪表从任务就绪表中删除任务查找最高优先级的就绪任务。 

以下是三种基本操作的C代码:

1.入表操作:

在程序中,可以用类似下面的代码把优先级别为prio的任务置为就绪状态:

OSRdyTbl[prio>>3] | = OSMapTbl[prio&0x07];

OSRdyGrp | = OSMapTbl[prio>>3];

2.出表操作:

如果要使一个优先级别为prio的任务脱离就绪状态则可使用如下类似代码:

if((OSRdyTbl[prio>>3] &= ~OSMapTbl[prio&0x07]) == 0)

      OSRdyGrp&=~OSMapTbl[prio>>3]; 

3.查表操作:

在就绪表中计算机查找最高优先级别任务的代码:

y =   OSUnMapTbl[OSRdyGrp];

x =   OSUnMapTbl[OSRdyTbl[y]];

prio = (y<<3) +x;

8.任务调度器(task scheduler)

OSTCBHighRdy 待运行任务控制块
OSTCBCur 正在运行的运行任务控制块

 9.任务切换的机理 

任务切换就是中止正在运行的任务(当前任务),转而去运行另外一个任务的操作,当然这个任务应该是就绪任务中优先级别最高的那个任务  

将被挂起的任务寄存器入栈
将较高优先级任务的寄存器出栈

 任务级的任务切换宏OS_TASK_SW()

OS_TASK_SW()是宏调用,含有微处理器的软中断指令。因为,系统假定任务切换是靠中断级代码完成的。

OS_TASK_SW()将处理器相关的软件中断机制封装起来,便于操作系统移植

10. 调度时机

1.用函数OSTaskCreate( )创建任务

 应用程序通过调用OSTaskCreate( ) 函数来创建一个任务,OSTaskCreate( )函数的原型如下:

INT8U OSTaskCreate (
  void (*task)(void *pd),//指向任务的指针
  void *pdata,	//传递给任务的参数 
  OS_STK *ptos,	//指向任务堆栈栈顶的指针
  INT8U prio	//任务的优先级
)

 2.uC/OS-II的任务框架

void  task_xxx(void *pdata)
{
    /* 该任务的初始化工作 */ 
            ……    
    /* 进入该任务的死循环 */
    while(1)
    {
        ……
    }
}

或者写作这种形式:

3. 试写出OSStartHighRdy( )函数的示意代码

void OSStartHighRdy()  {    
    调用用户定义的OSTaskSwHook(); 
    OSRuning = TRUE;  
    得到将要恢复运行任务的堆栈指针:  Stack pointer = OSTCBHighRdy->OSTCBStkPtr;
    从新任务堆栈中恢复处理器的所有寄存器;
    执行中断返回指令; 
}    

猜你喜欢

转载自blog.csdn.net/weixin_51659166/article/details/131077562