您的位置:首页 > 其它

ucos-iii任务

2013-02-10 20:52 225 查看
这回说下任务建立,那么我们看下任务控制块有哪些内容:
(这系统越来越大,任务控制块的内容也是越来越多了,呵呵)
struct os_tcb {
CPU_STK *StkPtr; /*这是堆栈指针,指向任务自己的堆栈的操作端*/

void *ExtPtr; /*如果我们还为任务建了数据缓冲区,就用这个指针指向这个地址*/

CPU_STK *StkLimitPtr; /*这是怕咱把堆栈用冒了,限制堆栈空间大小的*/

OS_TCB *NextPtr; /*建立了任务,prio值一样的,就会连接在一起,不管你是什么状态,能不能动,这个是指向前一个任务控制块*/
OS_TCB *PrevPtr; /* 指向后一个任务控制块*/

OS_TCB *TickNextPtr; /*有些任务可能在睡觉呢,要经过一定的时钟节拍才会醒,这些任务就用这个连在一起*/
OS_TCB *TickPrevPtr; /*同上,只不过,前一个指向前面的任务控制块,这个是指向后面的*/

OS_TICK_SPOKE *TickSpokePtr; /* 也是当任务被delay时用来管理任务的 */

CPU_CHAR *NamePtr; /* 给任务起名字,感觉没太大用处*/

CPU_STK *StkBasePtr; /* */

OS_TASK_PTR TaskEntryAddr; /* 指向任务的函数体*/
void *TaskEntryArg; /*这个我就知道怎么用了,反正也没看到内核用到它,可能也是给用户的,给个0就行了,不用在意 */

OS_PEND_DATA *PendDataTblPtr; /*任务会因为等资源而被挂起,这个就先不说了*/
OS_STATE PendOn; /* 指示任务被挂起下面说一下。 */
OS_STATUS PendStatus; /* 挂起的状态 下面说*/

OS_STATE TaskState; /* See OS_TASK_STATE_xxx任务的状态,下面说 */
OS_PRIO Prio; /* Task priority (0 == highest)优先级 */
CPU_STK_SIZE StkSize; /* 堆栈的大小 */
OS_OPT Opt; /* 留给任务的一些选项,下面说吧 */

OS_OBJ_QTY PendDataTblEntries; /* Size of array of objects to pend on */

CPU_TS TS; /* 时间戳,得到任务建立的时间 */

OS_SEM_CTR SemCtr; /* 信号量,等说到这个资源时吧,这里不说了 */

/* DELAY / TIMEOUT这三个变量也是一言难尽 */
OS_TICK TickCtrPrev; /* Previous time when task was ready */
OS_TICK TickCtrMatch; /* Absolute time when task is going to be ready */
OS_TICK TickRemain; /* Number of ticks remaining for a match (updated at ... */
/* ... run-time by OS_StatTask() */
OS_TICK TimeQuanta;/*这两个说过了,不说了*/
OS_TICK TimeQuantaCtr;

#if OS_MSG_EN > 0u
void *MsgPtr; /* 得到的消息资源就放在这 */
OS_MSG_SIZE MsgSize; /* 消息量*/
#endif

#if OS_CFG_TASK_Q_EN > 0u
OS_MSG_Q MsgQ; /* 消息队列 */
#if OS_CFG_TASK_PROFILE_EN > 0u
CPU_TS MsgQPendTime; /* Time it took for signal to be received */
CPU_TS MsgQPendTimeMax; /* Max amount of time it took for signal to be received */
#endif
#endif

#if OS_CFG_TASK_REG_TBL_SIZE > 0u
OS_REG RegTbl[OS_CFG_TASK_REG_TBL_SIZE]; /* Task specific registers */
#endif

#if OS_CFG_FLAG_EN > 0u
OS_FLAGS FlagsPend; /* 等待的标志位资源 */
OS_FLAGS FlagsRdy; /* */
OS_OPT FlagsOpt; /* Options (See OS_OPT_FLAG_xxx)标志的选项 */
#endif

#if OS_CFG_TASK_SUSPEND_EN > 0u
OS_NESTING_CTR SuspendCtr; /* Nesting counter for OSTaskSuspend()当一个任务的任务控制块为空时会用到这个 */
#endif

#if OS_CFG_TASK_PROFILE_EN > 0u /*下面都是统计的,说到统计任务时候说吧*/
OS_CPU_USAGE CPUUsage; /* CPU Usage of task (0-100%) */
OS_CTX_SW_CTR CtxSwCtr; /* Number of time the task was switched in */
CPU_TS CyclesDelta; /* value of OS_TS_GET() - .CyclesStart */
CPU_TS CyclesStart; /* Snapshot of cycle counter at start of task resumption */
OS_CYCLES CyclesTotal; /* Total number of # of cycles the task has been running */
OS_CYCLES CyclesTotalPrev; /* Snapshot of previous # of cycles */

CPU_TS SemPendTime; /* Time it took for signal to be received */
CPU_TS SemPendTimeMax; /* Max amount of time it took for signal to be received */
#endif

#if OS_CFG_STAT_TASK_STK_CHK_EN > 0u
CPU_STK_SIZE StkUsed; /* Number of stack elements used from the stack */
CPU_STK_SIZE StkFree; /* Number of stack elements free on the stack */
#endif

#ifdef CPU_CFG_INT_DIS_MEAS_EN
CPU_TS IntDisTimeMax; /* Maximum interrupt disable time */
#endif
#if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u
CPU_TS SchedLockTimeMax; /* Maximum scheduler lock time */
#endif

#if OS_CFG_DBG_EN > 0u
OS_TCB *DbgPrevPtr;
OS_TCB *DbgNextPtr;
CPU_CHAR *DbgNamePtr;
#endif
};

/******************************************************************************************************
OS_STATE PendOn这个变量取如下值
#define OS_TASK_PEND_ON_NOTHING (OS_STATE)( 0u) /* 不等任何资源 */
#define OS_TASK_PEND_ON_FLAG (OS_STATE)( 1u) /* 如果是因为等待标志位被挂起的话PendOn等于这个值 */
#define OS_TASK_PEND_ON_TASK_Q (OS_STATE)( 2u) /* 因等待消息而被挂起 */
#define OS_TASK_PEND_ON_MULTI (OS_STATE)( 3u) /* 如果是等待多个资源的话就赋这个值 */
#define OS_TASK_PEND_ON_MUTEX (OS_STATE)( 4u) /* 因等互诉信号而被挂起的话为这个值 */
#define OS_TASK_PEND_ON_Q (OS_STATE)( 5u) /* 等待队列 */
#define OS_TASK_PEND_ON_SEM (OS_STATE)( 6u) /* 等待信号量 */
#define OS_TASK_PEND_ON_TASK_SEM (OS_STATE)( 7u) /* 这个和上面什么不同我还不清楚 */

*******************************************************************************************************/
/******************************************************************************************************
TaskState任务状态(注意注释里的二进制值,你会发现更多)
#define OS_TASK_STATE_RDY (OS_STATE)( 0u) /* 0 0 0 就绪 */
#define OS_TASK_STATE_DLY (OS_STATE)( 1u) /* 0 0 1 delay延时 */
#define OS_TASK_STATE_PEND (OS_STATE)( 2u) /* 0 1 0 因等资源而被挂起 */
#define OS_TASK_STATE_PEND_TIMEOUT (OS_STATE)( 3u) /* 0 1 1 因等资源而被挂起,并且在等资源时有时间限制*/
下面单说下面的状态是在调用了void OSTaskSuspend (OS_TCB *p_tcb,
OS_ERR *p_err)后得到的
#define OS_TASK_STATE_SUSPENDED (OS_STATE)( 4u) /* 1 0 0 Suspended */
#define OS_TASK_STATE_DLY_SUSPENDED (OS_STATE)( 5u) /* 1 0 1 Suspended + Delayed or Timeout */
#define OS_TASK_STATE_PEND_SUSPENDED (OS_STATE)( 6u) /* 1 1 0 Suspended + Pend */
#define OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED (OS_STATE)( 7u) /* 1 1 1 Suspended + Pend + Timeout */
这是说明该任务被删除了
#define OS_TASK_STATE_DEL (OS_STATE)(255u)
前4个不用说了,说下SUSPENDED的吧,
如果原来是OS_TASK_STATE_RDY,调用了OSTaskSuspend 函数的话就会得到OS_TASK_STATE_SUSPENDED状态,这个状态就是不干活,
如果原来是OS_TASK_STATE_DLY,调用了OSTaskSuspend 函数的话就会得到OS_TASK_STATE_DLY_SUSPENDED
剩下的两个的同上。
如果一个任务是OS_TASK_STATE_DLY_SUSPENDED,如果延时时间到了,就会变成OS_TASK_STATE_SUSPENDED,这个状态还是不会干活的
如果这时调用了void OSTaskResume (OS_TCB *p_tcb,
OS_ERR *p_err)这时就会变成OS_TASK_STATE_RDY,这样就能干活了。

*******************************************************************************************************/
/******************************************************************************************************
OS_OPT Opt; 看英语就能明白了,不说了
#define OS_OPT_TASK_NONE (OS_OPT)(0x0000u) /* No option selected */
#define OS_OPT_TASK_STK_CHK (OS_OPT)(0x0001u) /* Enable stack checking for the task */
#define OS_OPT_TASK_STK_CLR (OS_OPT)(0x0002u) /* Clear the stack when the task is create */
#define OS_OPT_TASK_SAVE_FP (OS_OPT)(0x0004u) /* Save the contents of any floating-point registers */
*******************************************************************************************************/
其他资源用到时说,这里说可能有点早,先说任务的建立吧
/******************************************************************************************************
void OSTaskCreate (OS_TCB *p_tcb, /*和以前不同,ucos-iii的任务控制块是要我们用的时候自己明名一个*/
CPU_CHAR *p_name,
OS_TASK_PTR p_task,
void *p_arg,
OS_PRIO prio,
CPU_STK *p_stk_base,
CPU_STK_SIZE stk_limit,
CPU_STK_SIZE stk_size,
OS_MSG_QTY q_size,
OS_TICK time_quanta,
void *p_ext,
OS_OPT opt,
OS_ERR *p_err)
{
CPU_STK_SIZE i;
#if OS_CFG_TASK_REG_TBL_SIZE > 0u
OS_OBJ_QTY reg_nbr;
#endif
CPU_STK *p_sp;
CPU_STK *p_stk_limit;
CPU_SR_ALLOC();

#ifdef OS_SAFETY_CRITICAL
if (p_err == (OS_ERR *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return;
}
#endif

#ifdef OS_SAFETY_CRITICAL_IEC61508
if (OSSafetyCriticalStartFlag == DEF_TRUE) {
*p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
return;
}
#endif

#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* ---------- CANNOT CREATE A TASK FROM AN ISR ---------- */
*p_err = OS_ERR_TASK_CREATE_ISR;
return;
}
#endif

#if OS_CFG_ARG_CHK_EN > 0u /* ---------------- VALIDATE ARGUMENTS ------------------ */
if (p_tcb == (OS_TCB *)0) { /* User must supply a valid OS_TCB */
*p_err = OS_ERR_TCB_INVALID;
return;
}
if (p_task == (OS_TASK_PTR)0) { /* User must supply a valid task */
*p_err = OS_ERR_TASK_INVALID;
return;
}
if (p_stk_base == (CPU_STK *)0) { /* User must supply a valid stack base address */
*p_err = OS_ERR_STK_INVALID;
return;
}
if (stk_size < OSCfg_StkSizeMin) { /* User must supply a valid minimum stack size */
*p_err = OS_ERR_STK_SIZE_INVALID;
return;
}
if (stk_limit >= stk_size) { /* User must supply a valid stack limit */
*p_err = OS_ERR_STK_LIMIT_INVALID;
return;
}
if (prio >= OS_CFG_PRIO_MAX) { /* Priority must be within 0 and OS_CFG_PRIO_MAX-1 */
*p_err = OS_ERR_PRIO_INVALID;
return;
}
#endif

#if OS_CFG_ISR_POST_DEFERRED_EN > 0u
if (prio == (OS_PRIO)0) {
if (p_tcb != &OSIntQTaskTCB) {
*p_err = OS_ERR_PRIO_INVALID; /* Not allowed to use priority 0 */
return;
}
}
#endif

if (prio == (OS_CFG_PRIO_MAX - 1u)) {
if (p_tcb != &OSIdleTaskTCB) {
*p_err = OS_ERR_PRIO_INVALID; /* Not allowed to use same priority as idle task */
return;
}
}
/*之前都是排错处理,这里就不说了。说下面的*/
OS_TaskInitTCB(p_tcb); /* 给你这个任务控制块赋初值 */

*p_err = OS_ERR_NONE;
/* --------------- CLEAR THE TASK'S STACK --------------- */
if ((opt & OS_OPT_TASK_STK_CHK) != (OS_OPT)0) { /* 任务的一些选项设置,这里是看要不要查看任务堆栈 */
if ((opt & OS_OPT_TASK_STK_CLR) != (OS_OPT)0) { /* 这里是看要不要把不为0的清0,也不一定必要吧,下面初始化任务堆栈时会赋合适的值的*/
p_sp = p_stk_base;
for (i = 0u; i < stk_size; i++) { /* Stack grows from HIGH to LOW memory */
*p_sp = (CPU_STK)0; /* Clear from bottom of stack and up! */
p_sp++;
}
}
}
/* ------- INITIALIZE THE STACK FRAME OF THE TASK ------- */
#if (CPU_CFG_STK_GROWTH == CPU_STK_GROWTH_HI_TO_LO)/*堆栈增涨方式是从高地址到低地址,还是低地址到高地址*/
p_stk_limit = p_stk_base + stk_limit;/*堆栈限制区如果是从高到低的话,很明显是最后的从P_stk_base到p_stk_limit设为禁用*/
#else
p_stk_limit = p_stk_base + (stk_size - 1u) - stk_limit;/*如果从低到高的增涨方式,到从p_stk_limit到p_stk_base+(stk_size-1)设为禁用*/
#endif

p_sp = OSTaskStkInit(p_task, /*堆栈初始化*/
p_arg,
p_stk_base,
p_stk_limit,
stk_size,
opt);

/* -------------- INITIALIZE THE TCB FIELDS ------------- */
p_tcb->TaskEntryAddr = p_task; /* 任务函数的入口址 */
p_tcb->TaskEntryArg = p_arg; /* 参数,不多说了 */

p_tcb->NamePtr = p_name; /* 任务名,也就是字符串 */

p_tcb->Prio = prio; /* 任务的优先级 */

p_tcb->StkPtr = p_sp; /* 这是OSTaskStkInit的返回值,是堆栈能操作的一端 */
p_tcb->StkLimitPtr = p_stk_limit; /* 设置限制区 */

p_tcb->TimeQuanta = time_quanta; /* 上节有说过,同一优先级值的任务的轮转 */
#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
if (time_quanta == (OS_TICK)0) {
p_tcb->TimeQuantaCtr = OSSchedRoundRobinDfltTimeQuanta;
} else {
p_tcb->TimeQuantaCtr = time_quanta;
}
#endif
p_tcb->ExtPtr = p_ext; /* 指向你为这个任务建的数据区地址 */
p_tcb->StkBasePtr = p_stk_base; /* 任务的基地地,不代表堆栈从这开始操作,也不代表从反向开始操作。*/
p_tcb->StkSize = stk_size; /* 任务堆栈的大小 */
p_tcb->Opt = opt; /* 任务的选项卡,上面还真说了 */

#if OS_CFG_TASK_REG_TBL_SIZE > 0u
for (reg_nbr = 0u; reg_nbr < OS_CFG_TASK_REG_TBL_SIZE; reg_nbr++) {
p_tcb->RegTbl[reg_nbr] = (OS_REG)0; /*这里可以装数据*/
}
#endif

#if OS_CFG_TASK_Q_EN > 0u
OS_MsgQInit(&p_tcb->MsgQ, /* 初始化这个任务的消息 */
q_size);
#endif

OSTaskCreateHook(p_tcb); /* 调用勾子函数,要我们自己写,也可以是空的 */

/* --------------- ADD TASK TO READY LIST --------------- */
OS_CRITICAL_ENTER();/*这两个下面说吧*/
OS_PrioInsert(p_tcb->Prio);
OS_RdyListInsertTail(p_tcb);

#if OS_CFG_DBG_EN > 0u
OS_TaskDbgListAdd(p_tcb);
#endif

OSTaskQty++; /* 当前系统的任务数 */

if (OSRunning != OS_STATE_OS_RUNNING) { /* OSRunning是不是运行状态如果还没调用OSStart的话就不是,那么到些返回 */
OS_CRITICAL_EXIT();
return;
}

OS_CRITICAL_EXIT_NO_SCHED();

OSSched();/*要是调用过OSStart就到这进行任务调度*/
}
*******************************************************************************************************/
/******************************************************************************************************
OS_PrioInsert(p_tcb->Prio)这个在上节说了,就是在建立任务时这个任务一定是就绪的,所以就会注册到OSPrioTbl[ix]中合适的位置。
OS_RdyListInsertTail说下这个函数,说到它了就不得不说下p_rdy_list,
struct os_rdy_list {
OS_TCB *HeadPtr; /* 同优先级的首个任务 */
OS_TCB *TailPtr; /* 同优先级的末尾任务 */
OS_OBJ_QTY NbrEntries; /* 这个优先级的就绪任务数 */
};
OS_EXT OS_RDY_LIST OSRdyList[OS_CFG_PRIO_MAX]; 用这个结构体声明一个数组,数组长度是我们定义的优先级总数。
OS_CFG_RPIO_MAX是我们定义的,如果为64,也就是说任务的优先级可以是0~63的一个,(对了63,不可以用,是给空任务的,其它的也会因为一些系统任务,我们用户用不了)
void OS_RdyListInsertTail (OS_TCB *p_tcb)
{
OS_RDY_LIST *p_rdy_list;
OS_TCB *p_tcb2;

p_rdy_list = &OSRdyList[p_tcb->Prio];
if (p_rdy_list->NbrEntries == (OS_OBJ_QTY)0) { /* CASE 0: Insert when there are no entries */
p_rdy_list->NbrEntries = (OS_OBJ_QTY)1; /* This is the first entry */
p_tcb->NextPtr = (OS_TCB *)0; /* No other OS_TCBs in the list */
p_tcb->PrevPtr = (OS_TCB *)0;
p_rdy_list->HeadPtr = p_tcb; /* Both list pointers point to this OS_TCB */
p_rdy_list->TailPtr = p_tcb;
} else { /* CASE 1: Insert AFTER the current tail of list */
p_rdy_list->NbrEntries++; /* One more OS_TCB in the list */
p_tcb->NextPtr = (OS_TCB *)0; /* Adjust new OS_TCBs links */
p_tcb2 = p_rdy_list->TailPtr;
p_tcb->PrevPtr = p_tcb2;
p_tcb2->NextPtr = p_tcb; /* Adjust old tail of list's links */
p_rdy_list->TailPtr = p_tcb;
}
}
这段代码挺简单的,就是两部分,一:这是我们建的这个优先级上的第一个任务,那么这个任务的NextPtr和PrevPtr都指向0,然后
p_rdy_list[p_tcb->Prio]->HeadPtr和p_rdy_list[p_tcb->Prio]->TailPtr都指向这个任务,
二:先找出p_tcb->Prio上任务的最后一个也就是p_rdy_list[p_tcb->Prio]->TailPtr指向的,然后这个任务的NextPtr指向我们新
建的任务,我们新建的任务的PrevPtr指向这个任务,然后p_rdy_list[p_tcb->Prio]->TailPtr指向我们新建的任务。

OS_RDY_LIST
+--------------+
| TailPtr |-----------------------------------------------+
+--------------+ OS_TCB OS_TCB | OS_TCB
| HeadPtr |------> +------------+ +------------+ +-> +------------+
+--------------+ | NextPtr |------>| NextPtr | ...... | NextPtr |->0
| NbrEntries=N | +------------+ +------------+ +------------+
+--------------+ 0<-| PrevPtr |<------| PrevPtr | ...... | PrevPtr |
+------------+ +------------+ +------------+
: : : : : :
: : : : : :
+------------+ +------------+ +------------+

OS_MsgQInit(&p_tcb->MsgQ,这个先不说了,
q_size);
*******************************************************************************************************/
/******************************************************************************************************
来说任务调度吧OSSched
先说在哪些地方用到这个这个函数了
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
OSTaskChangePrio
OSTaskCreate
OSTaskDel
OSTaskQPend
OSTaskQPendAbort
OSTaskResume
OSTaskSemPend
OSTaskSemPendAbort
OSTaskSuspend
OS_TaskQPost
OS_TaskSemPost
OSSchedUnlock
OSSchedRoundRobinYield
OSQDel
OSQPend
OSQPendAbort
OS_QPost
OSTimeDly
OSTimeDlyHMSM
OSTimeDlyResume
OSSemDel
OSSemPend
OSSemPendAbort
OS_SemPost
OSMutexDel
OSMutexPend
OSMutexPendAbort
OSMutexPost
OSPendMulti
OSFlagDel
OSFlagPend
OSFlagPendAbort
OS_FlagPost
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
以上好像很多,但可以这么分类,
每次建立新的任务,因为你建的这个任务可能优先级会更高,为了实时性,就必需这时进行一次调度
等待资源事件(ucos-ii都是用event来管理的,都叫事件)或资源事件的发布,或是删除,再加上中止等待事件。
还有就是使当前任务休息时也要调度一次。
中断之后也会调度,但不是用这个函数。好了,大至就这4类了。
现在可以看这个函数了
void OSSched (void)
{
CPU_SR_ALLOC();

if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* 中断处理函数中不能调度 */
return; /* Yes ... only schedule when no nested ISRs */
}

if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* 调度上锁之后也不能 */
return; /* Yes */
}

CPU_INT_DIS();
OSPrioHighRdy = OS_PrioGetHighest(); /* 得到最高优先级,一会说这个函数的执行 */
OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;
if (OSTCBHighRdyPtr == OSTCBCurPtr) { /* 也许还是当前优先级最高,那样就不用切换任务了 */
CPU_INT_EN(); /* Yes ... no need to context switch */
return;
}

#if OS_CFG_TASK_PROFILE_EN > 0u
OSTCBHighRdyPtr->CtxSwCtr++; /* Inc. # of context switches to this task */
#endif
OSTaskCtxSwCtr++; /* Increment context switch counter */

OS_TASK_SW(); /* 进行切换,这个也是我们根据硬件平台自己写的,一会说下 */
CPU_INT_EN();
}
*******************************************************************************************************/
/******************************************************************************************************
这时说下这个获得最高优先级的函数。
OS_PRIO OS_PrioGetHighest (void)
{
CPU_DATA *p_tbl;
OS_PRIO prio;

prio = (OS_PRIO)0;
p_tbl = &OSPrioTbl[0];
while (*p_tbl == (CPU_DATA)0) { /* Search the bitmap table for the highest priority */
prio += DEF_INT_CPU_NBR_BITS; /* DEF_INT_CPU_NBR_BITS正是OSPrioTbl[]的位长,也是说OSPrioTbl
能装多少了优先级*/
p_tbl++;
}
prio += (OS_PRIO)CPU_CntLeadZeros(*p_tbl); /* Find the position of the first bit set at the entry */
return (prio);
}
以前说过了就绪优先级的设置,都在OSPrioTbl[]中,如果你想找一个就绪的,优先级最高的一定要这里找。优先级的设置方法了,
所以我想应该都知道最高优先级在哪。先看OSPrioTbl[0],然后依次往下看,直到OSPrioTbl[OS_PRIO_TBL_SIZE]。
如果OSPrioTbl[0]不为0,就不用往下看了,
CPU_DATA CPU_CntLeadZeros (CPU_DATA val)
{
CPU_DATA nbr_lead_zeros;

#if (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_08)/*看咱单片机的字长,这回我就当咱的单片机字长是8位的*/
nbr_lead_zeros = CPU_CntLeadZeros08((CPU_INT08U)val);

#elif (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_16)
nbr_lead_zeros = CPU_CntLeadZeros16((CPU_INT16U)val);

#elif (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_32)
nbr_lead_zeros = CPU_CntLeadZeros32((CPU_INT32U)val);

#elif (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_64)
nbr_lead_zeros = CPU_CntLeadZeros64((CPU_INT64U)val);

#else /* See Note #1a. */
nbr_lead_zeros = DEF_INT_CPU_U_MAX_VAL;
#endif

return (nbr_lead_zeros);
}

CPU_DATA CPU_CntLeadZeros08 (CPU_INT08U val)/至于16,32的就不说了/
{
#if (!((defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) && \
(CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_08)))
CPU_DATA ix;
#endif
CPU_DATA nbr_lead_zeros;

/* ---------- ASM-OPTIMIZED ----------- */
#if ((defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) && \
(CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_08))
nbr_lead_zeros = CPU_CntLeadZeros((CPU_DATA)val);
nbr_lead_zeros -= (CPU_CFG_DATA_SIZE - CPU_WORD_SIZE_08) * DEF_OCTET_NBR_BITS;

#else /* ----------- C-OPTIMIZED ------------ */
/* Chk bits [07:00] : */
/* .. Nbr lead zeros = .. */
ix = (CPU_DATA)(val >> 0u); /* .. lookup tbl ix = 'val' >> 0 bits */
nbr_lead_zeros = (CPU_DATA)(CPU_CntLeadZerosTbl[ix] + 0u); /* .. plus nbr msb lead zeros = 0 bits.*/
#endif

return (nbr_lead_zeros);
}

static const CPU_INT08U CPU_CntLeadZerosTbl[256] = { /* Data vals : */
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
8u, 7u, 6u, 6u, 5u, 5u, 5u, 5u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, /* 0x00 to 0x0F */
3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, /* 0x10 to 0x1F */
2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, /* 0x20 to 0x2F */
2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, /* 0x30 to 0x3F */
1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, /* 0x40 to 0x4F */
1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, /* 0x50 to 0x5F */
1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, /* 0x60 to 0x6F */
1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, /* 0x70 to 0x7F */
0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /* 0x80 to 0x8F */
0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /* 0x90 to 0x9F */
0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /* 0xA0 to 0xAF */
0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /* 0xB0 to 0xBF */
0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /* 0xC0 to 0xCF */
0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /* 0xD0 to 0xDF */
0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /* 0xE0 to 0xEF */
0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u /* 0xF0 to 0xFF */
}

这个不难,看下程序不难理解,这个表也不难理解,我来用三个优先级举例(先假设只有我们这个三个优先级的任务,别想什么
空任务和统计任务等)10,12,20。用上一节的内容
对于10来说
ix=1,余数是2
对于12来说
ix=1,余数是4
对于20来说
ix=2,余数是4
OSPrioTbl[1]
10 12
_ _
|0|0|1|0|1|0|0|0|

OSPrioTbl[2]
20
_
|0|0|0|0|1|0|0|0|
图画的还算明白吧?就这么看吧,
首先因为OSPrioTbl[0]为0,Prio=Prio+8看OSPrioTbl[1]=40,好了不向下查了,调用这个函数CPU_CntLeadZeros
并且传入的参数是40,假设我们单片机是8位的调用CPU_CntLeadZeros08,同时这个40也会被传过来nbr_lead_zeros=2,
这时Prio再加2,就得10了。还有这个表是统计出来的,看下10,和12的例子大家应该能懂,要是有什么不懂可以问一下(邮箱是suntie@live.cn)

OSPrioCur 这个值是当前正在工作的任务
OSPrioHighRdy 这个值是当前最高的优先级值
OSTCBHighRdyPtr这个指向当前最高优先级任务的任务块
OSTCBCurPtr 这个指向当前正在工作的任务
还有如果OSTCBCurPtr和OSTCBHighRdyPtr不一样,那么就会导致任务的切换。

*******************************************************************************************************/
/******************************************************************************************************
OS_TASK_SW
在这里我们要做的事是
OSPrioCur=OSPrioHighRdy
将当前的任务的内容保存入栈
OSTCBCurPtr=OSTCBHighRdyPt
将最高优先级任务的内容出栈
好了,os_task.c中大部分都和一些事件处理有关,还有一些没关的,但比较简单,就不说了。
下回说时钟节拍。
*******************************************************************************************************/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  实时操作系统