μC/OS-II在80x86上的移植
#defineUBYTEINT8U/*在uC/OS-II中并沒有實際的用處 */
#defineWORDINT16S
#defineUWORDINT16U
#defineLONGINT32S
#defineULONGINT32U
/*
*************************************************************************
******
*INTEL80x86(實模式, 大模式編譯)
*
*方法 #1: 用簡單指令開關(guān)中斷。
* 注意,用方法1關(guān)閉中斷,從調(diào)用函數(shù)返回后中斷會重新打開!
* 注意將文件OS_CPU_A.ASM中與OSIntCtxSw()相關(guān)的常量從10改到8。
*
* 方法 #2: 關(guān)中斷前保存中斷被關(guān)閉的狀態(tài).
* 注意將文件OS_CPU_A.ASM中與OSIntCtxSw()相關(guān)的常量從8改到10。
*
*
*
*************************************************************************
******
*/
#defineOS_CRITICAL_METHOD2
#ifOS_CRITICAL_METHOD==1
#defineOS_ENTER_CRITICAL()asmCLI/* 關(guān)閉中斷*/
#defineOS_EXIT_CRITICAL()asmSTI/* 打開中斷*/
#endif
#ifOS_CRITICAL_METHOD==2
#defineOS_ENTER_CRITICAL()asm{PUSHF;CLI}/* 關(guān)閉中斷 */
#defineOS_EXIT_CRITICAL()asmPOPF/* 打開中斷 */
#endif
/*
*************************************************************************
******
*INTEL80x86(實模式, 大模式編譯)
*************************************************************************
******
*/
#defineOS_STK_GROWTH1/* 堆棧由高地址向低地址增長 (3)*/
#defineuCOS0x80/* 中斷向量0x80用于任務(wù)切換 (4)*/
#defineOS_TASK_SW()asmINTuCOS(5)
/*
*************************************************************************
******
* 全局變量
*************************************************************************
******
*/
OS_CPU_EXTINT8UOSTickDOSCtr;/* 為調(diào)用DOS時鐘中斷而定義的計數(shù)器*/
(6)*/
9.03.01 數(shù)據(jù)類型
由于不同的處理器有不同的字長,μC/OS-II的移植需要重新定義一系列的數(shù)據(jù)結(jié)構(gòu)。使用
BorlandC/C++編譯器,整數(shù)(int)類型數(shù)據(jù)為16位,長整形(long)為32位。為了讀者方便起見,盡管μC/OS-II中沒有用到浮點類型的數(shù),在源代碼中筆者還是提供了浮點類型的定義。
由于在80x86實模式中堆棧都是按字進行操作的,沒有字節(jié)操作,所以BorlandC/C++編譯器中堆棧數(shù)據(jù)類型OS_STK聲明為16位。所有的堆棧都必須用OS_STK聲明。
9.03.02 代碼臨界區(qū)
與其他實時系統(tǒng)一樣,μC/OS-II在進入系統(tǒng)臨界代碼區(qū)之前要關(guān)閉中斷,等到退出臨界區(qū)后再打開。從而保護核心數(shù)據(jù)不被多任務(wù)環(huán)境下的其他任務(wù)或中斷破壞。BorlandC/C++支持嵌入?yún)R編語句,所以加入關(guān)閉/打開中斷的語句是很方便的。μC/OS-II定義了兩個宏用來關(guān)閉/打開中斷:OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()。此處,筆者為用戶提供兩種開關(guān)中斷的方法,如下所述的方法1和方法2。作為一種測試,本書采用了方法1。當(dāng)然,您可以自由決定采用那種方法。
方法1
第一種方法,也是最簡單的方法,是直接將OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()定義為處理器的關(guān)閉(CLI)和打開(STI)中斷指令。但這種方法有一個隱患,如果在關(guān)閉中斷后調(diào)用μC/OS-II函數(shù),當(dāng)函數(shù)返回后,中斷將被打開!嚴(yán)格意義上的關(guān)閉中斷應(yīng)該是執(zhí)行OS_ENTER_CRITICAL()后中斷始終是關(guān)閉的, 方法1顯然不滿足要求。 但方法1的最大優(yōu)點是簡單,執(zhí)行速度快(只有一條指令),在此類操作頻繁的時候更為突出。如果在任務(wù)中并不在意調(diào)用函數(shù)返回后是否被中斷,推薦用戶采用方法1。此時需要將OSIntCtxSw()中的常量由10改到8(見文件OS_CPU_A.ASM)。
方法2
執(zhí)行OS_ENTER_CRITICAL()的第二種方法是先將中斷關(guān)閉的狀態(tài)保存到堆棧中,然后關(guān)閉中斷。與之對應(yīng)的OS_EXIT_CRITICAL()的操作是從堆棧中恢復(fù)中斷狀態(tài)。采用此方法,不管用戶是在中斷關(guān)閉還是允許的情況下調(diào)用μC/OS-Ⅱ中的函數(shù),在調(diào)用過程中都不會改變中斷狀態(tài)。
如果用戶在中斷關(guān)閉的情況下調(diào)用μC/OS-Ⅱ函數(shù),其實是延長了中斷響應(yīng)時間。雖然OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()可以保護代碼的臨界段。但如此用法要小心,特別
是在調(diào)用OSTimeDly()一類函數(shù)之前關(guān)閉了中斷。 此時任務(wù)將處于延時掛起狀態(tài), 等待時鐘中斷,但此時時鐘中斷是禁止的!則系統(tǒng)可能會崩潰。很明顯,所有的PEND調(diào)用都會涉及到這個問題,必須十分小心。所以建議用戶調(diào)用μC/OS-Ⅱ的系統(tǒng)函數(shù)之前打開中斷。
9.03.03 堆棧增長方向
80x86處理器的堆棧是由高地址向低地址方向增長的, 所以常量OS_STK_GROWTH必須設(shè)置為1
[程序清單L9.2(3)]。
9.03.04 OS_TASK_SW()
在 μC/OS-II中,就緒任務(wù)的堆棧初始化應(yīng)該模擬一次中斷發(fā)生后的樣子,堆棧中應(yīng)該按進
棧次序設(shè)置好各個寄存器的內(nèi)容。OS_TASK_SW()函數(shù)模擬一次中斷過程,在中斷返回的時候進
行任務(wù)切換。80x86提供了256個軟中斷源可供選用,中斷服務(wù)程序(ISR)(也稱為例外處理過
程)的入口點必須指向匯編函數(shù)OSCtxSw()(請參看文件OS_CPU_A.ASM)。
由于筆者是在PC機上測試代碼的,本章的代碼用到了中斷號128(0x80),因為此中斷號是提供給用戶使用的[程序清單L9.2(4)](PC和操作系統(tǒng)會占用一部分中斷資源—譯者注),類似的用戶可用中斷號還有0x4B到0x5B,0x5D到0x66,或者0x68到0x6F。如果用戶用的不是PC,而是其他嵌入式系統(tǒng),如80186處理器,用戶可能有更多的中斷資源可供選用。
9.03.05 時鐘節(jié)拍的發(fā)生頻率
實時系統(tǒng)中時鐘節(jié)拍的發(fā)生頻率應(yīng)該設(shè)置為10到100Hz。通常(但不是必須的)為了方便計算設(shè)為整數(shù)。不幸的是,在PC中,系統(tǒng)缺省的時鐘節(jié)拍頻率是18.20648Hz,這對于我們的計算和設(shè)置都不方便。本章中,筆者將更改PC的時鐘節(jié)拍頻率到200Hz(間隔5ms)。一方面200Hz近似18.20648Hz的11倍,可以經(jīng)過11次延時再調(diào)用DOS中斷;另一方面,在DOS中,有些操作要求時鐘間隔為54.93ms,我們設(shè)定的間隔5ms也可以滿足要求。如果您的PC機處理器是80386,時鐘節(jié)拍最快也只能到200Hz,而如果是PentiumII處理器,則達到200Hz以上沒有問題。
評論