ucos 之任務切換 源碼分析 4

常見任務格式函數

//每一個任務都有一個掛起,能夠進行任務切換
void Task_LED(void *arg)
{
    (void)arg;                		// 'arg' 並無用到,防止編譯器提示警告
    while (1)
    {
        //用戶實現功能代碼
        OSTimeDlyHMSM(0, 0,0,1000);  //任務掛起 實現任務切換
    }
}


OSTimeDlyHMSM 時間延時 計數計算函數

//  延時時間計算  調用延時函數
INT8U  OSTimeDlyHMSM (INT8U   hours,     //小時
                      INT8U   minutes,   //分鐘
                      INT8U   seconds,   //秒
                      INT16U  ms)        //毫秒
{
    INT32U ticks;


    if (OSIntNesting > 0u) {          /* 是否在中斷See if trying to call from an ISR     */
            return (OS_ERR_TIME_DLY_ISR);
    }
    if (OSLockNesting > 0u) {       /* 查看是否調度被鎖See if called with scheduler locked    */
        return (OS_ERR_SCHED_LOCKED);
    }
    #if OS_ARG_CHK_EN > 0u  
    if (hours == 0u) {           //延時時間是否0
        if (minutes == 0u) {
            if (seconds == 0u) {
                if (ms == 0u) {
                    return (OS_ERR_TIME_ZERO_DLY);
                }
            }
        }
    }
    if (minutes > 59u) {       
        return (OS_ERR_TIME_INVALID_MINUTES);    /* 判斷時間範圍是否正確      */
    }
    if (seconds > 59u) {
        return (OS_ERR_TIME_INVALID_SECONDS);
    }
    if (ms > 999u) {
        return (OS_ERR_TIME_INVALID_MS);
    }
    #endif
    //計算 延時的ms數       
    ticks = ((INT32U)hours * 3600uL + (INT32U)minutes * 60uL + (INT32U)seconds) * OS_TICKS_PER_SEC
          + OS_TICKS_PER_SEC * ((INT32U)ms + 500uL / OS_TICKS_PER_SEC) / 1000uL;
	//上面多了0.5ms爲任務調度須要的時間
    OSTimeDly(ticks);  //延時函數
    return (OS_ERR_NONE);
}

OSTimeDly()時間延時函數

// 延時函數 將本任務從就緒列表中清除,讓後調用OS_Sched()從就緒表中找到最高級任務運行
void  OSTimeDly (INT32U ticks)
{
    INT8U      y;
#if OS_CRITICAL_METHOD == 3u    /*    中斷模式3        */
    OS_CPU_SR  cpu_sr = 0u;
#endif



    if (OSIntNesting > 0u) {       /* See if trying to call from an ISR 是否嵌套中斷    */
        return;
    }
    if (OSLockNesting > 0u) {        /* See if called with scheduler locked 是否調度鎖     */
        return;
    }
    if (ticks > 0u) {                            /* 0 means no delay!              */
        OS_ENTER_CRITICAL();
	//把OSRdyTbl清零
        y            =  OSTCBCur->OSTCBY;  
        OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;
	//把OSRdyGrp清零:即去掉當前任務放到準備任務中
        if (OSRdyTbl[y] == 0u) {
            OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;
        }
	
        OSTCBCur->OSTCBDly = ticks;     /* Load ticks in TCB          */
        OS_EXIT_CRITICAL();
        OS_Sched();                 /* 系統調度   */
    }


OS_Sched()任務調度函數

void  OS_Sched (void)
{
    #if OS_CRITICAL_METHOD == 3u        
        OS_CPU_SR  cpu_sr = 0u;
    #endif


    OS_ENTER_CRITICAL();
    if (OSIntNesting == 0u) {        //是否中斷嵌套  調度鎖 
        if (OSLockNesting == 0u) {    
            OS_SchedNew();  //找到最高級優先級 詳解見  http://my.oschina.net/u/274829/blog/263287
            OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
            if (OSPrioHighRdy != OSPrioCur) {     /* 最高級任務 不是當前任務   */
    #if OS_TASK_PROFILE_EN > 0u
                OSTCBHighRdy->OSTCBCtxSwCtr++;    /* 當前任務調度次數  */
    #endif
                OSCtxSwCtr++;                /*任務切換次數 Increment context switch counter      */
                OS_TASK_SW();                /* 任務切換                    */
            }
        }
    }
    OS_EXIT_CRITICAL();

OSCtxSw 任務切換 彙編代碼

//這裏主要是爲了產生 PendSV中斷  任務切換在 PendSV_Handler 中進行切換
OSCtxSw
	PUSH    {R4, R5}                ;將R4,R5入棧
        LDR     R4, =NVIC_INT_CTRL  	;觸發PendSV異常 (causes context switch)
        LDR     R5, =NVIC_PENDSVSET
        STR     R5, [R4]  ;產生軟中斷
	POP     {R4, R5}
        BX      LR  ;跳到原地址

 任務切換詳細過程PendSV_Handler http://my.oschina.net/u/274829/blog/266098  spa

時間切換 .net

void  OSTimeTick (void)
{
    OS_TCB    *ptcb;
#if OS_TICK_STEP_EN > 0u
    BOOLEAN    step;
#endif
#if OS_CRITICAL_METHOD == 3u        /* Allocate storage for CPU status register     */
    OS_CPU_SR  cpu_sr = 0u;
#endif


#if OS_TIME_TICK_HOOK_EN > 0u
    OSTimeTickHook();                      /* Call user definable hook                     */
#endif
#if OS_TIME_GET_SET_EN > 0u
    OS_ENTER_CRITICAL();                  
    OSTime++;               //系統時間增長
    OS_EXIT_CRITICAL();
#endif
    if (OSRunning == OS_TRUE) {
#if OS_TICK_STEP_EN > 0u
        switch (OSTickStepState) {      /* Determine whether we need to process a tick  */
            case OS_TICK_STEP_DIS:         /* Yes, stepping is disabled       */
                 step = OS_TRUE;
                 break;

            case OS_TICK_STEP_WAIT:         /* No,  waiting for uC/OS-View to set ...       */
                 step = OS_FALSE;           /*      .. OSTickStepState to OS_TICK_STEP_ONCE */
                 break;

            case OS_TICK_STEP_ONCE:       /* Yes, process tick once and wait for next ... */
                 step            = OS_TRUE;    /*      ... step command from uC/OS-View  */
                 OSTickStepState = OS_TICK_STEP_WAIT;
                 break;

            default:                       /* Invalid case, correct situation              */
                 step            = OS_TRUE;
                 OSTickStepState = OS_TICK_STEP_DIS;
                 break;
        }
        if (step == OS_FALSE) {           /* Return if waiting for step command           */
            return;
        }
#endif
        ptcb = OSTCBList;                   /* Point at first TCB in TCB list               */
        while (ptcb->OSTCBPrio != OS_TASK_IDLE_PRIO) {  /* Go through all TCBs in TCB list  */
            OS_ENTER_CRITICAL();
            if (ptcb->OSTCBDly != 0u) {       /* No, Delayed or waiting for event with TO  */
                ptcb->OSTCBDly--;             /* Decrement nbr of ticks to end of delay  */
                if (ptcb->OSTCBDly == 0u) {       /* Check for timeout       */

                    if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) {
                        ptcb->OSTCBStat  &= (INT8U)~(INT8U)OS_STAT_PEND_ANY;  //清除事件標誌    
                        ptcb->OSTCBStatPend = OS_STAT_PEND_TO;    /*時間超時 標誌  */
                    } else {
                        ptcb->OSTCBStatPend = OS_STAT_PEND_OK;
                    }

                    if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) {  /*準備好了  */
                        OSRdyGrp               |= ptcb->OSTCBBitY;      //加到就緒隊列
                        OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
                    }
                }
            }
            ptcb = ptcb->OSTCBNext;                        /* Point at next TCB in TCB list                */
            OS_EXIT_CRITICAL();
        }
    }
}

時鐘源  硬件時間中斷提供code

void  OSTickHandler (void)
{
#if OS_CRITICAL_METHOD == 3
    OS_CPU_SR cpu_sr;
#endif 

    OS_ENTER_CRITICAL();                         
    OSIntNesting++;
    OS_EXIT_CRITICAL();

    OSTimeTick();         /*  uC/OS-II's OSTimeTick()*/

    OSIntExit();                                 
}
相關文章
相關標籤/搜索