首先我们看任务就绪表的设置过程,当任务创建的时候需要设置一次任务就绪表,所以我们先看oscreatetask,在里面查找到这句代码
err = OS_TCBInit(prio, psp, (OS_STK *)0, 0u, 0u, (void *)0, 0u);//然后初始化tcb任务区
还记得tcb中有四个变量是用于快速查找任务就绪表的,分别是
ptcb->OSTCBY ptcb->OSTCBX ptcb->OSTCBBitY ptcb->OSTCBBitX 在OS_TCBInit中处理流程如下 #if OS_LOWEST_PRIO <= 63u ptcb->OSTCBY = (INT8U)(prio >> 3u); ptcb->OSTCBX = (INT8U)(prio & 0x07u); #else ptcb->OSTCBY = (INT8U)((INT8U)(prio >> 4u) & 0xFFu); ptcb->OSTCBX = (INT8U) (prio & 0x0Fu); #endif
ptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY); ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX); 可以看到,现在当系统定义的优先级大于63之后OSTCBY和OSTCBX的赋值方式发生了改变,之前是将345三位用于存放任务就绪分组,012存放就绪任务状态,这样就有了8个分组和每组八个任务,一共64个任务,而现在 将0123四个位存放就绪任务状态值,4567四个位存放就绪任务分组的值,这样就有16个分组和16个位来存放,一共就能有256个任务了. 这样改变之后就需要重新设置OSRdyGrp和OSRdyTbl[]的位宽,查看代码有以下内容 OS_EXT OS_PRIO OSRdyGrp; OS_EXT OS_PRIO OSRdyTbl[OS_RDY_TBL_SIZE]; 位宽由OS_PRIO指定,再看OS_PRIO的定义,如下 #if OS_LOWEST_PRIO <= 63u typedef INT8U OS_PRIO; #else typedef INT16U OS_PRIO; #endif #define OS_RDY_TBL_SIZE ((OS_LOWEST_PRIO) / 16u + 1u) 当优先级变化的时候,分组的宽度变成了16位,同时,数组长度变成了优先级/16+1,也就是说最多有16个元素,和我们所料不差,同样,当我们从任务就绪表中找出当前最高优先级的就绪任务的时候,查找方式也发生了变化,如下 INT8U y; OS_PRIO *ptbl;
if ((OSRdyGrp & 0xFFu) != 0u) { y = OSUnMapTbl[OSRdyGrp & 0xFFu]; } else { y = OSUnMapTbl[(OS_PRIO)(OSRdyGrp >> 8u) & 0xFFu] + 8u; } ptbl = &OSRdyTbl[y]; if ((*ptbl & 0xFFu) != 0u) { OSPrioHighRdy = (INT8U)((y << 4u) + OSUnMapTbl[(*ptbl & 0xFFu)]); } else { OSPrioHighRdy = (INT8U)((y << 4u) + OSUnMapTbl[(OS_PRIO)(*ptbl >> 8u) & 0xFFu] + 8u); } 而之前的查找方式就颇为简单了 y = OSUnMapTbl[OSRdyGrp]; OSPrioHighRdy = (INT8U)((y << 3u) + OSUnMapTbl[OSRdyTbl[y]]); 这两种方式有什么区别? 首先, OSUnMapTbl这个数组是没有变化的,但是OSRdyGrp变成16位了,不能直接去表里面去查找了,这里面就做了一个调整,当低八位有任何一个不为0的时候,说明此时优先级最高的就绪任务的优先级在前八个OSRdyTbl元素中,0-7这是可以直接查表的,那当为0的时候,说明此时最高优先级的元素至少是第八个元素,那么将高八位代表的数值标出来,加上8,就能得到大于8的分组优先级. 好,此时分组优先级得到了,要去找子优先级,可以直接在数组中找到,但是得到的数据时16进制的bcd码,还需要转换一次到hex,并且找出最高优先级,那就再用OSUnMapTbl过一次,处理的原理还是低八位有效直接通过低八位查找,高八位有效通过高八位查找并加上8,两个都得到之后 Y左移四位加上子分组四位,就能得到当前最高优先级的任务的优先级了
总结:ucos扩展任务优先级的方法就是将OSTCBY和OSTCBX原先三位标识优先级转为四位,将优先级从64转为256. |