常見任務格式函數
//每一個任務都有一個掛起,能夠進行任務切換 void Task_LED(void *arg) { (void)arg; // 'arg' 並無用到,防止編譯器提示警告 while (1) { //用戶實現功能代碼 OSTimeDlyHMSM(0, 0,0,1000); //任務掛起 實現任務切換 } }
// 延時時間計算 調用延時函數 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); }
// 延時函數 將本任務從就緒列表中清除,讓後調用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(); /* 系統調度 */ }
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();
//這裏主要是爲了產生 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(); }