ucos-iii任务

这回说下任务建立,那么我们看下任务控制块有哪些内容:
(这系统越来越大,任务控制块的内容也是越来越多了,呵呵)
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[n]能装多少了优先级*/
        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的例子大家应该能懂,要是有什么不懂可以问一下(邮箱是[email protected]

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

*******************************************************************************************************/
/******************************************************************************************************
OS_TASK_SW
在这里我们要做的事是
OSPrioCur=OSPrioHighRdy
将当前的任务的内容保存入栈
OSTCBCurPtr=OSTCBHighRdyPt
将最高优先级任务的内容出栈
好了,os_task.c中大部分都和一些事件处理有关,还有一些没关的,但比较简单,就不说了。
下回说时钟节拍。

*******************************************************************************************************/ 

你可能感兴趣的:(实时操作系统)