uC/OS-II定義了兩個系統任務,空閒任務與統計任務。
空閒任務OSTaskIdle()是μC/OS-Ⅱ必不可少的系統函數,當沒有其它任務進入就緒態時,該任務立即轉入運行態。空閒任務的優先級永遠設爲最低,即
OS_LOWEST_PRIO
,永遠不被掛起,也不能被刪除。空閒任務什麼都不做,只是在不停地給一個32位計數器
OSIdleCtr
加1,統計任務使用這個計數器以確定當前應用程序實際消耗的CPU時間。計數器是一個全局變量,大多數8位或16位CPU對32位變量加1需要多條指令,所以在訪問前必須先關中斷,然後再開啓,以防高優先級任務或中斷打入。
void OS_TaskIdle (void *p_arg)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0;
#endif
(void)p_arg; /* Prevent compiler warning for not using 'p_arg' */
for (;;) {
OS_ENTER_CRITICAL();
OSIdleCtr++;
OS_EXIT_CRITICAL();
OSTaskIdleHook(); /* Call user definable HOOK */
}
}
- 統計任務
OSTaskStat()
也是μC/OS-Ⅱ的系統函數之一,其功能是計算當前CPU的利用率,告訴用戶應用程序使用了多少CPU時間。一旦將文件OS_CFG.H
中的配置常數OS_ TASK_STAT_EN
置1,這個任務就自動建立。它每秒鐘運行一次,計算結果放在一個有符號的8位整數OSCPUsage
中,表示格式是百分數,精確到1%。
void OS_TaskStat (void *p_arg)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0;
#endif
(void)p_arg; /* Prevent compiler warning for not using 'p_arg' */
while (OSStatRdy == OS_FALSE) {
OSTimeDly(2 * OS_TICKS_PER_SEC / 10); /* Wait until statistic task is ready */
}
OSIdleCtrMax /= 100L;
if (OSIdleCtrMax == 0L) {
OSCPUUsage = 0;
(void)OSTaskSuspend(OS_PRIO_SELF);
}
for (;;) {
OS_ENTER_CRITICAL();
OSIdleCtrRun = OSIdleCtr; /* Obtain the of the idle counter for the past second */
OSIdleCtr = 0L; /* Reset the idle counter for the next second */
OS_EXIT_CRITICAL();
OSCPUUsage = (INT8U)(100L - OSIdleCtrRun / OSIdleCtrMax);
OSTaskStatHook(); /* Invoke user definable hook */
#if (OS_TASK_STAT_STK_CHK_EN > 0) && (OS_TASK_CREATE_EXT_EN > 0)
OS_TaskStatStkChk(); /* Check the stacks for each task */
#endif
OSTimeDly(OS_TICKS_PER_SEC / 10); /* Accumulate OSIdleCtr for the next 1/10 second */
}
}
- 下面重點分析一下如何計算CPU利用率。
使用統計任務時,初始化時只能建立唯一的一個任務,其它任務的建立只能在多任務啓動後建立。值得注意的是:時鐘節拍的初始化和啓動工作也可以放在OSStart()函數中完成。一般不要在多任務啓動之前啓動時鐘節拍器,因爲這樣做可能導致任務開始前應用程序就收到時鐘節拍中斷,以至系統崩潰。
void main (void)
{
OSInit(); /*初始化ucosii */
OSTaskCreate(TaskStart,(void *)0,
&startup_task_stk[STARTUP_TASK_STK_SIZE-1], STARTUP_TASK_PRIO);/*創建唯一任務 */
OSStart();
}
void TaskStart(void *p_arg)
{
SysTick_init();/*安裝並啓動始終節拍 */
OSStatInit(); /*調用系統函數,初始化統計任務 */
while(1)
{
/*TaskStart代碼 */
}
}
- 統計任務的使用方法是:首先用戶在初始化時建立一個也只能是一個任務,其次在這個唯一的任務中調用
OSStatInit()
函數。
void OSStatInit (void)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0;
#endif
OSTimeDly(2); /* Synchronize with clock tick */
OS_ENTER_CRITICAL();
OSIdleCtr = 0L; /* Clear idle counter */
OS_EXIT_CRITICAL();
OSTimeDly(OS_TICKS_PER_SEC / 10); /* Determine MAX. idle counter value for 1/10 second */
OS_ENTER_CRITICAL();
OSIdleCtrMax = OSIdleCtr; /* Store maximum idle counter count in 1/10 second */
OSStatRdy = OS_TRUE;
OS_EXIT_CRITICAL();
}
進入多任務的條件準備好了以後,調用系統啓動函數
OSStart()
。這個函數將使TaskStart()
開始執行,因爲TaskStart()
是優先級最高的任務。TaskStart()
負責初始化和啓動時鐘節拍。在這裏啓動時鐘節拍是必要的,因爲用戶不會希望在多任務還沒有開始時就接收到時鐘節拍中斷。接下去TaskStart()
調用統計初始化函數OSStatInit()
。
統計初始化函數OSStatInit()
決定在沒有其它應用任務運行時,空閒計數器OSIdleCtr
的計數有多快。這裏取0.1秒(OS_TICKS_PER_SEC / 10
)內OSIdleCtr的計數值OSIdleCtrMax
爲計算CPU利用率的基準。- 系統統計初始化任務函數
OSStatInit()
調用延遲函數OSTimeDly(2)
將自身延時2個時鐘節拍以停止自身的運行。這是爲了使OSStatInit()
與時鐘節拍同步。 - μC/OS-Ⅱ然後選下一個優先級最高的進入就緒態的任務運行,這恰好是統計任務
OSTaskStat()
。OSTaskStat()
所要做的第一件事就是查看統計任務就緒標誌是否爲“假”,如果是的話,要延時0.2秒(2 * OS_TICKS_PER_SEC / 10
)。一定會是這樣,因爲標誌OSStatRdy
已被OSInit()
函數初始化爲“假”,所以實際上OSTaskStat
也將自己推入休眠態0.2秒。 - 於是任務切換到空閒任務,
OSTaskIdle()
開始運行,這是唯一一個就緒態任務了。CPU處在空閒任務OSTaskIdle
中,直到TaskStart()
的延遲兩個時鐘節拍完成。 - 兩個時鐘節拍之後,
TaskStart()
恢復運行。 在執行OSStartInit()
時,空閒計數器OSIdleCtr被清零。然後,OSStatInit()
將自身延時0.1秒。 - 因爲沒有其它進入就緒態的任務,
OSTaskIdle()
又獲得了CPU的控制權。0.1秒鐘以後,TaskStart()
繼續運行,還是在OSStatInit()
中,空閒計數器將0.1秒鐘內計數的值存入空閒計數器最大值OSIdleCtrMax
。 OSStarInit()
將統計任務就緒標誌OSStatRdy
設爲“真”,以此來允許OSTaskStat()
開始計算CPU的利用率。
- 系統統計初始化任務函數
統計任務每0.1秒執行一次,以確定所有應用程序中的任務消耗了多少CPU時間。當用戶的應用程序代碼加入以後,運行空閒任務的CPU時間就少了,
OSIdleCtr
就不會像原來什麼任務都不運行時有那麼多計數。要知道,OSIdleCtr
的最大計數值是OSStatInit()
在初始化時保存在計數器最大值OSIdleCtrMax
中的。CPU利用率是保存在變量OSCPUsage中的,根據公式計算OSIdleCtr=OSIdleCtrMax
時CPU利用率最低爲0,OSIdleCtr=0
時CPU利用率最高爲100%。
===========以上爲統計任務的分析===============關於統計任務運行頻率的補充
統計任務執行到最後時是OSTimeDly(OS_TICKS_PER_SEC/10);
這樣一個函數。表示延遲一分鐘。而只有統計任務延時時空閒任務纔有可能運行,所以每當統計任務運行時OSIdleCtr的值都是在可能的1s內記的數。因爲在統計任務在賦完值之後清零了。所以說,統計任務不是1s運行一次,只不過統計任務運行時用到的變量都是在1s內的數據。
參考:http://gha20028.blog.163.com/blog/static/13481666201363021616344/