您的位置:首页 > 其它

UCOS-II任务管理1

2017-04-20 10:56 351 查看
任务控制块:

  一旦任务建立了,任务控制块OS_TCBs将被赋值,任务控制块是一个数据结构当任务的CPU使用权限被剥夺时,uC/OS用它来保存该任务的状态。

typedef struct os_tcb

{

  OS_STK *OSTCBStkPtr;//指向任务栈顶的指针,

  #if OS_TASK_CREATE_EXT_EN

  void *OSTCBExtPtr;//指向用户定义的任务控制块扩展。

  OS_STK *OSTCBStkBottom;//指向任务栈底的指针

  //栈中可以容纳的指针元素数目而不是字节,标示栈容量的总数

  INT32U OSTCBStkSize;

  

  //选择项,OS_TASK_OPT_STK_CHK,OS_TASK_OPT_STK_CLR,OS_TASK_SAVE_FP

  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;//任务状态字,为0表示任务进入就绪态。

  INT8U OSTCBPrio;//任务优先级

  

  //用于加速任务进入就绪态的过程或进入等待事件发生状态的过程,

  INT8U OSTCBX;

  INT8U OSTCBY;

  INT8U OSTCBBitX;

  INT8U OSTCBBitY;

  

  #if OS_TASK_DEL_EN

  BOOLEAN OSTCBDelReq;//表示该任务是否需要删除

  #endif

} OS_TCB;

任务控制块中几个成员的算法:

  OSTCBY = priority >> 3;

  OSTCBBitY = OSMapTbl[priority >> 3];

  OSTCBX = priority & 0x07;

  OSTCBBitX = OSMapTbl[priority & 0x07];

就绪表:

  每个任务被赋予不同的优先级等级,从 0 级到最低优先级OS_LOWEST_PR1O,包括 0 和OS_LOWEST_PR1O 在内。每个任务的就绪态标志都放入就绪表中的,就绪表中有两个变量 OSRedyGrp 和OSRdyTbl[]。

  

当 OSRdyTbl[0]中的任何一位是 1 时,OSRdyGrp 的第 0 位置 1,

当 OSRdyTbl[1]中的任何一位是 1 时,OSRdyGrp 的第 1 位置 1,

...

当 OSRdyTbl[6]中的任何一位是 1 时,OSRdyGrp 的第 6 位置 1,

当 OSRdyTbl[7]中的任何一位是 1 时,OSRdyGrp 的第 7 位置 1,

OSMapTbl[]的值:

  OSMapTbl[0]:0000 0001

  OSMapTbl[1]:0000 0010

  OSMapTbl[2]:0000 0100

  ...

  OSMapTbl[7]:1000 0000

使任务进入就绪态:

  OSRdyGrp |= OSMapTbl[prio >> 3];

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

从就绪表中删除一个任务:

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

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

OSUnMapTbl[ ]:是预先存好的一个表,用于查询一个字节中最低位为1的位在第几bit。

找出进入就绪态的优先级最高的任务:

  y = OSUnMapTbl[OSRdyGrp];

  x = OSUnMapTbl[OSRdyTbl[y]];

  prio = (y << 3) + x;

任务调度:

  uC/OS任务调度所花费的时间是常数。

  任务级调度函数:OSSched();

  中断级调度函数:OSIntExt();

void OSSched (void)

{

  INT8U y;

  OS_ENTER_CRITICAL();

  if ((OSLockNesting | OSIntNesting) == 0)//判断中断嵌套层数和任务调度器是否上锁

  {

  y = OSUnMapTbl[OSRdyGrp];

  OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);

  if (OSPrioHighRdy != OSPrioCur)

   {

  OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];

  OSCtxSwCtr++;

  OS_TASK_SW();

  }

  }

  OS_EXIT_CRITICAL();

}

任务切换的步骤:

将被挂起任务的微处理器寄存器推入堆栈,然后将较高优先级的任务的寄存器值从栈中恢复到寄存器中。

要将 OS_TCBHighRdy 指向即将被运行的任务,还需要让当前任务控制块 OSTCBCur 指向即将被运行的任务。

给任务调度器上锁和解锁:

  OSSchedlock()、 OSSchedUnlock()。 调用 OSSchedlock()的任务保持对 CPU 的控制权,尽管有个优先级更高的任务进入了就绪态。但是中断服务是能够被识别的(假设中断是打开的),OSLockNesting表示调度器上锁的嵌套层数,最多嵌套255层,为0时即不上锁。

  调用 OSSchedLock()以后,用户的应用程序不得使用任何能将现行任务挂起的系统调用。也就是说,用户程序不得调用OSMboxPend()、OSQPend()、OSSemPend()、OSTaskSuspend(OS_PR1O_SELF)、OSTimeDly()或 OSTimeDlyHMSM(),直到 OSLockNesting 回零为止。因为调度器上了锁,用户就锁住了系统,任何其它任务都不能运行。

  当低优先级的任务要发消息给多任务的邮箱、消息队列、信号量时,用户不希望高优先级的任务在邮箱、队列和信号量没有得到消息之前就取得了CPU 的控制权,此时,用户可以使用禁止调度器函数。

空闲任务:

  OSTaskIdle() 这个任务在没有其它任务进入就绪态时投入运行。这个空闲任务[OSTaskIdle()]永远设为最低优先级,空闲任务不可能被应用软件删除。闲任务OSTaskIdle()什么也不做,只是在不停地给一个 32 位的名叫 OSIdleCtr 的计数器加 1,统计任务使用这个计数器以确定现行应用软件实际消耗的 CPU 时间。

统计任务:

  OSTaskStat()  如果用户将系统定义常数 OS_TASK_STAT_EN(见文件 OS_CFG.H)设为 1,这个任务就会建立。一旦得到了允许,OSTaskStat()每秒钟运行一次(见文件 OS_CORE.C),计算当前的 CPU 利用率。 用百分比表示,这个值放在一个有符号 8 位整数 OSCPUsage 中,精读度是 1 个百分点。

  如果用户应用程序打算使用统计任务,用户必须在初始化时建立一个唯一的任务,在这个任务中调用 OSStatInit() 换句话说,在调用系统启动函数 OSStart()之前,用户初始代码必须先建立一个任务,在这个任务中调用系统统计初始化函数OSStatInit(),然后再建立应用程序中的其它任务。

  为了能够计算CPU的使用率,所以在OSStatInit()中主要任务就是得到在1S内能将OSIdleCtr加的最大次数并保存。

  

时钟节拍:

  μC/OS 需要用户提供周期性信号源,用于实现时间延时和确认超时。节拍率应在每秒10 次到 100 次之间,或者说 10 到 100Hz。时钟节拍率越高,系统的额外负荷就越重。时钟节拍的实际频率取决于用户应用程序的精度。时钟节拍源可以是专门的硬件定时器,也可以是来自 50/60Hz 交流电源的信号。

  用户必须在多任务系统启动以后再开启时钟节拍器,也就是在调用 OSStart()之后。换句话说,在调用 OSStart()之后做的第一件事是初始化定时器中断。千万不能再OSInit之后就允许时钟节拍中断, 时钟节拍中断有可能在μC/OS-Ⅱ启动第一个任务之前发生,此时μC/OS-Ⅱ是处在一种不确定的状态之中,用户应用程序有可能会崩溃。

OSInit() uC/OS初始化:

  在调用μC/OS-Ⅱ的任何其它服务之前,μC/OS-Ⅱ要求用户首先调用系统初始化函数OSIint()。OSIint()初始化μC/OS-Ⅱ所有的变量和数据结构。

OSStart() uC/OS启动:

  多任务的启动是用户通过调用 OSStart()实现的。然而,启动μC/OS-Ⅱ之前,用户至少要建立一个应用任务。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息