OS_CORE.C(8)
本篇介紹的是OSStart()函數和OSStatInit()函數和OSTimeTick()函數。
OSStart()多任務開始函數:
/*$PAGE*/ /* ********************************************************************************************************* * START MULTITASKING * 啟動多個任務 * Description: This function is used to start the multitasking process which lets uC/OS-II manages the * task that you have created. Before you can call OSStart(), you MUST have called OSInit() * and you MUST have created at least one task. * 該功能用來開始多任務進程,使UC/OS-II管理你所創建的任務。在調用OSStart()之前必須先調用OSInit()并且必須創建至少一個任務 * Arguments : none * * Returns : none * * Note : OSStartHighRdy() MUST: * a) Call OSTaskSwHook() then,調用OSStartHighRdy()之后就調用OSTaskSwHook()函數 * b) Set OSRunning to OS_TRUE.將OSRunning設置為真,指出多任務已經開始 * c) Load the context of the task pointed to by OSTCBHighRdy.加載高優先級就緒任務啟動函數中指出的任務的上下文 * d_ Execute the task.執行任務 ********************************************************************************************************* */void OSStart(void) /*啟動多個任務*/ {if (OSRunning == OS_FALSE) { /*此時沒有多任務*/OS_SchedNew(); /* Find highest priority's task priority number 找到最高優先級的任務優先級號 */OSPrioCur = OSPrioHighRdy; /*將最高優先級任務的優先級號作為當前要執行任務的優先級號*/OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; /* Point to highest priority task ready to run 指向將要運行的最高優先級任務 */OSTCBCur = OSTCBHighRdy; /*將高優先級任務的TCB作為當前TCB*/OSStartHighRdy(); /* Execute target specific code to start task執行代碼開始任務 */} } 將上述代碼總結為如圖所示流程:
OSStatInit()統計任務初始化函數:
/*$PAGE*/ /* ********************************************************************************************************* * STATISTICS INITIALIZATION * 統計任務初始化 * Description: This function is called by your application to establish CPU usage by first determining * how high a 32-bit counter would count to in 1 second if no other tasks were to execute * during that time. CPU usage is then determined by a low priority task which keeps track * of this 32-bit counter every second but this time, with other tasks running. CPU usage is * determined by: * 統計初始化函數OSStatInit()決定在沒有其它應用任務運行時,空閑計數器(OSIdleCtr)的計數有多快。這個任務每秒執行一次,以確定所有應用程序中的任務消耗了多少CPU時間。當用戶的應用程序代碼加入以后,運行空閑任務的CPU時間就少了,OSIdleCtr就不會像原來什么任務都不運行時有那么多計數。要知道,OSIdleCtr的最大計數值是OSStatInit()在初始化時保存在計數器最大值OSIdleCtrMax中的。 * OSIdleCtr * CPU Usage (%) = 100 * (1 - ------------) * OSIdleCtrMaxCPU使用率(百分比形式)=100*(1-空閑計數值/設定最大空閑計數值) * * Arguments : none * * Returns : none ********************************************************************************************************* */#if OS_TASK_STAT_EN > 0u void OSStatInit(void) /*統計任務初始化*/ { #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register 中斷函數被設定為模式3 */OS_CPU_SR cpu_sr = 0u; #endifOSTimeDly(2u); /* Synchronize with clock tick調用延遲函數OSTimeDly()將自身延時2個時鐘節拍以停止自身的運行,這是為了使OSStatInit()與時鐘節拍同步 */OS_ENTER_CRITICAL(); /*關閉中斷(進入中斷)*/OSIdleCtr = 0uL; /* Clear idle counter 執行OSStartInit()時,空閑計數器OSIdleCtr被清零*/OS_EXIT_CRITICAL(); /*打開中斷*/OSTimeDly(OS_TICKS_PER_SEC / 10u); /* Determine MAX. idle counter value for 1/10 second確定最大空閑計數值為1或10s */OS_ENTER_CRITICAL(); /*關閉中斷*/OSIdleCtrMax = OSIdleCtr; /* Store maximum idle counter count in 1/10 second 存儲最大空閑計數值 */OSStatRdy = OS_TRUE; /*將統計任務就緒標志OSStatRdy設為"真",以此來允許兩個時鐘節拍以后OSTaskStat()開始計算CPU的利用率*/OS_EXIT_CRITICAL(); /*打開中斷*/ } #endif OSTimeTick()時鐘節拍函數:/*$PAGE*/ /*2018/2/3~2/7 ********************************************************************************************************* * PROCESS SYSTEM TICK * 時鐘節拍函數 * Description: This function is used to signal to uC/OS-II the occurrence of a 'system tick' (also known * as a 'clock tick'). This function should be called by the ticker ISR but, can also be * called by a high priority task. *該功能是用來給uc/os發送時鐘信號。該功能稱為時鐘中斷,也叫做高優先級任務 * Arguments : none * * Returns : none ********************************************************************************************************* */void OSTimeTick(void) /*時鐘節拍函數*/ {OS_TCB *ptcb; /*指向TCB列表的的指針*/ #if OS_TICK_STEP_EN > 0uBOOLEAN step; /*設置一個布爾型變量*/ #endif #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register中斷函數被設定為模式3 */OS_CPU_SR cpu_sr = 0u; #endif#if OS_TIME_TICK_HOOK_EN > 0u /*可以生成時鐘鉤子函數OS_TIME_TICK_HOOK()*/OSTimeTickHook(); /* Call user definable hook 調用用戶自定義鉤子函數 */ #endif #if OS_TIME_GET_SET_EN > 0u /*可以生成OS_TIME_GET_SET()函數*/OS_ENTER_CRITICAL(); /* Update the 32-bit tick counter 更新32位節拍數,關中斷 */OSTime++; /*/累加從開機以來的時間,用的是一個無符號32位變量*/OS_EXIT_CRITICAL(); /*開中斷*/ #endifif (OSRunning == OS_TRUE) { #if OS_TICK_STEP_EN > 0uswitch (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 ...步進等待狀態:等待uC/OS-View將步進狀態設置成進一步*/step = OS_FALSE; break;case OS_TICK_STEP_ONCE: /* Yes, process tick once and wait for next ...步進一次等待下一步命令 */step = OS_TRUE; /*... step command from uC/OS-View步進命令來自于uc/os-view*/OSTickStepState = OS_TICK_STEP_WAIT; /*將步進狀態設置為步進等待狀態*/break;default: /* Invalid case, correct situatio無效的情況或者正確的情況下*/step = OS_TRUE; OSTickStepState = OS_TICK_STEP_DIS; /*將步進狀態設置為禁止狀態*/break;}if (step == OS_FALSE) { /* Return if waiting for step command如果正在等待步進命令,返回*/return;} #endifptcb = OSTCBList; /* Point at first TCB in TCB list 指向TCB列表的第一個*/while (ptcb->OSTCBPrio != OS_TASK_IDLE_PRIO) { /* Go through all TCBs in TCB list 瀏覽TCB列表的所有TCB*/OS_ENTER_CRITICAL(); /*進入中斷*/if (ptcb->OSTCBDly != 0u) { /* No, Delayed or waiting for event with TO等待任務時的最多節拍數不為0*/ptcb->OSTCBDly--; /* Decrement nbr of ticks to end of delay時間延遲項減1*/if (ptcb->OSTCBDly == 0u) { /* Check for timeout減1后檢查是否到時間了。時間延遲項等于0,就轉為就緒態(外部條件準備就緒)*/if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) { /*(檢查內部條件是否準備就緒)如果TCB狀態和掛起狀態進行位與運算之后不等于準備好的狀態,簡單來說就是任務沒有準備好*/ptcb->OSTCBStat &= (INT8U)~(INT8U)OS_STAT_PEND_ANY; /* Yes, Clear status flag清除狀態標志*/ptcb->OSTCBStatPend = OS_STAT_PEND_TO; /* Indicate PEND timeout將TCB掛起狀態設置為超時狀態*/}else { /*如果是已準備好的狀態(內部條件準備就緒)*/ptcb->OSTCBStatPend = OS_STAT_PEND_OK;/*就將TCB掛起狀態設置為掛起結束(正常結束)狀態*/}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指向TCB列表的下一個 */OS_EXIT_CRITICAL(); /*退出中斷(開中斷)*/}} } 同時介紹一下相關的時間管理方面的內容:http://blog.csdn.net/adam_embedded/article/details/46323491
1.1 時鐘節拍
UCOSii通過時鐘節拍OSTimeTick()來定期進行任務調度,一般來說這個頻率是10-100HZ,頻率越高,系統的開銷也就越大。
1.2 任務延時函數
OSTimeDly()
任務可以調用OSTimeDly()來對自身延時一段時間。延時時,任務被掛起。任務被延時的時間必須是時鐘節拍的倍數。與延時有關的變量在Tcb結構體中。
Tcb.OSTCBDly表示任務自己延時掛起的時間。
這樣,當任務調用OSTimeDly()來進行延時時,該函數會修改修改OSTCBDly的值,把要延時的次數寫入該變量,最后進行任務調度即可。
每次時鐘節拍發生的時候,OSTCBDly的值都會被減去一,當該值為0的時候,內核就會把它放入就緒隊列。
NOTE: 當調用OSTimeDly(1)只延時一個時鐘節拍的時候,由于任務可能運行在一個時鐘節拍的中后期,此時經過不到半個時鐘節拍的時間,OSTCBDly的值就會被修改。因此,如果用戶的應用程序至少得延時一個節拍,必須要調用 OSTimeDly(2),指定延時兩個節拍。(即指定延時1,延時可能不足1,但是指定延時為2,至少可以保證延時一個節拍)。
來看一下OSTimeDly()的結構和原型:
結構:
void OSTimeDly(OS_TICK dly,//指定延時的長度,單位為時間節拍OS_OPT opt,//延時模式OS_ERR *p_err//錯誤信息 )
- 如果延時時間dly>0,則會發生任務調度;0表示不延時
- OSTimeDly()函數延時模式有四種:OS_OPT_TIME_DLY;OS_OPT_TIME_TIMEOUT;OS_OPT_TIME_PERIODIC;OS_OPT_TIME_MATCH;
void OSTimeDly (INT16U ticks) {if (ticks > 0) {OS_ENTER_CRITICAL();if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) {OSRdyGrp &= ~OSTCBCur->OSTCBBitY;} OSTCBCur->OSTCBDly = ticks;OS_EXIT_CRITICAL();OSSched();} }
可以看到該函數將延時次數傳遞給了OSTCBDly。
OSTimeDly()有一些缺點:一是只能延時65535次時鐘節拍,二是不能換算成時間。
1.3 結束任務延時函數
OSTimeDlyResume()函數可以被用來強制某一任務結束延時,它的主要作用是支持任務之間的通訊和同步。
OSTimeDlyResume()要做的就是將OSTCBDly清0,然后進行任務調度。
1.4 系統時間
每次發生時鐘節拍時,UCOS都會將一個32位的計數器加1。
OSTimeGet()和 OSTimeSet()用來獲取或者設置這個計數器的值。
總結
以上是生活随笔為你收集整理的OS_CORE.C(8)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OS_CORE.C(7)
- 下一篇: OS_CORE.C(9)