從零開始學習UCOSII操作系統5--時間管理
1、UCOSII的定時中斷
(1)絕大多數的內核要求提供定時中斷,以實現延時與超時控制等功能。這個定時中斷叫做時鐘節拍。
(2)時鐘的中斷子程序ISR和時鐘節拍函數OSTimeTick()該函數用於通知UCOSII,發生了時鐘的節拍中斷。
2、UCOSII的5個關鍵的時鐘函數
(1)OSTimeDly();
後面的4個函數可以根據需要進行配置使用
(2)OSTimeHMSM();
(3)OSTimeDlyResume();
(4)OSTimeGet();
(5)OSTimeSet();
3、關鍵的時鐘延時函數的實現OSTimeDly()
(1)參數分析:
ticks:代表的是多少個時鐘週期節拍
(2)實現過程:
把相應任務的就緒表中的位圖的位置清零。
把需要執行的等待節拍進行處理。
最後進行任務調度,尋找下一個這個時刻最高優先級的任務。
(3)發出疑問?爲什麼我在OS_TCB的結構體當中的Ticks填寫相應的數字的時候可以實現把任務從就緒態變爲等待的狀態?
答案OSTimeTick()這個函數
void OSTimeDly (INT32U ticks)
{
INT8U y;
#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
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();
y = OSTCBCur->OSTCBY; /* Delay current task */
OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;
if (OSRdyTbl[y] == 0u) {
OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;
}
OSTCBCur->OSTCBDly = ticks; /* Load ticks in TCB */
OS_EXIT_CRITICAL();
OS_Sched(); /* Find next task to run! */
}
}
實現任務等待時間的關鍵的函數:
PS:我以後都會把對理解無關緊要的代碼刪除。
(1)當任務是處於運行的狀態的時候。判斷OS現在處於的是什麼樣的狀態。
(2)所有的任務都是通過任務的鏈表鏈接到一起的,我們後面的一個while循環就是,從開始不斷的遍歷到最後的任務,也就是空閒任務。
(3)對延時的時間不斷的減1,當延時的dlyTick減少到0的時候,對OS_TCB任務控制塊的一些狀態進行修改,並且重新的把任務添加回就緒表中。
PS:這個函數應該是放置到中斷服務函數中的,整個時間片的不斷的觸發執行的。
void OSTimeTick (void)
{
OS_TCB *ptcb;
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; /* Yes, Clear status flag */
ptcb->OSTCBStatPend = OS_STAT_PEND_TO; /* Indicate PEND timeout */
} else {
ptcb->OSTCBStatPend = OS_STAT_PEND_OK;
}
if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) { /* Is task suspended? */
OSRdyGrp |= ptcb->OSTCBBitY; /* No, Make ready */
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
}
}
}
ptcb = ptcb->OSTCBNext; /* Point at next TCB in TCB list */
OS_EXIT_CRITICAL();
}
}
}
OSTimeDlyHmSM
INT8U OSTimeDlyHMSM (INT8U hours, INT8U minutes, INT8U seconds, INT16U milli)
由於OSTimeDlyHMSM()的具體實現方法,用戶不能結束延時調用OSTimeDlyHMSM()要求延時超過65535個節拍的任務。換句話說,如果時鐘節拍的頻率是100Hz,用戶不能讓調用OSTimeDlyHMSM(0,10,55,350)或更長延遲時間的任務結束延時。
4、恢復延時的任務:OSTimeDlyResume()
裏面關鍵的操作就是把那個全局的時間計數器變量設置爲0
INT8U OSTimeDlyResume (INT8U prio)
{
OS_TCB *ptcb;
if (prio >= OS_LOWEST_PRIO) {
return (OS_ERR_PRIO_INVALID);
}
OS_ENTER_CRITICAL();
ptcb = OSTCBPrioTbl[prio]; /* Make sure that task exist */
if (ptcb == (OS_TCB *)0) {
OS_EXIT_CRITICAL();
return (OS_ERR_TASK_NOT_EXIST); /* The task does not exist */
}
if (ptcb == OS_TCB_RESERVED) {
OS_EXIT_CRITICAL();
return (OS_ERR_TASK_NOT_EXIST); /* The task does not exist */
}
if (ptcb->OSTCBDly == 0u) { /* See if task is delayed */
OS_EXIT_CRITICAL();
return (OS_ERR_TIME_NOT_DLY); /* Indicate that task was not delayed */
}
ptcb->OSTCBDly = 0u; /* 清除任務計數器 */
if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) {
ptcb->OSTCBStat &= ~OS_STAT_PEND_ANY; /* Yes, Clear status flag */
ptcb->OSTCBStatPend = OS_STAT_PEND_TO; /* Indicate PEND timeout */
} else {
ptcb->OSTCBStatPend = OS_STAT_PEND_OK;
}
if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) { /* Is task suspended? */
OSRdyGrp |= ptcb->OSTCBBitY; /* No, Make ready */
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
OS_EXIT_CRITICAL();
OS_Sched(); /* See if this is new highest priority */
} else {
OS_EXIT_CRITICAL(); /* Task may be suspended */
}
return (OS_ERR_NONE);
}