?? functionforucos.txt
字號:
#endif
#if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN
void *OSTCBMsg; //
#endif
INT16U OSTCBDly; //任務延時節(jié)拍
INT8U OSTCBStat; //任務狀態(tài),當它等于OS_STAT_READY時,任務進入就緒態(tài)
INT8U OSTCBPrio; //任務優(yōu)先級
INT8U OSTCBX; //例如任務的優(yōu)先級為25, 則OSTCBX=25%8=1
INT8U OSTCBY; //OSTCBY=25%8=3
INT8U OSTCBBitX; //
INT8U OSTCBBitY; //對應的位數(shù)
#if OS_TASK_DEL_EN
BOOLEAN OSTCBDelReq; //
#endif
} OS_TCB;
第六章:OS的核心運轉過程 (1)空閑任務的建立及運行過程
μC/OS /sherlock_lai 發(fā)表于2008-01-16, 21:56
OS是如何運轉起來的?(一般情況下,不考慮系統(tǒng)的一些配置被修改).
1.系統(tǒng)變量常量配置
在程序的最開頭,先定義你需要的任務的堆棧大小,優(yōu)先級,此時CPU已經(jīng)將系統(tǒng)的一些變量,常量儲存于實際物理地址了(例如任務堆棧)
#define .....
...
2.運行到OSInit();
首先是一個主函數(shù),CPU運行第一個函數(shù)OSInit();在這里,CPU初始化一些系統(tǒng)變量的值,例如一些任務記數(shù)器等.
然后創(chuàng)建兩個基本的任務:空閑任務(CPU閑置時就連續(xù)運行此任務),統(tǒng)計任務(統(tǒng)計空閑任務,以便計算CPU的使用率).
void Main(void)
{
OSInit();
OSTaskCreate(Main_Task, (void *)0, (OS_STK *)&Main_Stack[TASK_STACK_SIZE-1], Main_PRIO);
OSStart();
}
2.0 初始化一個任務控制快單向鏈表, .OSTCBNext=下一個, OSTCBFreeList為第一個,如果這個鏈表被取出一個,則OSTCBFreeList指向空鏈表里的第一個
2.1 建立空閑任務的過程
2.11 OSTaskStkInit 根據(jù)任務函數(shù)入口,傳遞的參數(shù),棧頂,選擇項,4個參數(shù)決定物理棧頂指針,這個棧里還有其他參數(shù),比如PC值,這些參數(shù)都保存在這個物理棧里,在任務開始運行時,將這些值取出,而當任務因為某種原因中斷了,則保存這些值,這樣下次就能從中斷的那個狀態(tài)再次運行這個任務.
初始化堆棧,從棧頂依次壓入,任務函數(shù)入口,各個寄存器,這樣恢復任務的時候先恢復各個寄存器,最后才將任務函數(shù)入口壓入PC,從而運行任務
2.12 OSTCBInit 初始化一個任務控制塊
將各個參數(shù)填入這個控制塊,并且生成一個雙向任務鏈表,每次初始化的任務控制塊將會添加入鏈表的左端,這個雙向鏈表在時鐘節(jié)拍中會用到.
最后在就緒表里將此任務對應的位置一,表示這個任務已經(jīng)就緒了.
2.13 如果以上都成功了,則任務記數(shù)器+1. 接下來會檢查OSRunning,如果它為0,說明系統(tǒng)還未運行,這樣空閑任務就建立了,等待OSStart 函數(shù)開始運行系統(tǒng),如果OSRunning 為1,說明系統(tǒng)已經(jīng)運行,這樣就執(zhí)行一次任務調度,任務調度的作用是,如果剛剛建立的任務優(yōu)先級最高,就運行這個任務. 以下分析任務調度函數(shù)
2.131 OSSched 如果任務調度的條件成立,則將就緒表里優(yōu)先級最高的任務賦予OSPrioHighRdy(等待運行里優(yōu)先級最高的任務)(這個地方有個疑問:在這個地方運行完后,OSPrioHighRdy和OSPrioRdy會變成什么) 如果這個最高優(yōu)先級的任務還沒運行,那么任務切換計數(shù)器+1,執(zhí)行OS_TASK_SW 任務切換函數(shù). 接下來解析任務切換函數(shù)功能
2.1311 OS_TASK_SW 保存處理器的值,將當前任務的堆棧指針保存到當前任務的OS_TCB, (第一次運行OS,這個TCB是否為空閑任務的TCB?) , OSTCBCur , OSPrioCur 賦予最高優(yōu)先級任務,堆棧指針賦予最高優(yōu)先級任務指針,將堆棧中的內(nèi)容恢復,執(zhí)行中斷返回指令,這樣就運行了最高優(yōu)先級任務了,這里就是空閑任務. (疑問:第一次的堆棧有何作用?還是本來就沒用?)
2.2 建立完空閑任務,這時空閑任務就運行了,這里又有個疑問,此時系統(tǒng)的最高優(yōu)先級任務為空閑任務,那么當空閑任務掛起進行任務調度時,那么會運行的不會又是空閑任務? 還是沒有跳會到主程序流程? 可能空閑任務里保存了兩塊堆棧,主流程堆棧和自身的堆棧. 這里不是很理解...不管先,繼續(xù)往下走,假設系統(tǒng)跳回到任務建立那,接下來也就是要建立統(tǒng)計任務了.
第六章:OS的核心運轉過程 (2)始終節(jié)拍函數(shù),統(tǒng)計任務
μC/OS /sherlock_lai 發(fā)表于2008-01-06, 22:19
OSTickISR 時鐘節(jié)拍函數(shù)
時鐘一到,保存寄存器值,當前的堆棧指針SP賦予OSTCBCur.OSTCBStkPtr,調用OSTimeTick()
OSTimeTick 節(jié)拍服務函數(shù)
將每個TCB中的.OSTCBDly-1,如果OSTCBDly為0了,任務原先也沒有被掛起,就將任務置為就緒態(tài),如果原先被掛起,就先將OSTCBDly為1. 這里有條語句ptcb=OSTCBList ,OSTCBList是?
接著恢復處理器寄存器的值,返回原先的狀態(tài).
前面提出的疑問這里突然也得到解決, 因為第一次建立空閑函數(shù),此時OSRUNNING還是為0,所以還不會出現(xiàn)程序在空閑任務處循環(huán)的情況,因為空閑任務根本不會運行,這里程序會繼續(xù)往下走,建立統(tǒng)計任務
OSTaskStat
第七章:函數(shù)解析:OSTimeTick
μC/OS /sherlock_lai 發(fā)表于2008-01-08, 20:31
void OSTimeTick (void) //這個節(jié)拍服務函數(shù)是在OSTickISR函數(shù)中調用的,目的是在時鐘節(jié)拍到來時,檢查每個任務的任務控制塊中的.OSTCBDly-1后是否為0,如果是,那么表明這個任務剛才是掛起的狀態(tài),此時應改變?yōu)榫途w態(tài)
{
OS_TCB *ptcb;
OSTimeTickHook(); //
ptcb = OSTCBList; //時鐘節(jié)拍到來時,將控制塊雙向鏈表的第一個控制塊取出(并不是節(jié)拍之前運行的任務)
while (ptcb->OSTCBPrio != OS_IDLE_PRIO) { //空閑任務處于控制塊雙向鏈表的最后一個,如果取出的控制塊為空閑任務的控制塊,那么已經(jīng)取到最后一個了,就結束
// OS_ENTER_CRITICAL();
if (ptcb->OSTCBDly != 0) { //
if (--ptcb->OSTCBDly == 0) { //
if (!(ptcb->OSTCBStat & OS_STAT_SUSPEND)) { //檢查任務是否處于強制掛起狀態(tài),如果是,那再掛起一個時鐘節(jié)拍,否則就將它就緒
OSRdyGrp |= ptcb->OSTCBBitY;
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
} else { //
ptcb->OSTCBDly = 1; //
} //
}
}
ptcb = ptcb->OSTCBNext; //下一個任務控制塊
// OS_EXIT_CRITICAL();
}
// OS_ENTER_CRITICAL(); //
OSTime++; //節(jié)拍計數(shù)器+1
// OS_EXIT_CRITICAL();
}
第八章:函數(shù)解析:OSTaskStat
μC/OS /sherlock_lai 發(fā)表于2008-01-08, 21:01
void OSTaskStat (void *pdata) //統(tǒng)計任務的目的是計算CPU利用率。CPU空閑時會不停的運行空閑任務,只要得到空閑任務運行次數(shù)的全局變量,就能統(tǒng)計出CPU利用率
{
INT32U run;
INT8S usage;
pdata = pdata; //
while (OSStatRdy == FALSE) { //等待統(tǒng)計任務就緒
OSTimeDly(2 * OS_TICKS_PER_SEC); //
}
for (;;) {
OS_ENTER_CRITICAL();
OSIdleCtrRun = OSIdleCtr; //獲得統(tǒng)計任務運行次數(shù)(1秒內(nèi))
run = OSIdleCtr;
OSIdleCtr = 0L; //清零,必要的,為下一秒的統(tǒng)計做準備
OS_EXIT_CRITICAL();
if (OSIdleCtrMax > 0L) {
usage = (INT8S)(100L - 100L * run / OSIdleCtrMax); //計算百分比
if (usage > 100) {
OSCPUUsage = 100;
} else if (usage < 0) {
OSCPUUsage = 0;
} else {
OSCPUUsage = usage;
}
} else {
OSCPUUsage = 0;
}
OSTaskStatHook(); //
OSTimeDly(OS_TICKS_PER_SEC); //掛起一秒,統(tǒng)計任務一秒運行一次 }
}
第九章:函數(shù)解析:OSStart
μC/OS /sherlock_lai 發(fā)表于2008-01-08, 22:07
void OSStart (void) //執(zhí)行這個函數(shù)OS就開始運行了
{
INT8U y;
INT8U x;
if (OSRunning == FALSE)
{
y = OSUnMapTbl[OSRdyGrp]; //取出優(yōu)先級最高的任務
x = OSUnMapTbl[OSRdyTbl[y]];
OSPrioHighRdy = (INT8U)((y << 3) + x);
OSPrioCur = OSPrioHighRdy;
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; //
OSTCBCur = OSTCBHighRdy;
OSStartHighRdy(); //OSRunning=TRUE,得到要將要運行的最高優(yōu)先級任務的指針,恢復任務棧內(nèi)的寄存器和PC值,開始執(zhí)行任務。疑問:AMR7移植的OS里,這個函數(shù)中為什么不包含OSRunning=TRUE這條指令????
}
}
執(zhí)行這個函數(shù)后,空閑任務開始不停運行,到了第一個時鐘節(jié)拍,CPU首先將任務雙向鏈表里的任務的延遲變量都-1,然后將延遲變量為0的任務就緒,接著看處于就緒態(tài)的優(yōu)先級最高的任務是否運行,如果沒有,就運行這個任務。然后系統(tǒng)到了第二個時鐘節(jié)拍,第三個.....一直做這樣的循環(huán),這樣就保證優(yōu)先級最高的任務得以第一時間運行。
一般情況下,UCOS的核心運轉過程就是這樣一個循環(huán)。
第十章:函數(shù)解析:OSTickISR,OSIntExit,OSIntCtxSw
μC/OS /sherlock_lai 發(fā)表于2008-01-08, 22:43
這個函數(shù)涉及寄存器的操作。以下是示意性代碼(引用邵貝貝一書)。
保存處理器寄存器;
調用OSIntEnter()或者直接給OSIntNesting加1;
if(OSIntNesting==1)
{
OSTCBCur->OSTCBStkPtr=Stack Pointer;
}
給產(chǎn)生中斷的設備清中斷;
重新允許中斷(可選);
OSTimeTick(); //給延時到的任務就緒態(tài)
OSIntExit(); //這個函數(shù)與OSSched 差不多,都是將最高級任務置為就緒態(tài)
恢復處理器寄存器;
執(zhí)行中斷返回指令;
}
void OSIntExit (void)
{
// OS_ENTER_CRITICAL();
if ((--OSIntNesting | OSLockNesting) == 0) //
OSIntExitY = OSUnMapTbl[OSRdyGrp];
OSPrioHighRdy = (INT8U)((OSIntExitY << 3) + OSUnMapTbl[OSRdyTbl[OSIntExitY]]);
if (OSPrioHighRdy != OSPrioCur)
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; //在這里得到新的OSTCBHighRdy參數(shù)
OSCtxSwCtr++;
OSIntCtxSw(); //這個函數(shù)與OSCtxSw差不多
}
}
// OS_EXIT_CRITICAL();
}
void OSIntCtxSw(void)
{
OSTCBCur->OSTCBStkPtr=堆棧指針;
OSTCBCur=OSTCBHighRdy;
OSPrioCur=OSPrioHighRdy; //恢復OSTCBCur參數(shù)
堆棧指針=OSTCBHighRdy->OSTCBStkPtr;
將任務堆棧中的內(nèi)容恢復;
執(zhí)行中斷返回指令;
}
第十一章:關于OSRunning的問題
μC/OS /sherlock_lai 發(fā)表于2008-01-09, 12:41
UCOS的源代碼中要求在OSStartHighRdy中加入OSRunning=TRUE的代碼,但是我用的那個ARM7移植的OSSTartHighRdy并沒有這段代碼,這會帶來什么問題?
首先,OSRunning這個變量在創(chuàng)建任務函數(shù)OSTaskCreate中有用到,如果OSRunning為TRUE,則執(zhí)行OSSched,OSSched的功能就是將就緒表中優(yōu)先級任務最高的任務取出,然后進行任務切換。也就是說,如果在OSStartHighRdy中沒有OSRunning=TRUE的代碼,在創(chuàng)建任務的時候,如果創(chuàng)建的任務的優(yōu)先級為最高,那么它并不能得到馬上運行。但實際上這也沒多大關系,因為當時鐘節(jié)拍到來的時候,時鐘節(jié)拍依次調用了OSTimeTick(節(jié)拍服務函數(shù))和OSIntExit。后者與OSSched是極其相似的,它們的作用也一樣。這樣,在節(jié)拍到來時,還是會進行任務切換,只不過剛創(chuàng)建的優(yōu)先級最高的任務相當于延時了一個節(jié)拍運行而已。
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -