版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、<p> 移植μC/OS-II</p><p> 這篇文章介紹如何將μC/OS-II移植到不同的處理器上。所謂移植,就是使一個(gè)實(shí)時(shí)內(nèi)核能在其他的微處理器上運(yùn)行。為了方便移植,大部分μC/OS-II的代碼是用C語言編寫的:但是,仍需要用C語言和匯編語言編寫一些與處理器硬件相關(guān)的代碼,這是因?yàn)棣藽/OS-II在讀/寫處理器寄存器時(shí),只能通過匯編語言來實(shí)現(xiàn)。由于μC/OS-II在設(shè)計(jì)前就已經(jīng)考慮了可移植性
2、,所以它的移植相對(duì)來說是比較容易的。要使μC/OS-II正常運(yùn)行,處理器必須滿足以下要求:</p><p> (1) 處理器的C編譯器能產(chǎn)生可重入型代碼:</p><p> (2) 處理器支持中斷,并且能產(chǎn)生定時(shí)中斷(通常為10-100Hz);</p><p> (3) 用C語言就可以開關(guān)中斷;</p><p> (4) 處理器能支持
3、一定數(shù)量的數(shù)據(jù)存儲(chǔ)器的硬件堆棧;</p><p> (5) 處理器有將堆棧指針以及其他CPU寄存器的內(nèi)容讀出、并存儲(chǔ)到堆?;騼?nèi)存中去的指令;</p><p> 如果已經(jīng)了解處理器和C編譯器的技術(shù)細(xì)節(jié),那么移植的工作是非常容易的,測(cè)試一個(gè)像μC/OS-II這樣的實(shí)時(shí)內(nèi)核其實(shí)并不復(fù)雜,甚至可以在沒有任何應(yīng)用程序下測(cè)試,換句話說,就是讓內(nèi)核自己測(cè)試自己。有兩種原因要這樣做:第一,避免使本來就
4、復(fù)雜的事情變的更加復(fù)雜化;第二,如果出現(xiàn)問題可以知道問題出在內(nèi)核代碼中,而不是應(yīng)用程序中。剛開始時(shí),可以運(yùn)行一些簡(jiǎn)單的任務(wù)和時(shí)鐘節(jié)拍中斷程序。一旦多任務(wù)調(diào)度成功運(yùn)行了,再添加應(yīng)用程序的任務(wù)就更加容易了。</p><p><b> 1.1 開發(fā)工具</b></p><p> 如前所述移植μC/OS-II需要標(biāo)準(zhǔn)的C交叉編譯器,并且是針對(duì)所使用的CPU的;因?yàn)樗且?/p>
5、個(gè)可剝奪的內(nèi)核,只能通過C編譯器來產(chǎn)生可重入型代碼。同時(shí)C編譯器還要支持匯編語言程序。絕大部分為嵌入式系統(tǒng)設(shè)計(jì)的C編譯器都包括匯編器、鏈接器、定位器。鏈接器用來將不同的模塊(編譯過或匯編過的文件)鏈接成目標(biāo)文件;定位器則允許將代碼和數(shù)據(jù)放置在目標(biāo)處理器的指定內(nèi)存空間中。</p><p> 所用的C編譯器還提供另一種機(jī)制,能在C編譯器中開中斷和關(guān)中斷。一些編譯器允許在C語言源代碼中直接插入?yún)R編語句,這就使得插入相
6、應(yīng)的處理器中的指令開中斷和關(guān)中斷變得容易了。</p><p><b> 1.2 文件</b></p><p> (1)INCLUDES.H文件</p><p> INCLUDES.H是一個(gè)頭文件,它出現(xiàn)在每個(gè).C文件的第一行,如下:</p><p> # include “ includes.h ”<
7、/p><p> INCLUDES.H文件使得工程項(xiàng)目中的每個(gè).C文件無需分別考慮它實(shí)際上需要哪些頭文件。使用INCLUDES.H文件的唯一缺點(diǎn)就是它可能包含一些與當(dāng)前要編譯的.C文件實(shí)際上不相干的頭文件。這意味著每個(gè)文件的編譯時(shí)間都會(huì)增加;但由于他增加了代碼的可移植性,所以還是決定使用這種方法。也可以通過重新編譯INCLUDES.H文件來增加頭文件,但是頭文件必須添加在文件列表的最后。</p><
8、;p> (2) OS_CPU.H文件</p><p> OS_CPU.H包含了用#define語句定義的、與處理器相關(guān)的常數(shù)、宏以及類型。OS_CPU.H文件的大體結(jié)構(gòu)如程序清單T1所列:</p><p> #ifdef OS_CPU_GLOBALS</p><p> #define OS_CPU_EXT</p><p>&l
9、t;b> #else</b></p><p> #define OS_CPU_EXT extern</p><p><b> #endif</b></p><p> typedef unsigned char BOOLEAN;</p><p> typedef unsigned char
10、 INT8U;/* 無符號(hào)8位整數(shù)*/</p><p> typedef signed char INT8S;/* 有符號(hào)8位整數(shù)*/</p><p> typedef unsigned int INT16U;/* 無符號(hào)16位整數(shù)*/</p><p> typedef signed int INT16S;
11、/* 有符號(hào)16位整數(shù)*/</p><p> typedef unsigned long INT32U;/* 無符號(hào)32位整數(shù) */</p><p> typedef signed long INT32S;/* 有符號(hào)32位整數(shù)*/</p><p> typedef float FP32;
12、/* 單精度浮點(diǎn)數(shù) */</p><p> typedef double FP64;/* 雙精度浮點(diǎn)數(shù) */</p><p> typedef unsigned int OS_STK;/* 堆棧入口寬度為16位*/</p><p> #define OS_ENTER_CRITICAL() ???/* 關(guān)
13、中斷*/</p><p> #define OS_EXIT_CRITICAL() ??? /* 開中斷s */ </p><p> #define OS_STK_GROWTH 1 /* 定義堆棧方向:1=向下遞減,0=向上遞增 */</p><p> #define OS_TASK_SW()
14、 ??? </p><p><b> 程序清單 T1</b></p><p> ?、?OS_CPU.H,與編譯器相關(guān)的數(shù)據(jù)類型</p><p> 因?yàn)椴煌奈⑻幚砥饔胁煌淖珠L(zhǎng),所以μC/OS-II的移植包括了一系列的數(shù)據(jù)類型的定義,而確保其可移植性
15、。尤其是,μC/OS-II代碼從不使用C語言中的 short, int 及l(fā)ong等數(shù)據(jù)類型,因?yàn)樗鼈兪桥c編譯器相關(guān)的,是不可移植的。相反,定義的數(shù)據(jù)結(jié)構(gòu)等既是可移植的,又很直觀。</p><p> 舉例來說,INT16U數(shù)據(jù)類型總是代表16位的無符號(hào)整型數(shù)。這樣μC/OS-II就可以斷定,聲明為該數(shù)據(jù)類型變量的范圍都是0~65535。將μC/OS-II移植到32位的處理器上,就意味著INT16U實(shí)際被聲明為無
16、符號(hào)短整型數(shù),而不是無符號(hào)整數(shù),但是,μC/OS-II處理的仍然是INT16U。</p><p> 你必須將任務(wù)堆棧的數(shù)據(jù)類型告訴μC/OS-II。這是通過為OS_STK聲明恰當(dāng)?shù)腃數(shù)據(jù)類型來實(shí)現(xiàn)的。如果處理器的堆棧是32位的,那么就應(yīng)該將OS_STK聲明:為:unsigned int,所有的任務(wù)堆棧都必須聲明使用OS_STK作為它的數(shù)據(jù)類型。</p><p> 用戶需要做的只是查閱編
17、譯器文檔,找出對(duì)應(yīng)于μC/OS-II的標(biāo)準(zhǔn)的C的相應(yīng)數(shù)據(jù)類型。</p><p> ?、?OS_CPU.H,OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()</p><p> 像其它的實(shí)時(shí)內(nèi)核一樣,μC/OS-II需要先關(guān)中斷再處理臨界段代碼,并且在處理完畢后再重新開中段。這就能夠保證臨界段代碼免受多任務(wù)或中斷服務(wù)子程序的破壞。通常每個(gè)處理器都會(huì)提供一定的匯編
18、指令來開關(guān)中斷,C編譯器必須有一定的機(jī)制直接從C語言中執(zhí)行這些操作。有些編譯器允許在C源代碼中直接加入?yún)R編語句,這就使得插入處理器指令來開關(guān)中斷變的容易,有些其它的編譯器提供語言擴(kuò)展功能,可以直接從C語言中開關(guān)中斷。為了隱藏編譯器廠商提供的不同實(shí)現(xiàn)方法,以增加可移植性,μC/OS-II定義了2個(gè)宏,用來關(guān)開中斷:OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL(),如T1:</p><p>
19、; 它們都是成對(duì)出現(xiàn)的,分別加在臨界段代碼的前面和后面;</p><p> µC/OS-II Service Function</p><p><b> {</b></p><p> OS_ENTER_CRITICAL();</p><p><b> /*臨界段代碼*/</b>&
20、lt;/p><p> OS_EXIT_CRITICAL();</p><p><b> }</b></p><p><b> T1</b></p><p><b> 方法一:</b></p><p> 實(shí)現(xiàn)OS_ENTER_CRITICAL()和O
21、S_EXIT_CRITICAL()這兩個(gè)宏的這種方法是最簡(jiǎn)單的方法,在中調(diào)用處理器指令關(guān)中斷,以及在中調(diào)用相應(yīng)處理器指令開中斷;但是這個(gè)過程還存在小小的問題:如果在禁止中斷的情況下調(diào)用μC/OS-II函數(shù),那么從μC/OS-II函數(shù)返回時(shí),中斷可能會(huì)變成允許的了。而實(shí)際上如果調(diào)用μC/OS-II之前中斷是關(guān)掉的希望從μC/OS-II函數(shù)返回時(shí),希望中斷還是關(guān)掉的。在這種情況下,僅靠這種方法是不適宜的。</p><p&
22、gt;<b> 方法二:</b></p><p> 執(zhí)行OS_ENTER_CRITICAL()時(shí),先將中斷狀態(tài)保存到堆棧中,然后關(guān)中斷;而當(dāng)執(zhí)行OS_EXIT_CRITICAL()時(shí),再從堆棧中恢復(fù)原來的中斷開關(guān)狀態(tài)。如果用這種方法,那么不管用戶是在中斷禁止,還是中斷允許的情況下調(diào)用μC/OS-II的功能函數(shù),調(diào)用后都不會(huì)改變中斷狀態(tài)。應(yīng)用程序可以調(diào)用OS_ENTER_CRITICAL(
23、)和OS_EXIT_CRITICAL(),以保護(hù)臨界段代碼;但是,在使用這種方法時(shí)需特別小心,因?yàn)槿绻谡{(diào)用像OSTimeDly()之類的功能函數(shù)之前就關(guān)掉了中斷,應(yīng)用程序就會(huì)崩潰。發(fā)生這種情況的原因是,任務(wù)被掛起,知道延遲時(shí)間到,而中斷是關(guān)掉的。OSTimeDly()實(shí)際上是依靠時(shí)鐘節(jié)拍實(shí)現(xiàn)中斷的,而因?yàn)橹袛嗍顷P(guān)掉的,程序不可能獲得時(shí)鐘節(jié)拍中斷。明顯的,所有的PEND調(diào)用都會(huì)涉及到這個(gè)問題,需十分小心。一個(gè)通用的辦法是,應(yīng)該在中斷允許
24、的情況下調(diào)用μC/OS-II的系統(tǒng)功能函數(shù)。</p><p> ?、?OS_CPU.H, OS_STK_GROWTH</p><p> 絕大多數(shù)微處理器和微控制器的堆棧都是從上往下遞減的,但是也有某些處理器使用的是相反的方式,μC/OS-II被設(shè)計(jì)成對(duì)這兩種情況都可以處理,只要再用配置常數(shù)OS_STK_GROWTH指定堆棧的方向就可以了:</p><p> 置O
25、S_STK_GROWTH為0,表示堆棧從下(低地址)往上(高地址)遞增:</p><p> 置OS_STK_GROWTH為1,表示堆棧從上(高地址)往下(低地址)遞減。</p><p> ?、?OS_CPU.H, OS_TASK_SW()</p><p> OS_TASK_SW()是一個(gè)宏,是在μC/OS-II從低優(yōu)先級(jí)任務(wù)切換到高優(yōu)先級(jí)任務(wù)時(shí)須用到的。OS_T
26、ASK_SW()總是在任務(wù)級(jí)代碼中被調(diào)用。另一個(gè)函數(shù)OSIntExit()用在中斷服務(wù)子程序ISR中。任務(wù)切換只是簡(jiǎn)單地將處理器的寄存器保存到將被掛起的任務(wù)的堆棧中,并且從堆棧中恢復(fù)要運(yùn)行的更高優(yōu)先級(jí)的任務(wù)。</p><p> 在μC/OS-II中,處于就緒態(tài)任務(wù)的堆棧結(jié)構(gòu)看起來就像剛剛發(fā)生過中斷一樣,所有的寄存器都保存在堆棧中。換句話說,μC/OS-II要運(yùn)行處于就緒態(tài)的任務(wù)必須要做的事是,從任務(wù)堆棧中恢復(fù)所
27、有的寄存器,并且執(zhí)行中斷返回指令。為了任務(wù)調(diào)度,可以通過執(zhí)行OS_TASK_SW()模仿中斷的產(chǎn)生。絕大多數(shù)處理器會(huì)提供軟中斷或指令陷阱來完成這項(xiàng)功能。中斷服務(wù)子程序或指令陷阱處理函數(shù)(也叫做異常處理函數(shù))的中斷向量地址必須指向匯編語言函數(shù)OSCtxSw()。</p><p> 例如,在Intel或者AMD80X86處理器上可以使用INT指令,但是中斷向量必須指向OSCtxSw()。有些處理器如Z80,并不提供
28、軟中斷機(jī)制。在這種情況下需要想辦法將堆棧結(jié)構(gòu)設(shè)置成與軟中斷發(fā)生后的堆棧結(jié)構(gòu)一樣。在OS_TASK_SW()函數(shù)中調(diào)用OSCtxSw(),而不是將某個(gè)中斷向量指向OSCtxSw()。實(shí)際上μC/OS-II已經(jīng)被移植到了Z80處理器上,μC/OS-II也同樣是可以的。</p><p> (3) OS_CPU_A.ASM</p><p> μC/OS-II的移植實(shí)例要求用戶編寫4個(gè)簡(jiǎn)單的匯編
29、程序:</p><p> OSStartHighRdy()</p><p><b> OSCtxSw()</b></p><p> OSIntCtxSw()</p><p> OSTickISR()</p><p> 如果編譯器支持插入行匯編代碼,就可以將所有與處理器相關(guān)的代碼放到OS_
30、CPU.C文件中,而不必再有單獨(dú)的匯編語言文件。</p><p> OS_CPU_A.ASM, OSStartHighRdy()</p><p> OSStart()函數(shù)調(diào)用OSStartHighRdy()來使就緒態(tài)任務(wù)中優(yōu)先級(jí)最高的任務(wù)開始運(yùn)行,在調(diào)用它之前,要已經(jīng)建立了至少一個(gè)應(yīng)用任務(wù)。OSStartHighRdy()假設(shè)OSTCBHighRdy指向最高優(yōu)先級(jí)任務(wù)的任務(wù)控制塊。就像
31、先前提到的,在μC/OS-II中處于就緒態(tài)任務(wù)的堆棧結(jié)構(gòu)看起來就像剛發(fā)生過中斷一樣,所有的寄存器都保存在堆棧中。要想運(yùn)行最高優(yōu)先級(jí)任務(wù),需將所有處理器按順序從任務(wù)堆棧中恢復(fù)出來,并且執(zhí)行中斷返回指令。為簡(jiǎn)單起見,堆棧指針總是存儲(chǔ)字任務(wù)控制塊的開頭。換句話說,也就是需要恢復(fù)的任務(wù)堆棧指針總是存儲(chǔ)在任務(wù)控制塊的偏移地址為0的位置。</p><p> 注意到OSStartHighRdy()必須調(diào)用OSTaskSwHo
32、ok()函數(shù),但OSStartHighRdy()函數(shù)只是做了任務(wù)切換工作的一半——只是完成了高優(yōu)先級(jí)任務(wù)寄存器的恢復(fù),而并沒有保存當(dāng)前任務(wù)的寄存器。OSTaskSwHook()函數(shù)必須檢查OSRunning位,以確定OSTaskSwHook()函數(shù)是被OSStartHighRdy()調(diào)用的(OSRunning是FALSE),還是在正常的任務(wù)切換之中(OSRunning是TRUE)被調(diào)用的。</p><p> O
33、S_CPU_A.ASM, OSCtxSw()</p><p> 任務(wù)級(jí)的切換是通過執(zhí)行軟中段指令,或者依據(jù)處理器的不同,執(zhí)行TRAP指令來實(shí)現(xiàn)的。中斷服務(wù)子程序,陷阱或異常處理的向量地址必須指向OSCtxSw()。</p><p> 如果當(dāng)前任務(wù)調(diào)用μC/OS-II提供的功能函數(shù),并使得更高優(yōu)先級(jí)任務(wù)進(jìn)入了就緒態(tài),在系統(tǒng)服務(wù)調(diào)用的最后,μC/OS-II會(huì)調(diào)用OSSched(),并由此推
34、斷出當(dāng)前任務(wù)不是需要運(yùn)行的最重要的任務(wù)了,OSSched()先將最高優(yōu)先級(jí)任務(wù)的地址裝載到OSTCBHighRdy,再通過調(diào)用OS_TASK_SW()執(zhí)行軟中斷或陷阱指令。注意變量OSTCBCur已經(jīng)包含了指向當(dāng)前任務(wù)控制塊的指針。軟中斷指令會(huì)強(qiáng)制將處理器的一些寄存器保存到當(dāng)前任務(wù)的堆棧中并使處理器執(zhí)行OSCtxSw()。</p><p> OSCtxSw()示意性代碼如T2,這些代碼必須用匯編語言編寫,因?yàn)橛?/p>
35、戶不能直接在C語言中訪問CPU寄存器。</p><p> void OSCtxSw(void)</p><p><b> {</b></p><p><b> 保存處理器寄存器;</b></p><p> 在當(dāng)前任務(wù)的任務(wù)控制塊中保存當(dāng)前任務(wù)的堆棧指針:</p><p&g
36、t; OSTCBCur->OSTCBStkPtr = Stack pointer;</p><p> Call user definable OSTaskSwHook();</p><p> OSTCBCur = OSTCBHighRdy; </p><p> OSPrioCur = OSPrioHighRdy;</p><p&
37、gt; 得到將要重新開始運(yùn)行的任務(wù)的堆棧指針:</p><p> Stack pointer = OSTCBHighRdy->OSTCBStkPtr;</p><p> 從新任務(wù)的任務(wù)堆棧中恢復(fù)處理器所有寄存器的值;</p><p> 執(zhí)行中斷返回指令; </p><p><b> }</b></
38、p><p> T2 OSCtxSw()的示意性代碼</p><p> OS_CPU_A.ASM, OSIntCtxSw()</p><p> OSIntExit()通過調(diào)用OSIntCtxSw(),在ISR中執(zhí)行任務(wù)切換功能。因?yàn)镺SIntCtxSw()是在ISR中被調(diào)用的,所以假定所有的處理器都被正確地保存到了被中斷任務(wù)的堆棧之中。OSIntCtxSw()的示
39、意性代碼如T3所示,這些代碼必須用匯編語言編寫,因?yàn)樵贑語言中不能直接訪問CPU寄存器。如果編譯器支持插入?yún)R編語言代碼,就可以將OSIntCtxSw()的代碼放在OS_CPU_C.C文件中,而不放在OS_CPU_A.ASM文件中。實(shí)際上如果需要,可以跳轉(zhuǎn)到OSCtxSw()中相同的代碼,以減少代碼量。</p><p> void OSIntCtxSw(void)</p><p><
40、b> {</b></p><p> 調(diào)用用戶定義的 OSTaskSwHook();</p><p> OSTCBCur = OSTCBHighRdy;</p><p> OSPrioCur = OSPrioHighRdy;</p><p> 得到將要重新執(zhí)行任務(wù)的堆棧指針:</p><p>
41、; Stack pointer = OSTCBHighRdy->OSTCBStkPtr;</p><p> 從新任務(wù)堆棧中恢復(fù)所有處理器寄存器;</p><p><b> 執(zhí)行中斷返回指令;</b></p><p><b> }</b></p><p> T3 OSIntCtxSw
42、()的示意性代碼</p><p> ④ OS_CPU_A.ASM, OSTickISR()</p><p> μC/OS-II要求用戶提供一個(gè)周期性的時(shí)鐘源,來實(shí)現(xiàn)時(shí)間的延遲和超時(shí)功能。時(shí)鐘節(jié)拍應(yīng)該每秒發(fā)生10~100次/秒。為了完成該任務(wù),可以使用硬件定時(shí)器,也可以從交流點(diǎn)中獲得50/60Hz的時(shí)鐘頻率。</p><p> 必須在開始多任務(wù)后,即調(diào)用OSSt
43、art()后,啟動(dòng)時(shí)鐘節(jié)拍中斷;然后,可以在OSStart()運(yùn)行后,μC/OS-II啟動(dòng)運(yùn)行的第一個(gè)任務(wù)中初始化節(jié)拍中斷。通常容易犯的錯(cuò)誤是,在調(diào)用OSInit()和OSStart()之間打開了時(shí)鐘節(jié)拍。(如程序清單T4所列)。 </p><p> void main(void)</p><p><b> {</b></p><p>
44、OSInit(); /* 初始化 μC/OS-II */</p><p> /* 應(yīng)用程序初始化代碼 */</p><p> /* 調(diào)用 OSTaskCreate() 建立至少1個(gè)任務(wù) */</p><p> 開時(shí)鐘節(jié)拍中斷; /* 千萬不要在這里開中斷 */</p>
45、<p> OSStart(); /* 開始多任務(wù) */</p><p><b> }</b></p><p> T4 在不正確的位置啟動(dòng)節(jié)拍中斷</p><p> Porting µC/OS-II</p><p> This ar
46、ticle describes in general terms what needs to be done in order to adapt µC/OS-II to different processors. Adapting a real-time kernel to a microprocessor or a microcontroller is called a port. Most of µC/OS-II
47、 is written in C for portability, however, it is still necessary to write some processor specific code in C and assembly language. Specifically, µC/OS-II manipulates processor registers which can only be done throu
48、gh assembly language. Porting µC/OS-II to different processors is re</p><p> A processor can run µC/OS-II if it satisfies the following general requirements:</p><p> (1) You must hav
49、e a C compiler for the processor and the C compiler must be able to produce reentrant code. </p><p> (2) You must be able to disable and enable interrupts from C.</p><p> (3) The processor mus
50、t support interrupts and you need to provide an interrupt that occurs at regular intervals (typically between 10 to 100 Hz).</p><p> (4) The processor must support a hardware stack, and the processor must b
51、e able to store a fair amount of data on the stack (possibly many Kbytes).</p><p> (5) The processor must have instructions to load and store the stack pointer and other CPU registers either on the stack or
52、 in memory.</p><p> Porting µC/OS-II is actually quite straightforward once you understand the subtleties of the target processor and the C compiler you will be using. Depending on the processor, a por
53、t can consist of writing or changing between 50 and 300 lines of code! Porting µC/OS-II could take you anywhere between a few hours to about a week.</p><p> Once you have a port of µC/OS-II for yo
54、ur processor, you will need to verify its operation. Testing a multitasking real-time kernel such as µC/OS-II is not as complicated as you may think. You should test your port without application code. In other word
55、s, test the operations of the kernel by itself. There are two reasons to do this. First, you don’t want to complicate things anymore than they need to be. Second, if something doesn’t work, you know that the problem lies
56、 in the port as opposed to</p><p> 1.1 Development Tools</p><p> As previously stated, you need a C compiler for the processor you intend to use in order to port µC/OS-II. Because µ
57、C/OS-II is a preemptive kernel, you should only use a C compiler that generates reentrant code. Your C compiler must also be able to support assembly language programming. Most C compiler designed for embedded systems wi
58、ll, in fact, also include an assembler, a linker, and a locator. The linker is used to combine object files (compiled and assembled files) from different modules wh</p><p> 1.2 Files</p><p>
59、(1) INCLUDES.H </p><p> INCLUDES.H is a MASTER include file and is found at the top of all .C files as follows:</p><p> # include “includes.h”</p><p> INCLUDES.H allows every .
60、C file in your project to be written without concerns about which header file will actually be needed. The only drawback to having a master include file is that INCLUDES.H may include header files that are not pertinent
61、to the actual .C file being compiled. This means that each file will require extra time to compile. This inconvenience is offset by code portability. You can edit INCLUDES.H to add your own header files but, your header
62、 files should be added at the end o</p><p> (2) OS_CPU.H</p><p> OS_CPU.H contains processor and implementation specific #defines constants, macros, and typedefs. The general layout of OS_CPU
63、.H is shown in listing </p><p> #ifdef OS_CPU_GLOBALS</p><p> #define OS_CPU_EXT</p><p><b> #else</b></p><p> #define OS_CPU_EXT extern</p><
64、;p><b> #endif</b></p><p> typedef unsigned char BOOLEAN;</p><p> typedef unsigned char INT8U;/* Unsigned 8 bit quantity*/ (1)</p><p> typedef signed c
65、har INT8S;/* Signed 8 bit quantity*/</p><p> typedef unsigned int INT16U;/* Unsigned 16 bit quantity*/</p><p> typedef signed int INT16S;/* Signed 16 bit quantity*/</p&
66、gt;<p> typedef unsigned long INT32U;/* Unsigned 32 bit quantity*/</p><p> typedef signed long INT32S;/* Signed 32 bit quantity*/</p><p> typedef float FP32;/*Singl
67、e precision floating point*/ (2)</p><p> typedef double FP64;/* Double precision floating point */</p><p> typedef unsignedint OS_STK;/*Each stack entryis 16-bit wide*/</p>&
68、lt;p> #define OS_ENTER_CRITICAL() ??? /* Disable interrupts*/ (3)</p><p> #define OS_EXIT_CRITICAL() ??? /* Enable interrupts*/ </p><p> #define OS_STK_GROWTH 1 /* De
69、fine stack growth: 1 = Down, 0 = Up*/ (4)</p><p> #define OS_TASK_SW() ??? </p><p> ?、貽S_CPU.H, Compiler Specific Data Types </p><p> Because different microprocessor
70、s have different word length, the port of µC/OS-II includes a series of type definitions that ensures portability. Specifically, µC/OS-II’s code never makes use of C’s short, int and, long data types because th
71、ey are inherently non-portable. Instead, I defined integer data types that are both portable and intuitive </p><p> The INT16U data type, for example, always represents a 16-bit unsigned integer. µC/O
72、S-II and your application code can now assume that the range of values for variables declared with this type is from 0 to 65535. A µC/OS-II port to a 32-bit processor could mean that an INT16U is actually declared a
73、s an unsigned short instead of an unsigned int. Where µC/OS-II is concerned, however, it still deals with an INT16U.</p><p> You must tell µC/OS-II the data type of a task’s stack. This is done b
74、y declaring the proper C data type for OS_STK. If stack elements on your processor are 32-bit and your compiler documentation specify that an int is 32-bit then, you would declare OS_STK as being of type unsigned int. Al
75、l task stacks MUST be declared using OS_STK as its data type.</p><p> All you have to do is to consult the compiler’s manual and find the standard C data types that corresponds to the types expected by
76、1;C/OS-II.</p><p> ②OS_CPU.H, OS_ENTER_CRITICAL() and OS_EXIT_CRITICAL()</p><p> µC/OS-II like all real-time kernels need to disable interrupts in order to access critical sections of co
77、de, and re-enable interrupts when done. This allows µC/OS-II to protect critical code from being entered simultaneously from either multiple tasks or Interrupt Service Routines (ISRS). Every processor generally prov
78、ide instructions to disable/enable interrupts and your C compiler must have a mechanism to perform these operations directly from C. Some compilers will allow you to insert in-line</p><p> µC/OS-II’s c
79、ritical sections are wrapped with OS_ENTER_CRITICAL() and OS_EXIT_CRITICAL() as shown below:</p><p> µC/OS-II Service Function</p><p><b> {</b></p><p> OS_ENTER_
80、CRITICAL(); /* µC/OS-II critical code section */</p><p> OS_EXIT_CRITICAL();</p><p><b> }</b></p><p><b> T1</b></p><p> Method
81、 #1:</p><p> The first and simplest way to implement these two macros is to invoke the processor instruction to disable interrupts for OS_ENTER_CRITICAL() and the enable interrupts instruction for OS_EXIT_C
82、RITICAL(). There is, however, a little problem with this scenario. If you called the µC/OS-II function with interrupts disabled then, upon return from µC/OS-II, interrupts would be enabled! If you had interrupt
83、s disabled, you may have wanted them to be disabled upon return from the µC/OS-II function. In th</p><p> Method #2:</p><p> The second way to implement OS_ENTER_CRITICAL() is to save the
84、 interrupt disable status onto the stack and then, disable interrupts. OS_EXIT_CRITICAL() would simply be implemented by restoring the interrupt status from the stack. Using this scheme, if you called a µC/OS-II ser
85、vice with either interrupts enabled or disabled then, the status would be preserved across the call.Your application can use OS_ENTER_CRITICAL()and OS_EXIT_CRITICAL() to also protect critical sections of code. Be careful
86、, h</p><p> ?、?OS_CPU.H, OS_STK_GROWTH</p><p> The stack on most microprocessors and microcontrollers grows from high-memory to low-memory. There are, however, some processors that work the oth
87、er way around. µC/OS-II has been designed to be able to handle either flavor. This is accomplished by specifying to µC/OS-II which way the stack grows through the configuration constant OS_STK_GROWTH as shown
88、below:</p><p> Set OS_STK_GROWTH to 0 for Low to High memory stack growth.</p><p> Set OS_STK_GROWTH to 1 for High to Low memory stack growth.</p><p> ④ OS_CPU.H, OS_TASK_SW()<
89、;/p><p> OS_TASK_SW() is a macro that is invoked when µC/OS-II switches from a low-priority task to the highest-priority task. OS_TASK_SW() is always called from task level code. Another mechanism, OSIntE
90、xit(), is used to perform a context switch when an ISR makes a higher priority task ready for execution. A context switch simply consist of saving the processor registers on the stack of the task being suspended, and res
91、toring the registers of the higher-priority task from its stack.</p><p> In µC/OS-II, the stack frame for a ready task always looks as if an interrupt has just occurred and all processor registers were
92、 saved onto it. In other words, all that µC/OS-II has to do to run a ready task is to restore all processor registers from the task’s stack and execute a return from interrupt. To switch context, you should implemen
93、t OS_TASK_SW() so that you simulate an interrupt. Most processors provide either software interrupt or TRAP instructions to accomplish this. The ISR or trap </p><p> For example, a port for an Intel or AMD
94、80x86 processor would use an INT instruction. The interrupt handler would need to vector to OSCtxSw(). There are some processors like the Zilog Z80 that do not provide a software interrupt mechanism. In this case, you wo
95、uld need to simulate the stack frame as closely to an interrupt stack frame as you can. In this case, OS_TASK_SW() would simply call OSCtxSw() instead of vector to it. The Z80 is a processor that has been ported to µ
96、;C/OS and thus would be p</p><p> (3)OS_CPU_A.ASM</p><p> A µC/OS-II port requires that you write four fairly simple assembly language functions:</p><p> OSStartHighRdy()&l
97、t;/p><p><b> OSCtxSw()</b></p><p> OSIntCtxSw()</p><p> OSTickISR()</p><p> If your compiler supports in-line assembly language code, you could actually pl
98、ace all the processor specific code into OS_CPU_C.C instead of having a separate assembly language file.</p><p> ?、貽S_CPU_A.ASM, OSStartHighRdy()</p><p> This function is called by OSStart() t
99、o start the highest priority task ready-to-run. Before you can call OSStart(), however, you MUST have created at least one of your tasks. OSStartHighRdy() assumes that OSTCBHighRdy points to the task control block of
100、 the task with the highest priority. As mentioned previously, in µC/OS-II, the stack frame for a ready task always looks as if an interrupt has just occurred and all processor registers were saved onto it. To run th
101、e highest priority task all</p><p> Note that OSStartHighRdy() MUST call OSTaskSwHook() because we are basically doing a ‘half’ context switch – we are restoring the registers of the highest priority task.
102、 OSTaskSwHook() can examine OSRunning to tell it whether OSTaskSwHook() was called from OSStartHighRdy() (i.e. if OSRunning is FALSE) or from a regular context switch (i.e. OSRunning is TRUE).</p><p> ②OS_
103、CPU_A.ASM, OSCtxSw()</p><p> As previously mentioned, a task level context switch is accomplished by issuing a software interrupt instruction or, depending on the processor, executing a TRAP instruction. T
104、he interrupt service routine, trap or exception handler MUST vector to OSCtxSw().</p><p> The current task calls a service provided by µC/OS-II which causes a higher priority task to be ready-to-run. A
105、t the end of the service call, µC/OS-II calls the function OSSched() which concludes that the current task is no longer the most important task to run. OSSched() loads the address of the highest priority task into O
106、STCBHighRdy and then executes the software interrupt or trap instruction by invoking the macro OS_TASK_SW(). Note that the variable OSTCBCur already contains a pointer to the</p><p> The pseudo code of what
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 眾賞文庫僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
評(píng)論
0/150
提交評(píng)論