您的位置:首页 > 其它

UC/OS II 任务管理(3)之初始化

2015-09-05 12:23 183 查看
析完跟任务管理相关的数据结构之后,我们就开始了解跟任务相关的函数了,以及函数之间的关系结构了。
从顶层往底层依此分析,这样可以让思路更加清晰,更加好理解。

1: void OSInit (void) (os_core.c )
在UCOS系统正式运行之前,我们需要对该系统进行初始化,包括重要的数据结构,创建空闲任务,统计任务等系统任务。
这里我们只分析对于该函数里面关于任务管理的部分。如下:
OS_InitMisc(); /*初始化数据变量 */
OS_InitRdyList(); /* 初始化就绪任务相关的变量 */
OS_InitTCBList(); /* 初始化TCB任务控制块链表*/

OS_InitTaskIdle(); /* 初始化和创建空闲任务*/
#if OS_TASK_STAT_EN > 0u
OS_InitTaskStat(); /* 如果是配置系统需要用到统计任务,那么就创建和初始化空闲任务*/
#endif

2:OS_InitMisc(void); (os_core.c)
该函数是初始化各种在系统运行时需要用到的杂项全局变量。
OSRunning = OS_FALSE; 需要注意的是这里在多任务开启之前,这里OSRunning 是OS_FALSE

3:OS_InitRdyList()
初始化跟就绪任务相关的变量。各个相关变量的初始值如下
OSRdyGrp = 0u;
for (i = 0u; i < OS_RDY_TBL_SIZE; i++) {

OSRdyTbl[i] = 0u;

}

OSPrioCur = 0u;

OSPrioHighRdy = 0u;

OSTCBHighRdy = (OS_TCB *)0;
OSTCBCur = (OS_TCB *)0;

4:OS_InitTCBList()
初始化任务控制块相关的数据结构。
OSTCBTbl,OSTCBPrioTbl 清零。
初始化任务控制块,若是任务控制块配置为带名称,则名称初始化为“?”字符串。
将系统任务控制块按顺序用单链表的形式连接起来,然后将链表放在空闲任务控制块链表中,用OSTCBFreeList指向空闲任务控制块链表,OSTCBFreeList = &OSTCBTbl[0];
OSTCBList 指向就绪任务控制块链表。就绪任务控制块链表初始化为空,OSTCBList= (OS_TCB *)0。

5:OS_InitTaskIdle() (os_core.c)
初始化和创建空闲任务(优先级位63)。
空闲任务的作用是在没有其他任务处于就绪状态的时候,空闲任务执行。否则系统中没有任务执行,会引起系统额崩溃。空闲任务是系统任务,非用户任务。

空闲任务函数OS_TaskIdle定义在os_core.c当中,其功能很简单,就是在运行该任务的时候,不断的对全局变量OSIdleCtr进行累加,计算空闲任务运行的节拍数。若是定义了空闲任务钩子函数,则还会运行空闲任务钩子函数。
该函数会在空闲任务创建的时候,被调用。

OS_InitTaskIdle()调用OSTaskCreate或者OSTaskCreateExt函数(具体任务创建函数如何实现,具体在后面分析)进行空闲任务的创建,需要注意的是,系统任务,是有自己独立的堆栈的,与用户任务的堆栈不在一起。空闲任务的堆栈OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE ]在ucos_ii.h中定义。创建任务之后,然后将任务的名称取名为"uC/OS-II Idle"(若是配置为任务有名称的话,即OS_TASK_NAME_EN > 0u)。

6:OS_InitTaskStat()
初始化和创建统计任务(优先级位62)。与空闲任务相类似。
若是宏OS_TASK_STAT_EN配置大于1,创建统计任务,否则不创建统计任务。这个可以根据我们的需求进行配置,决定是否需要。
统计任务函数OS_TaskStat定义在os_core.c中。该函数的主要功能是统计计算CPU的使用率。计算使用率的计算方式为:
OSCPUUsage = 100 * (1 - OSIdleCtr / OSIdleCtrMax ) ;
全局变量是计算在一秒钟之内,空闲任务能够计数到的最大的值。
代码的实现主要是函数中的以下的四行代码
OSIdleCtrMax /= 100uL;
OSIdleCtrRun = OSIdleCtr;
OSIdleCtr = 0uL;
OSCPUUsage = (INT8U)(100uL - OSIdleCtrRun / OSIdleCtrMax);

OSIdleCtrMax /= 100uL;
OSCPUUsage = (INT8U)(100uL - OSIdleCtrRun / OSIdleCtrMax);
这里讲最大值除以100是为了之后的计算。若是不除100,根据前面提到的公式来的话, OSIdleCtr / OSIdleCtrMax这里我们希望得到的是一个浮点数,也就是一个小于1的小数,但是因为OSIdleCtr、OSIdleCtrMax 都是整数,且OSIdleCtr < OSIdleCtrMax,则两个数相除就必定为0,则OSCPUUsage 始终会等于100。所以先OSIdleCtrMax /100,然后再OSIdleCtrRun / OSIdleCtrMax,这个结果就不会是一个小于0的数,这个时候就不会出现始终等于0的情况
。同时在算数逻辑上100 - OSIdleCtrRun / OSIdleCtrMax=100 -OSIdleCtrRun / (OSIdleCtrMax/100) = 100(1 -OSIdleCtrRun / OSIdleCtrMax )。这样计算能够接近数学运算的结果。

OSIdleCtrRun = OSIdleCtr;
OSIdleCtr = 0uL;
这里用到一个临时变量OSIdleCtrRun 存储OSIdleCtr,然后就OSIdleCtr就可以用于下一秒的空闲节拍计数了。

OSTimeDly(OS_TICKS_PER_SEC / 10u); //计算完这些值之后,然后任务将自己阻塞100ms左右。在这个时间内OSIdleCtr又会进行累加(空闲任务优先级低于统计任务,所以只有在统计任务阻塞的时候时候,空闲任务才会执行,OSIdleCtr才会更新 ),用于下一次的统计。是不是源码有问题?OS_TICKS_PER_SEC / 10u,OSIdleCtr是1/10秒内的统计数,但是除的OSIdleCtrMax却是1s之内(v2.9版本中的源码注释是这么写的,ucos_ii.h中定义OSIdleCtrMax的注释)的最大值?个人认为应该不要除10。等具体用到的时候,要记得验证一下。
统计任务的堆栈为OSTaskStatStk[OS_TASK_STAT_STK_SIZE ]。
任务的创建方式跟OS_InitTaskIdle()相似。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: