OS_CORE.C(11)
OS_SchedNew(void)找到將要運行的最高優(yōu)先級任務函數(shù)
和任務調(diào)度函數(shù)OS_Sched(void):
/* ********************************************************************************************************* * FIND HIGHEST PRIORITY TASK READY TO RUN * 找到將要運行的最高優(yōu)先級任務 * Description: This function is called by other uC/OS-II services to determine the highest priority task * that is ready to run. The global variable 'OSPrioHighRdy' is changed accordingly. *描述: 該功能被其他服務調(diào)用,用來決定將要運行的最高優(yōu)先級任務是什么。全局變量OSPrioHighRdy相應改變。 * Arguments : none *參數(shù):無 * Returns : none *返回值:無 * Notes : 1) This function is INTERNAL to uC/OS-II and your application should not call it. * 2) Interrupts are assumed to be disabled when this function is called.注釋: 1)該功能是內(nèi)部函數(shù),你的應用程序不能調(diào)用。2)當這個功能被調(diào)用的時候不能被中斷(原子函數(shù)) ********************************************************************************************************* */static void OS_SchedNew(void) /*找到將要被調(diào)度的任務*/ { #if OS_LOWEST_PRIO <= 63u /*優(yōu)先級<=63,支持64位任務*/INT8U y;y = OSUnMapTbl[OSRdyGrp]; OSPrioHighRdy = (INT8U)((y << 3u) + OSUnMapTbl[OSRdyTbl[y]]);/*計算最高優(yōu)先級任務的優(yōu)先級*/ #else /* We support up to 256 tasks支持256個任務 */INT8U y;OS_PRIO *ptbl; /*ptb1是指向事件控制塊的指針*/if ((OSRdyGrp & 0xFFu) != 0u) /*如果就緒組不為0*/{ y = OSUnMapTbl[OSRdyGrp & 0xFFu]; /*y為在表中查到的數(shù)*/}else {y = OSUnMapTbl[(OS_PRIO)(OSRdyGrp >> 8u) & 0xFFu] + 8u;/*將y置為8*/}ptbl = &OSRdyTbl[y];if ((*ptbl & 0xFFu) != 0u) /*計算出優(yōu)先級*/{OSPrioHighRdy = (INT8U)((y << 4u) + OSUnMapTbl[(*ptbl & 0xFFu)]);}else {OSPrioHighRdy = (INT8U)((y << 4u) + OSUnMapTbl[(OS_PRIO)(*ptbl >> 8u) & 0xFFu] + 8u);} #endif }
/*$PAGE*/ /*2018/2/8 ********************************************************************************************************* * SCHEDULER * 調(diào)度 * Description: This function is called by other uC/OS-II services to determine whether a new, high * priority task has been made ready to run. This function is invoked by TASK level code * and is not used to reschedule tasks from ISRs (see OSIntExit() for ISR rescheduling). *描述:該功能被其他服務調(diào)用,用來決定是否一個新的、高優(yōu)先級任務已經(jīng)準備好運行了。任務級的調(diào)度是由函數(shù)OSSched()完成的。中斷級的調(diào)度是由另一個函數(shù)OSIntExt()完成的). * Arguments : none *參數(shù):無 * Returns : none *返回值:無 * Notes : 1) This function is INTERNAL to uC/OS-II and your application should not call it. * 2) Rescheduling is prevented when the scheduler is locked (see OS_SchedLock()) 注釋: 1)該功能為內(nèi)部函數(shù),你的應用程序不能調(diào)用2) 給調(diào)度器上鎖用于禁止任務調(diào)度 (查看 OSSchedLock()函數(shù)) ********************************************************************************************************* */void OS_Sched(void) /*任務調(diào)度函數(shù)*/ { #if OS_CRITICAL_METHOD == 3u /*中斷函數(shù)被設定為模式3*/OS_CPU_SR cpu_sr = 0u; #endifOS_ENTER_CRITICAL(); /*關中斷*/if (OSIntNesting == 0u) { /*如果所有的中斷都完成了 */if (OSLockNesting == 0u) { /* 并且調(diào)度器沒有被鎖 */OS_SchedNew(); /*找到要運行的任務*/OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; /*為實現(xiàn)任務切換,OSTCBHighRdy必須指向優(yōu)先級最高的那個任務控制塊OS_TCB,這是通過將以OSPrioHighRdy為下標的OSTCBPrioTbl[]數(shù)組中的那個元素賦給OSTCBHighRdy來實現(xiàn)的*/if (OSPrioHighRdy != OSPrioCur) { /*找到最高優(yōu)先級任務后,函數(shù)檢查這個優(yōu)先級最高的任務是否是當前正在運行的任務,以避免不必要的任務調(diào)度,多花時間*/#if OS_TASK_PROFILE_EN > 0uOSTCBHighRdy->OSTCBCtxSwCtr++; /* Inc. # of context switches to this task */#endifOSCtxSwCtr++; /*任務切換計數(shù)值加1,統(tǒng)計切換次數(shù) */OS_TASK_SW(); /*進行實際的任務交換 */}}}OS_EXIT_CRITICAL(); /*開中斷*/ }
這兩個函數(shù)中讓人費解的還是計算優(yōu)先級那一塊。回頭看了(9)中介紹的有關知識,感覺描述的還是不夠清楚。有時間重新梳理一下,盡量描述詳盡。
?OS_StrLen(INT8U *psrc)確定一個ASCII字符串的長度的函數(shù):
這個函數(shù)不需要多說。
?OS_TaskIdle(void *p_arg)空閑任務函數(shù):
空閑任務函數(shù)主要是統(tǒng)計空閑任務數(shù)量,調(diào)用用戶自定義的鉤子函數(shù)。
OS_TaskStatStkChk(void)檢查所有的任務堆棧函數(shù):
OS_STK_DATA stk_data;這個語句中,解釋一下OS_STK_DATA結(jié)構(gòu)體,方便大家理解: /* *2018/1/30 ********************************************************************************************************* * TASK STACK DATA * 任務堆棧數(shù)據(jù) ********************************************************************************************************* */#if OS_TASK_CREATE_EXT_EN > 0u typedef struct os_stk_data {INT32U OSFree; /* Number of free bytes on the stack 堆棧中未使用的字節(jié)數(shù) */INT32U OSUsed; /* Number of bytes used on the stack 堆棧中已使用的字節(jié)數(shù) */ } OS_STK_DATA; #endif
?OS_TaskStat(void *p_arg)統(tǒng)計任務函數(shù):
/*$PAGE*/ /*2018/2/8 ********************************************************************************************************* * STATISTICS TASK * 統(tǒng)計任務 * Description: This task is internal to uC/OS-II and is used to compute some statistics about the * multitasking environment. Specifically, OS_TaskStat() computes the CPU usage. * CPU usage is determined by: *描述:這個任務是uc/os-ii內(nèi)部任務,并且被用來計算一些關于多任務環(huán)境的統(tǒng)計數(shù)據(jù)。最關鍵的是用OS_TaskStat()函數(shù)計算CPU的使用率 * OSIdleCtr * OSCPUUsage = 100 * (1 - ------------) (units are in %) * OSIdleCtrMax * cpu的使用率=100*(1-空閑任務數(shù)/設定的空閑任務總數(shù)) * Arguments : parg this pointer is not used at this time. *參數(shù): --parg:這個時候不使用parg * Returns : none *返回值: 無 * Notes : 1) This task runs at a priority level higher than the idle task. In fact, it runs at the * next higher priority, OS_TASK_IDLE_PRIO-1. * 2) You can disable this task by setting the configuration #define OS_TASK_STAT_EN to 0. * 3) You MUST have at least a delay of 2/10 seconds to allow for the system to establish the * maximum value for the idle counter.注釋: 1) uC/OS-II已經(jīng)將空閑任務的優(yōu)先級設為最低,即OS_LOWEST_PR10,統(tǒng)計任務的優(yōu)先級設為次低,OS_LOWEST_PR10-1.2)你可以通過設置配置禁用該任務 #define OS_TASK_STAT_EN to 0.3)你必須有至少0.2s(2個時鐘節(jié)拍)的延遲來使系統(tǒng)能夠為空閑任務計數(shù)器設置最大值 ********************************************************************************************************* */#if OS_TASK_STAT_EN > 0u void OS_TaskStat(void *p_arg) /*任務統(tǒng)計函數(shù)*/ { #if OS_CRITICAL_METHOD == 3u /*將中斷類型設置為3*/OS_CPU_SR cpu_sr = 0u; #endifp_arg = p_arg; /*自己給自己賦值,防止編譯出現(xiàn)錯誤*/while (OSStatRdy == OS_FALSE) /*如果統(tǒng)計任務狀態(tài)不是就緒的,通過延遲函數(shù)OSTimeDly()等待*/{ OSTimeDly(2u * OS_TICKS_PER_SEC / 10u); /* Wait until statistic task is ready*/}OSIdleCtrMax /= 100uL; /*將最大空閑計數(shù)值對100求整*/if (OSIdleCtrMax == 0uL) /*如果最大空閑計數(shù)值為0*/{OSCPUUsage = 0u; /*CPU使用率為0*/#if OS_TASK_SUSPEND_EN > 0u /*如果允許任務掛起*/(void)OSTaskSuspend(OS_PRIO_SELF);/*調(diào)用任務掛起函數(shù)(參數(shù)為自身的優(yōu)先級)*/#else /*不允許任務掛起*/for (;;) {OSTimeDly(OS_TICKS_PER_SEC); /*就通過延遲函數(shù)進行等待*/}#endif}for (;;) {OS_ENTER_CRITICAL(); /*關中斷*/OSIdleCtrRun = OSIdleCtr; /*將此時統(tǒng)計的空閑計數(shù)值賦給OSIdleCtrRun這個臨時變量*/OSIdleCtr = 0uL; /*將OSIdleCtr重新設置為0,然后進行下一秒鐘的計數(shù)*/OS_EXIT_CRITICAL(); /*開中斷*/OSCPUUsage = (INT8U)(100uL - OSIdleCtrRun / OSIdleCtrMax); /*計算CPU的使用率*/OSTaskStatHook(); /*執(zhí)行用戶自定義的鉤子函數(shù)*/#if (OS_TASK_STAT_STK_CHK_EN > 0u) && (OS_TASK_CREATE_EXT_EN > 0u)OS_TaskStatStkChk(); /*任務堆棧檢測*/#endifOSTimeDly(OS_TICKS_PER_SEC / 10u); /*調(diào)用延遲函數(shù)OSTimeDly()將自身延時1個時鐘節(jié)拍以停止自身的運行*/} } #endif
在這個函數(shù)中想解釋一下幾點:
1.任務統(tǒng)計函數(shù)中最主要的幾個語句是:
OSIdleCtrMax /= 100uL; /*將最大空閑計數(shù)值對100求整*/ OSIdleCtrRun = OSIdleCtr; /*將此時統(tǒng)計的空閑計數(shù)值賦給OSIdleCtrRun這個臨時變量*/ OSIdleCtr = 0uL; /*將OSIdleCtr重新設置為0,然后進行下一秒鐘的計數(shù)*/ OSCPUUsage = (INT8U)(100uL - OSIdleCtrRun / OSIdleCtrMax); /*計算CPU的使用率*/
2.在這個函數(shù)中:解釋一下下面這個語句:
OSIdleCtrMax /= 100uL; /*將最大空閑計數(shù)值對100求整*/
大家可能看到這個語句時和我有著同樣的疑問:為什么要對100取整?有什么必要性?
?這里將最大值除以100是為了之后的計算。若是不除100,根據(jù)前面提到的公式來的話,?OSIdleCtr / OSIdleCtrMax這里我們希望得到的是一個浮點數(shù),也就是一個小于1的小數(shù),但是因為OSIdleCtr、OSIdleCtrMax 都是整數(shù),且OSIdleCtr < OSIdleCtrMax,則兩個數(shù)相除就必定為0,則OSCPUUsage 始終會等于100。所以先OSIdleCtrMax /100,然后再OSIdleCtrRun / OSIdleCtrMax,這個結(jié)果就不會是一個小于0的數(shù),這個時候就不會出現(xiàn)始終等于0的情況 。同時在算數(shù)邏輯上100 - OSIdleCtrRun / OSIdleCtrMax=100 -OSIdleCtrRun *100/ OSIdleCtrMax = 100(1 -OSIdleCtrRun / OSIdleCtrMax )。這樣計算能夠接近數(shù)學運算的結(jié)果。
3.第三個關于這個函數(shù)的疑問是:在for循環(huán)最后的一行語句:
OSTimeDly(OS_TICKS_PER_SEC / 10u); /*調(diào)用延遲函數(shù)OSTimeDly()將自身延時1個時鐘節(jié)拍以停止自身的運行*/
我們知道這個語句是延遲函數(shù)。但是這里為什么要用呢?
實際上,OSTimeDly()函數(shù)可以看作一個延時函數(shù),但是它真正的內(nèi)涵是將CPU讓給其他的任務。將自身的任務延時,在OSTimeDly(Ticks)這段時間內(nèi)調(diào)用OS_Sched()函數(shù)找出任務就緒列表中優(yōu)先級最高的任務并將當前CPU切換到該任務。
關于這個函數(shù)就介紹到這里。
OS_TCBInit(INT8U ? ?prio, OS_STK ?*ptos,OS_STK ?*pbos,INT16U ? id,INT32U ? stk_size,void ? ?*pext,INT16U ? opt)
初始化TCB函數(shù):
/*$PAGE*/ /*2018/2/9 ********************************************************************************************************* * INITIALIZE TCB * 初始化TCB * Description: This function is internal to uC/OS-II and is used to initialize a Task Control Block when * a task is created (see OSTaskCreate() and OSTaskCreateExt()). *描述:該功能是內(nèi)部函數(shù),當有任務被創(chuàng)建時(詳情見OSTaskCreate()函數(shù)和OSTaskCreateExt()函數(shù)),該函數(shù)被用來初始化任務控制塊, * Arguments : prio is the priority of the task being created *參數(shù): --prio是被創(chuàng)建任務的優(yōu)先級 * ptos is a pointer to the task's top-of-stack assuming that the CPU registers * have been placed on the stack. Note that the top-of-stack corresponds to a * 'high' memory location is OS_STK_GROWTH is set to 1 and a 'low' memory * location if OS_STK_GROWTH is set to 0. Note that stack growth is CPU * specific. * --ptos:假設CPU寄存器被堆棧占用,ptos就是指向棧頂?shù)闹羔槨W⒁?#xff1a;如果內(nèi)存增長方式被設定為1(從高地址到低地址),那么ptos(棧頂)指向的是高地址;相反,如果增長方式被設定為0(從低地址到高地址),那么ptos(棧頂)指向的是低地址。具體是什么增長方式取決于不同的CPU * pbos is a pointer to the bottom of stack. A NULL pointer is passed if called by * 'OSTaskCreate()'. * --pbos:指向棧底的指針。如果是使用OSTaskCreate()創(chuàng)建任務,pbos被設定為null空。 * id is the task's ID (0..65535) * --id是棧的ID號 * stk_size is the size of the stack (in 'stack units'). If the stack units are INT8Us * then, 'stk_size' contains the number of bytes for the stack. If the stack * units are INT32Us then, the stack contains '4 * stk_size' bytes. The stack * units are established by the #define constant OS_STK which is CPU * specific. 'stk_size' is 0 if called by 'OSTaskCreate()'. * --stk_size:是棧的大小(或者準確講師棧單元的大小)。如果棧單元是8位的,stk_size值得就是8位可以表示的字節(jié)大小(2的8次方字節(jié))。如果棧單元室32位的,這個棧就有4*stk_size字節(jié)這么大。棧單元是通過 #define constant OS_STK來定義的。與CPU類型相關 * pext is a pointer to a user supplied memory area that is used to extend the task * control block. This allows you to store the contents of floating-point * registers, MMU registers or anything else you could find useful during a * context switch. You can even assign a name to each task and store this name * in this TCB extension. A NULL pointer is passed if called by OSTaskCreate(). * --pext擴展指針:指向用戶可使用的內(nèi)存單元,該內(nèi)存單元是為了擴大任務控制塊。這樣可以存儲浮點數(shù)寄存器、MMU寄存器或者其他在上下文交換時可用的寄存器中的內(nèi)容。甚至可以設定每個任務的名稱,并將該名稱存儲在TCB擴展中。 * opt options as passed to 'OSTaskCreateExt()' or, * 0 if called from 'OSTaskCreate()'. * --opt:如果是OSTaskCreateExt()調(diào)用,代表OS_TCB的選擇項,如果是OSTaskCreate()調(diào)用,opt為0 * Returns : OS_ERR_NONE if the call was successful * OS_ERR_TASK_NO_MORE_TCB if there are no more free TCBs to be allocated and thus, the task cannot * be created. *返回值:OS_ERR_NONE:調(diào)用成功返回該值OS_ERR_TASK_NO_MORE_TCB:如果沒有空閑的TCB了,任務不能被創(chuàng)建,返回該值 * Note : This function is INTERNAL to uC/OS-II and your application should not call it. 注釋: 該功能是內(nèi)部函數(shù),你的應用程序不能調(diào)用 ********************************************************************************************************* */INT8U OS_TCBInit(INT8U prio, OS_STK *ptos,OS_STK *pbos,INT16U id,INT32U stk_size,void *pext,INT16U opt) {OS_TCB *ptcb; /*指向TCB的指針*/ #if OS_CRITICAL_METHOD == 3u /*將中斷類型設置為3*/OS_CPU_SR cpu_sr = 0u; #endif #if OS_TASK_REG_TBL_SIZE > 0uINT8U i; #endifOS_ENTER_CRITICAL(); /*關中斷*/ptcb = OSTCBFreeList; /*ptcb指針指向空閑TCB列表,來獲得一個空閑的TCB*/if (ptcb != (OS_TCB *)0) /*如果ptcb不為0,即還有空閑的TCB*/{OSTCBFreeList = ptcb->OSTCBNext; /* Update pointer to free TCB list更新一下空閑TCB列表指針(起始指針后移一個)*/OS_EXIT_CRITICAL(); /*關中斷*/ptcb->OSTCBStkPtr = ptos; /*將棧頂指針存儲在ptch中的OSTCBStkPtr */ptcb->OSTCBPrio = prio; /*將優(yōu)先級存儲在OSTCBPrio中*/ptcb->OSTCBStat = OS_STAT_RDY; /*將TCB的狀態(tài)設置為就緒態(tài)*/ptcb->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status將掛起狀態(tài)設置為OS_STAT_PEND_OK*/ptcb->OSTCBDly = 0u; /* Task is not delayed無任務延遲,直接執(zhí)行*/#if OS_TASK_CREATE_EXT_EN > 0u /*如果創(chuàng)建的是擴展型任務,存儲有關的信息*/ptcb->OSTCBExtPtr = pext; ptcb->OSTCBStkSize = stk_size; ptcb->OSTCBStkBottom = pbos; ptcb->OSTCBOpt = opt; ptcb->OSTCBId = id; #else /*不是擴展型任務*/pext = pext; /*pext只針對擴展型任務,所以這里自己給自己賦值,防止編譯出錯*/stk_size = stk_size;pbos = pbos;opt = opt;id = id;#endif#if OS_TASK_DEL_EN > 0uptcb->OSTCBDelReq = OS_ERR_NONE;/*將刪除TCB的請求設置為OS_ERR_NONE*//*如果可以刪除任務本身,可以從每個OS_TCB中節(jié)省出一個布爾量*/#endif/*提前進行相關計算,為了節(jié)省CPU的操作事件*/#if OS_LOWEST_PRIO <= 63u ptcb->OSTCBY = (INT8U)(prio >> 3u);ptcb->OSTCBX = (INT8U)(prio & 0x07u);#else ptcb->OSTCBY = (INT8U)((INT8U)(prio >> 4u) & 0xFFu);ptcb->OSTCBX = (INT8U)(prio & 0x0Fu);#endif/* Pre-compute BitX and BitY */ptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY);/*提前計算位掩碼*/ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX);#if (OS_EVENT_EN)ptcb->OSTCBEventPtr = (OS_EVENT *)0; /* 如果不打算在應用程序中使用各類事件,OS_TCB中OSTCBEventPt就不會出現(xiàn)任務就不會被掛起Task is not pending on an event*/#if (OS_EVENT_MULTI_EN > 0u)ptcb->OSTCBEventMultiPtr = (OS_EVENT **)0; /* Task is not pending on any events任務不會因為任何事件被掛起*/#endif#endif#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u) && (OS_TASK_DEL_EN > 0u)ptcb->OSTCBFlagNode = (OS_FLAG_NODE *)0; /* Task is not pending on an event flag任務不會因為事件標志被掛起 */#endif#if (OS_MBOX_EN > 0u) || ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u))ptcb->OSTCBMsg = (void *)0; /* No message received消息數(shù)設為0*/#endif#if OS_TASK_PROFILE_EN > 0uptcb->OSTCBCtxSwCtr = 0uL; /* Initialize profiling variables初始化分析變量 */ptcb->OSTCBCyclesStart = 0uL;ptcb->OSTCBCyclesTot = 0uL;ptcb->OSTCBStkBase = (OS_STK *)0;ptcb->OSTCBStkUsed = 0uL;#endif#if OS_TASK_NAME_EN > 0uptcb->OSTCBTaskName = (INT8U *)(void *)"?";/*初始化TCB任務名稱*/#endif#if OS_TASK_REG_TBL_SIZE > 0u /* Initialize the task variables初始化任務變量*/for (i = 0u; i < OS_TASK_REG_TBL_SIZE; i++) {ptcb->OSTCBRegTbl[i] = 0u;}#endifOSTCBInitHook(ptcb); /*初始化鉤子函數(shù)*/OSTaskCreateHook(ptcb); /* Call user defined hook調(diào)用用戶自定義的鉤子函數(shù)*/OS_ENTER_CRITICAL(); /*關中斷*/OSTCBPrioTbl[prio] = ptcb; ptcb->OSTCBNext = OSTCBList; /* Link into TCB chain鏈接到任務控制塊鏈接串*/ptcb->OSTCBPrev = (OS_TCB *)0; if (OSTCBList != (OS_TCB *)0) {OSTCBList->OSTCBPrev = ptcb;}OSTCBList = ptcb;OSRdyGrp |= ptcb->OSTCBBitY; /*通過掩碼計算就緒組號*/OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;/*通過掩碼計算在就緒表中的位置*/OSTaskCtr++; /* 任務數(shù)目加1*/OS_EXIT_CRITICAL(); /*開中斷*/return (OS_ERR_NONE);}OS_EXIT_CRITICAL(); /*開中斷*/return (OS_ERR_TASK_NO_MORE_TCB); }
相關介紹:http://blog.csdn.net/m0_37411189/article/details/72967962
解析在創(chuàng)建任務時對該任務控制塊的初始化過程(三步走):
2.用任務的屬性對任務控制塊各個成員進行賦值
3.把這個任務控制塊鏈入到任務控制塊鏈表(OSTCBList),并在任務就緒表中登記該任務
個人感覺源代碼讀起來有些費神,但是這三個圖表現(xiàn)的很清楚。
到這里,OS_CORE.C文件讀完。
總結(jié)
以上是生活随笔為你收集整理的OS_CORE.C(11)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OS_CORE.C(10)
- 下一篇: uc/os-II(source)各种文件