從 μC/OS 升級(jí)到 μC/OS-II
本章描述如何從μC/OS 升級(jí)到 μC/OS-II。如果已經(jīng)將μC/OS移植到了某類微處理器上,移植μC/OS-II所要做的工作應(yīng)當(dāng)非常有限。在多數(shù)情況下,用戶能夠在1個(gè)小時(shí)之內(nèi)完成這項(xiàng)工作。
如果用戶熟悉μC/OS的移植,可隔過(guò)本章前一部分直接參閱10.05節(jié)。
10.0目錄和文件
用戶首先會(huì)注意到的是目錄的結(jié)構(gòu),主目錄不再叫 SOFTWAREuCOS。而是叫SOFTWAREuCOS-II。 所有的μC/OS-II文件都應(yīng)放在用戶硬盤的SOFTWAREuCOS-II 目錄下。面向不同的微處理器或微處理器的源代碼一定是在以下兩個(gè)或三個(gè)文件中: OS_CPU.H,OS_CPU_C.C,或許還有OS_CPU_A.ASM.。匯編語(yǔ)言文件是可有可無(wú)的,因?yàn)橛行〤編譯程序允許使用在線匯編代碼,用戶可以將這些匯編代碼直接寫在 OS_CPU_C.C.中。
與微處理器有關(guān)的特殊代碼,即與移植有關(guān)的代碼,在 μC/OS 中是放在用微處理器名字命名的文件中的,例如,Intel80x86的實(shí)模式(RealMode),在大模式下編譯(LargeModle)時(shí),文件名為Ix86L.H, Ix86L_C.C,和Ix86L_A.ASM.。
表L10.1在μC/OS-II中重新命名的文件.
升級(jí)可以從這里開始:首先將μC/OS目錄下的舊文件復(fù)制到μC/OS-II 的相應(yīng)目錄下,并改用新的文件名,這比重新建立一些新文件要容易許多。表10.2給出來(lái)幾個(gè)與移植有關(guān)的新舊文件名命名法的例子。
表 L10.2對(duì)不同微處理器從μC/OS到μC/OS-II,要重新命名的文件.
10.1 INCLUDES.H
用戶應(yīng)用程序中的INCLUDES.H 文件要修改。以80x86 實(shí)模式,在大模式下編譯為例,用戶要做如下修改:
? 變目錄名 μC/OS 為 μC/OS-II
? 變文件名 IX86L.H 為 OS_CPU.H
? 變文件名UCOS.H 為 uCOS_II.H
新舊文件如程序清單 L10.1和 L10.2所示
10.2 OS_CPU.H
OS_CPU.H 文件中有與微處理器類型及相應(yīng)硬件有關(guān)的常數(shù)定義、宏定義和類型定義。
10.2.1 與編譯有關(guān)的數(shù)據(jù)類型s
為了實(shí)現(xiàn) μC/OS-II, 用戶應(yīng)定義6個(gè)新的數(shù)據(jù)類型: INT8U、 INT8S、 INT16U、 NT16S、INT32U、和INT32S。這些數(shù)據(jù)類型有分別表示有符號(hào)和無(wú)符號(hào)8位、16位、32位整數(shù)。在μC/OS中相應(yīng)的數(shù)據(jù)類型分別定義為:UBYTE、BYTE、UWORD、WORD、ULONG和LONG。用戶所要做的僅僅是復(fù)制μC/OS中數(shù)類型并修改原來(lái)的UBYTE為INT8U,將BYTE為INT8S,將UWORD修改為INT16U等等,如程序清單 L10.3所示。
程序清單 L10.1μC/OS 中的 INCLUDES.H.
/*
***************************************************************
*INCLUDES.H
***************************************************************
*/
#include
#include
#include
#include
#include
#include
#include"SOFTWAREUCOSIX86LIX86L.H"
#include"OS_CFG.H"
#include"SOFTWAREUCOSSOURCEUCOS.H"
程序清單 L10.2μ$04** 中的 INCLUDES.H.
/*
***************************************************************
*INCLUDES.H
***************************************************************
*/
#include
#include
#include
#include
#include
#include
#include"SOFTWAREuCOS-IIIX86LOS_CPU.H"
#include"OS_CFG.H"
#include"SOFTWAREuCOS-IISOURCEuCOS_II.H"
程序清單 L10.3μC/OS到μC/OS-II 數(shù)據(jù)類型的修改.
/*uC/OSdatatypes:*/
typedefunsignedcharUBYTE;/*Unsigned8bitquanTIty*/
typedefsignedcharBYTE;/*Signed8bitquantity*/
typedefunsignedintUWORD;/*Unsigned16bitquantity*/
typedefsignedintWORD;/*Signed16bitquantity*/
typedefunsignedlongULONG;/*Unsigned32bitquantity*/
typedefsignedlongLONG;/*Signed32bitquantity*/
/*uC/OS-IIdatatypes*/
typedefunsignedcharINT8U;/*Unsigned8bitquantity*/
typedefsignedcharINT8S;/*Signed8bitquantity*/
typedefunsignedintINT16U;/*Unsigned16bitquantity*/
typedefsignedintINT16S;/*Signed16bitquantity*/
typedefunsignedlongINT32U;/*Unsigned32bitquantity*/
typedefsignedlongINT32S;/*Signed32bitquantity*/
在μC/OS中, 任務(wù)棧定義為類型OS_STK_TYPE, 而在μC/OS-II中任務(wù)棧要定義類型OS_STK.,為了免于修改所有應(yīng)用程序的文件, 可以在OS_CPU.H中建立兩個(gè)數(shù)據(jù)類型, 以Intel80x86 為例,如程序清單 L10.4所示。
程序清單 L10.4μC/OS 和 μC/OS-II任務(wù)棧的數(shù)據(jù)類型
#defineOS_STK_TYPEUWORD/* 在 uC/OS 中 */
#defineOS_STKINT16U/* 在 uC/OS-II 中 */
10.2.2OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()
μC/OS-II和μC/OS一樣,分別定義兩個(gè)宏來(lái)開中斷和關(guān)中斷:OS_ENTER_CRITICAL()和
OS_EXIT_CRITICAL()。在μC/OS向μC/OS-II升級(jí)的時(shí)候,用戶不必動(dòng)這兩個(gè)宏。.
10.2.3OS_STK_GROWTH
大多數(shù)微處理器和微處理器的棧都是由存儲(chǔ)器高地址向低地址操作的,然而有些微處理器的工
作方式正好相反。μC/OS-II設(shè)計(jì)成通過(guò)定義一個(gè)常數(shù)OS_STK_GROWTH來(lái)處理不同微處理器棧操作的取向:[!--empirenews.page--]
對(duì)棧操作由低地址向高地址增長(zhǎng),設(shè)OS_STK_GROWTH 為 0
對(duì)棧操作由高地址向低地址遞減,設(shè)OS_STK_GROWTH 為 1
有些新的常數(shù)定義(#define constants )在μC/OS中是沒(méi)有的,故要加到OS_CPU.H中去。
10.2.4OS_TASK_SW()
OS_TASK_SW()是一個(gè)宏,從μC/OS升級(jí)到μC/OS-II時(shí),這個(gè)宏不需要改動(dòng)。當(dāng)μC/OS-II從低優(yōu)先級(jí)的任務(wù)向高優(yōu)先級(jí)的任務(wù)切換時(shí)要用到這個(gè)宏,OS_TASK_SW()的調(diào)用總是出現(xiàn)在任務(wù)級(jí)代碼中。
10.2.5OS_FAR
因?yàn)镮ntel80x86的結(jié)構(gòu)特點(diǎn), 在μC/OS中使用過(guò)OS_FAR 。 這個(gè)定義語(yǔ)句 (#define ) 在μC/OS-II中去掉了,因?yàn)檫@條定義使移植變得不方便。結(jié)果是對(duì)于Intel80x86,如果用戶定義在大模式下編譯時(shí),所有存儲(chǔ)器屬性都將為遠(yuǎn)程(FAR).
在μC/OS-II中,任務(wù)返回值類型定義如程序清單L10.5所示。用戶可以重新編輯所有OS_FAR的文件,或者在μC/OS-II中將OS_FAR定義為空,去掉OS_FAR,以實(shí)現(xiàn)向μC/OS-II的升級(jí)。
程序清單 L10.5 在 μC/OS 中任務(wù)函數(shù)的定義
voidOS_FARtask(void*pdata)
{
pdata=pdata;
while(1){
.
.
}
}
10.3 OS_CPU_A.ASM
移植μC/OS 和μC/OS-II 需要用戶用匯編語(yǔ)言寫4個(gè)相當(dāng)簡(jiǎn)單的函數(shù)。
OSSTartHighRdy()
OSCtxSw()
OSIntCtxSw()
OSTickISR()
10.3.1OSStartHighRdy()
在μC/OS-II中,OSStartHighRdy()要調(diào)用OSSTaskSwHook()。OSTaskSwHook()這個(gè)函數(shù)在μC/OS中沒(méi)有。用戶將最高優(yōu)先級(jí)任務(wù)的棧指針裝入CPU之前要先調(diào)用OSTaskSwHook()。
還有, OSStartHighRdy要在調(diào)用OSTaskSwHook()之后立即將OSRunning設(shè)為1。程序清單L10.6 給出OSStartHighRdy()的示意代碼。.μC/OS只有其中最后三步。
程序清單 L10.6 OSStartHighRdy()的示意代碼
OSStartHighRdy:
CallOSTaskSwHook(); 調(diào)用OSTaskSwHook();
SetOSRunningto1; 置 OSRunning 為
1;
LoadtheprocessorstackpointerwithOSTCBHighRdy->OSTCBStkPtr;
將 OSTCBHighRdy->OSTCBStkPtr 裝入處理器的棧指
針;
POPalltheprocessorregistersfromthestack; 從棧中彈出所有寄存器的值;
ExecuteaReturnfromInterruptinstruction; 執(zhí)行中斷返回指令;
10.3.2OSCtxSw()
在μC/OS-II中,任務(wù)切換要增作兩件事,首先,將當(dāng)前任務(wù)棧指針保存到當(dāng)前任務(wù)控制塊TCB后要立即調(diào)用OSTaskSwHook()。其次,在裝載新任務(wù)的棧指針之前必須將OSPrioCur設(shè)為OSPrioHighRdy 。OSCtxSw()的示意代碼如程序清單L10.7所示。μC/OS-II加上了步驟L10.7(1)和(2)。
程序清單 L10.7 OSCtxSw()的示意代碼
OSCtxSw:
PUSHprocessorregistersontothecurrenttask’sstack;
所有處理器寄存器的值推入當(dāng)前任務(wù)棧;
SavethestackpointeratOSTCBCur->OSTCBStkPtr;
CallOSTaskSwHook();1)
OSTCBCur=OSTCBHighRdy;
OSPrioCur=OSPrioHighRdy;(2)
LoadtheprocessorstackpointerwithOSTCBHighRdy->OSTCBStkPtr;
將 OSTCBHighRdy->OSTCBStkPtr 裝入處理器的棧指
針;
POPalltheprocessorregistersfromthestack; 從棧中彈出所有寄存器的值;
ExecuteaReturnfromInterruptinstruction;
10.3.3OSIntCtxSw()
如同上述函數(shù)一樣,在μC/OS-II.中,OSCtxSw()也增加了兩件事。首先,將當(dāng)前任務(wù)的棧指針保存到當(dāng)前任務(wù)的控制塊TCB后要立即調(diào)用OSTaskSwHook()。其次,在裝載新任務(wù)的棧指針之前必須將OSPrioCur 設(shè)為OSPrioHighRdy。程序清單L10.8給出OSIntCtxSw()的示意代碼。μC/OS-II.中增加了L10.8(1)和(2)。
程序清單L10.8OSIntCtxSw()的示意代碼
OSIntCtxSw():
AdjustthestackpointertoremovecalltoOSIntExit(),localsin
OSIntExit()
andthecalltoOSIntCtxSw();
調(diào)整由于調(diào)用上述子程序引起的棧指針值的變化;
SavethestackpointeratOSTCBCur->OSTCBStkPtr;
保存棧指針到OSTCBCur->OSTCBStkPtr;
CallOSTaskSwHook(); 調(diào)用OSTaskSwHook();(1)
OSTCBCur=OSTCBHighRdy;
OSPrioCur=OSPrioHighRdy;(2)
LoadtheprocessorstackpointerwithOSTCBHighRdy->OSTCBStkPtr;
將 OSTCBHighRdy->OSTCBStkPtr 裝入處理器的棧指針;
POPalltheprocessorregistersfromthestack; 從棧中彈出所有寄存器的值;
ExecuteaReturnfromInterruptinstruction; 執(zhí)行中斷返回指令;
10.3.4OSTickISR()
在μC/OS-II和μC/OS 中,這個(gè)函數(shù)的代碼是一樣,無(wú)須改變。
10.4 OS_CPU_C.C
移植 μC/OS-II 需要用C語(yǔ)言寫6個(gè)非常簡(jiǎn)單的函數(shù):
OSTaskStkInit()
OSTaskCreateHook()
OSTaskDelHook()
OSTaskSwHook()
OSTaskStatHook()
OSTimeTickHook()
其中只有一個(gè)函數(shù)OSTaskStkInit()是必不可少的。其它5個(gè)只需定義,而不包括任何代碼。
10.4.1OSTaskStkInit()
在μC/OS中,OSTaskCreate()被認(rèn)為是與使用的微處理器類型有關(guān)的函數(shù)。實(shí)際上這個(gè)函數(shù)中只有一部分內(nèi)容是依賴于微處理器類型的。在μC/OS-II中,與使用的微處理器類型有關(guān)的那一部分已經(jīng)從函數(shù)OSTaskCreate() 中抽出來(lái)了,放在一個(gè)叫作OSTaskStkInit()的函數(shù)中。
OSTaskStkInit()只負(fù)責(zé)設(shè)定任務(wù)的棧,使之看起來(lái)好像中斷剛剛發(fā)生過(guò),所有的CPU寄存器都被推入堆棧。作為提供給用戶的例子,程序清單L10.9給出Intel80x86實(shí)模式,在大模式下編譯的 μC/OS的OSTaskCreate()函數(shù)的代碼。程序清單L10.10是同類微微處理器的μC/OS-II的OSTaskStkInit()函數(shù)的代碼。比較這兩段代碼,可以看出:從 [L10.9(1)]
OS_EXIT_CRIITICAL() 到 [L10.9(2)] 調(diào)用 OSTaskStkInit() 都抽出來(lái)并移到了[!--empirenews.page--]
OSTaskStkInit()中。
程序清單L10.9μC/OS 中的 OSTaskCreate()
UBYTEOSTaskCreate(void(*task)(void*pd),void*pdata,void*pstk,UBYTE
p)
{
UWORDOS_FAR*stk;
UBYTEerr;
OS_ENTER_CRITICAL();
if(OSTCBPrioTbl[p]==(OS_TCB*)0){
OSTCBPrioTbl[p]=(OS_TCB*)1;
OS_EXIT_CRITICAL();(1)
stk=(UWORDOS_FAR*)pstk;
*--stk=(UWORD)FP_OFF(pdata);
*--stk=(UWORD)FP_SEG(task);
*--stk=(UWORD)FP_OFF(task);
*--stk=(UWORD)0x0202;
*--stk=(UWORD)FP_SEG(task);
*--stk=(UWORD)FP_OFF(task);
*--stk=(UWORD)0x0000;
*--stk=(UWORD)0x0000;
*--stk=(UWORD)0x0000;
*--stk=(UWORD)0x0000;
*--stk=(UWORD)0x0000;
*--stk=(UWORD)0x0000;
*--stk=(UWORD)0x0000;
*--stk=(UWORD)0x0000;
*--stk=(UWORD)0x0000;
*--stk=_DS;
err=OSTCBInit(p,(voidfar*)stk);(2)
if(err==OS_NO_ERR){
if(OSRunning){
OSSched();
}
}else{
OSTCBPrioTbl[p]=(OS_TCB*)0;
}
return(err);
}else{
OS_EXIT_CRITICAL();
return(OS_PRIO_EXIST);
}
}
程序清單 L10.10 μC/OS-II中的OSTaskStkInit()
void*OSTaskStkInit(void(*task)(void*pd),void*pdata,void*ptos,
INT16Uopt)
{
INT16U*stk;
opt=opt;
stk=(INT16U*)ptos;
*stk--=(INT16U)FP_SEG(pdata);
*stk--=(INT16U)FP_OFF(pdata);
*stk--=(INT16U)FP_SEG(task);
*stk--=(INT16U)FP_OFF(task);
*stk--=(INT16U)0x0202;
*stk--=(INT16U)FP_SEG(task);
*stk--=(INT16U)FP_OFF(task);
*stk--=(INT16U)0xAAAA;
*stk--=(INT16U)0xCCCC;
*stk--=(INT16U)0xDDDD;
*stk--=(INT16U)0xBBBB;
*stk--=(INT16U)0x0000;
*stk--=(INT16U)0x1111;
*stk--=(INT16U)0x2222;
*stk--=(INT16U)0x3333;
*stk--=(INT16U)0x4444;
*stk=_DS;
return((void*)stk);
}
10.4.2OSTaskCreateHook()
OSTaskCreateHook()在μC/OS中沒(méi)有,如程序清單L10.11所示,在由.μC/OS 向μC/OS-II升級(jí)時(shí),定義一個(gè)空函數(shù)就可以了。注意其中的賦值語(yǔ)句,如果不把Ptcb賦給Ptcb,有些編譯器會(huì)產(chǎn)生一個(gè)警告錯(cuò)誤,說(shuō)定義的Ptcb變量沒(méi)有用到。
程序清單10.11 μC/OS-II 中的OSTaskCreateHook()
#ifOS_CPU_HOOKS_EN
OSTaskCreateHook(OS_TCB*ptcb)
{
ptcb=ptcb;
}
#endif
OS_CFG.H
OS_CPU_HOOKS _EN設(shè)為1時(shí),OSTaskCreateHook()的代碼才會(huì)生成。這樣做的好處是允許
用戶移植時(shí)可在不同文件中定義鉤子函數(shù)。
10.4.3OSTaskDelHook()
OSTaskDelHook() 這個(gè)函數(shù)在μC/OS中沒(méi)有,如程序清單10.12所示,從μC/OS 到μC/OS-II,只要簡(jiǎn)單地定義一個(gè)空函數(shù)就可以了。注意,如果不用賦值語(yǔ)句將ptcb賦值為ptcb,有些編譯程序可能會(huì)產(chǎn)生一些警告信息,指出定義的ptcb變量沒(méi)有用到。
程序清單L10.12 μC/OS-II中的OSTaskDelHook().
#ifOS_CPU_HOOKS_EN
OSTaskDelHook(OS_TCB*ptcb)
{
ptcb=ptcb;
}
#endif
也還是要用條件編譯管理指令來(lái)處理這個(gè)函數(shù)。只有把OS_CFG.H. 文件中的
OS_CPU_HOOKS_EN 設(shè)為1,OSTaskDelHook()的代碼才能生成。這樣做的好處是允許用戶移植時(shí)在不同的文件中定義鉤子函數(shù)。
10.4.4OSTaskSwHook()
OSTaskSwHook() 在μC/OS 中也不存在。從μC/OS向μC/OS-II升級(jí)時(shí),只要簡(jiǎn)單地定義一個(gè)空
函數(shù)就可以了,如程序清單L10.13所示。
程序清單L10.13 μC/OS-II中的OSTaskSwHook()函數(shù)
#ifOS_CPU_HOOKS_EN
OSTaskSwHook(void)
{
}
#endif
也還是要用編譯管理指令來(lái)處理這個(gè)函數(shù)。 只有把OS_CFG.H 文件中的OS_CPU_HOOKS_EN設(shè)為1,OSTaskSwHook() 的代碼才能生成。.
10.4.5OSTaskStatHook()
OSTaskStatHook()在μC/OS中不存在,從μC/OS向μC/OS-II升級(jí)時(shí),只要簡(jiǎn)單地定義一個(gè)空函數(shù)就可以了,如程序清單L10.14所示。
也還是要用編譯管理指令來(lái)處理這個(gè)函數(shù)。 只有把OS_CFG.H 文件中的OS_CPU_HOOKS_EN設(shè)為1,OSTaskSwHook() 的代碼才能生成。
程序清單L10.14 μC/OS-II中的OSTaskStatHook()函數(shù)
#ifOS_CPU_HOOKS_EN
OSTaskStatHook(void)
{
}
#endif
10.4.6OSTimeTickHook()
OSTimeTickHook()在μC/OS中不存在,從μC/OS向μC/OS-II升級(jí)時(shí),只要簡(jiǎn)單地定義一個(gè)空函數(shù)就可以了,如程序清單L10.15所示。
也還是要用編譯管理指令來(lái)處理這個(gè)函數(shù)。 只有把OS_CFG.H 文件中的OS_CPU_HOOKS_EN設(shè)為1,OSTimeTickHook()的代碼才能生成。
.
程序清單L10.15 μC/OS-II中的OSTimeTickHook()
#ifOS_CPU_HOOKS_EN
OSTimeTickHook(void)
{
}
#endif
10.5總結(jié)
表T10.3總結(jié)了從μC/OS向μC/OS-II.升級(jí)需要改變得地方。其中processor_name.?是μC/OS中
移植范例程序的文件名。
表 T10.3 升級(jí) μC/OS到 μC/OS-I要修改的地方