μC/OS-II在80x86上的移植
OSTaskStkInit()
OSTaskCreateHook()
OSTaskDelHook()
OSTaskSwHook()
OSTaskStatHook()
OSTimeTickHook()
實(shí)際需要修改的只有OSTaskStkInit()函數(shù),其他五個(gè)函數(shù)需要聲明,但不一定有實(shí)際內(nèi)容。這五個(gè)函數(shù)都是用戶定義的,所以O(shè)S_CPU_C.C中沒有給出代碼。如果用戶需要使用這些函數(shù),請(qǐng)將文件OS_CFG.H中的#define constant OS_CPU_HOOKS_EN設(shè)為1,設(shè)為0表示不使用這些函數(shù)。
程序清單L 9.9 18.2Hz 的OSTickISR()函數(shù).
_OSTickISRPROCFAR
;
PUSHA; 保存被中斷任務(wù)的CPU環(huán)境
PUSHES
PUSHDS
;
MOVAX,SEG_OSIntNesting;載入 DS
MOVDS,AX
;
INCBYTEPTR_OSIntNesting;標(biāo)示uC/OS-II進(jìn)入中斷
;
INT081H; 調(diào)用DOS的時(shí)鐘中斷處理函數(shù)
;
CALLFARPTR_OSTimeTick; 調(diào)用OSTimeTick()函數(shù)
;
CALLFARPTR_OSIntExit;標(biāo)示uC/OS-IIof中斷結(jié)束
;
POPDS; 恢復(fù)被中斷任務(wù)的CPU環(huán)境
POPES
POPA
;
IRET; 返回被中斷任務(wù)
;
_OSTickISRENDP
圖F9.7 傳遞參數(shù) pdata的堆棧初始化結(jié)構(gòu)
9.05.01 OSTaskStkInit()
該函數(shù)由OSTaskCreate()或OSTaskCreateExt()調(diào)用,用來初始化任務(wù)的堆棧。初始狀態(tài)的堆棧模擬發(fā)生一次中斷后的堆棧結(jié)構(gòu)。圖F9.7說明了OSTaskStkInit()初始化后的堆棧內(nèi)容。請(qǐng)注意,圖中的堆棧結(jié)構(gòu)不是調(diào)用OSTaskStkInit()任務(wù)的,而是新創(chuàng)建任務(wù)的。
當(dāng)調(diào)用OSTaskCreate()或OSTaskCreateExt()創(chuàng)建一個(gè)新任務(wù)時(shí),需要傳遞的參數(shù)是:
任務(wù)代碼的起使地址,參數(shù)指針(pdata),任務(wù)堆棧頂端的地址,任務(wù)的優(yōu)先級(jí)。
OSTaskCreateExt()還需要一些其他參數(shù),但與OSTask StkInit()沒有關(guān)系。
OSTaskStkInit()(程序清單L9.10)只需要以上提到的3個(gè)參數(shù)(task,pdata,和ptos)。
程序清單L 9.10 OSTaskStkInit().
void*OSTaskStkInit(void(*task)(void*pd),void*pdata,void*ptos,INT16Uopt)
{
INT16U*stk;
opt=opt;/*'opt'未使用,此處可防止編譯器的警告 */
stk=(INT16U*)ptos;/* 載入堆棧指針 (1)*/
*stk--=(INT16U)FP_SEG(pdata);/* 放置向函數(shù)傳遞的參數(shù) (2)*/
*stk--=(INT16U)FP_OFF(pdata);
*stk--=(INT16U)FP_SEG(task);/* 函數(shù)返回地址(3)*/
*stk--=(INT16U)FP_OFF(task);
*stk--=(INT16U)0x0202;/*SW 設(shè)置為中斷開啟 (4)*/
*stk--=(INT16U)FP_SEG(task);/* 堆棧頂端放置指向任務(wù)代碼的指針*/
*stk--=(INT16U)FP_OFF(task);
*stk--=(INT16U)0xAAAA;/*AX=0xAAAA(5)*/
*stk--=(INT16U)0xCCCC;/*CX=0xCCCC*/
*stk--=(INT16U)0xDDDD;/*DX=0xDDDD*/
*stk--=(INT16U)0xBBBB;/*BX=0xBBBB*/
*stk--=(INT16U)0x0000;/*SP=0x0000*/
*stk--=(INT16U)0x1111;/*BP=0x1111*/
*stk--=(INT16U)0x2222;/*SI=0x2222*/
*stk--=(INT16U)0x3333;/*DI=0x3333*/
*stk--=(INT16U)0x4444;/*ES=0x4444*/
*stk=_DS;/*DS=當(dāng)前CPU的 DS寄存器 (6)*/
return((void*)stk);
}
由于80x86堆棧是16位寬的(以字為單位)[程序清單L9.10(1)],OSTaskStkInit()將創(chuàng)立一個(gè)指向以字為單位內(nèi)存區(qū)域的指針。同時(shí)要求堆棧指針指向空堆棧的頂端。
筆者使用的BorlandC/C++編譯器配置為用堆棧而不是寄存器來傳送參數(shù)pdata,此時(shí)參數(shù)pdata的段地址和偏移量都將被保存在堆棧中[程序清單L9.10(2)]。
堆棧中緊接著是任務(wù)函數(shù)的起始地址[程序清單L9.10(3)],理論上,此處應(yīng)該為任務(wù)的返回地址,但在μC/OS-II中,任務(wù)函數(shù)必須為無限循環(huán)結(jié)構(gòu),不能有返回點(diǎn)。
返回地址下面是狀態(tài)字(SW)[程序清單L9.10(4)], 設(shè)置狀態(tài)字也是為了模擬中斷發(fā)生后的堆棧結(jié)構(gòu)。堆棧中的SW初始化為0x0202,這將使任務(wù)啟動(dòng)后允許中斷發(fā)生;如果設(shè)為0x0002,則任務(wù)啟動(dòng)后將禁止中斷。需要注意的是,如果選擇任務(wù)啟動(dòng)后允許中斷發(fā)生,則所有的任務(wù)運(yùn)行期間中斷都允許;同樣,如果選擇任務(wù)啟動(dòng)后禁止中斷,則所有的任務(wù)都禁止中斷發(fā)生,而不能有所選擇。
如果確實(shí)需要突破上述限制,可以通過參數(shù)pdata向任務(wù)傳遞希望實(shí)現(xiàn)的中斷狀態(tài)。如果某個(gè)任務(wù)選擇啟動(dòng)后禁止中斷,那么其他的任務(wù)在運(yùn)行的時(shí)候需要重新開啟中斷。同時(shí)還要修改OSTaskIdle()和OSTaskStat()函數(shù),在運(yùn)行時(shí)開啟中斷。如果以上任何一個(gè)環(huán)節(jié)出現(xiàn)問題,系統(tǒng)就會(huì)崩潰。所以筆者還是推薦用戶設(shè)置SW為0x0202,在任務(wù)啟動(dòng)時(shí)開啟中斷。
堆棧中還要留出各個(gè)寄存器的空間,注意寄存器在堆棧中的位置要和運(yùn)行指令PUSHA,PUSHES,和PUSHDS和壓入堆棧的次序相同。 上述指令在每次進(jìn)入中斷服務(wù)程序時(shí)都會(huì)調(diào)用[程序清單L9.10(5)]。AX,BX,CX,DX,SP,BP,SI,和DI的次序是和指令PUSHA的壓棧次序相同的。如果使用沒有PUSHA指令的8086處理器,就要使用多個(gè)PUSH指令壓入上述寄存器,且順序要與PUSHA相同。 在程序清單L9.10中每個(gè)寄存器被初始化為不同的值, 這是為了調(diào)試方便。
Borland編譯器支持偽寄存器變量操作,可以用_DS關(guān)鍵字取得CPUDS寄存器的值,程序清單
L9.10中(6)標(biāo)記處用_DS直接把DS寄存器拷貝到堆棧中。
堆棧初始化工作結(jié)束后,OSTaskStkInit()返回新的堆棧棧頂指針,OSTaskCreate()或
OSTaskCreateExt()將指針保存在任務(wù)的OS_TCB中。
9.05.02 OSTaskCreateHook()
OS_CPU_C.C中未定義,此函數(shù)為用戶定義。
9.05.03 OSTaskDelHook()
OS_CPU_C.C中未定義,此函數(shù)為用戶定義。
9.05.04 OSTaskSwHook()
OS_CPU_C.C中未定義,此函數(shù)為用戶定義。其用法請(qǐng)參考例程3。
9.05.05 OSTaskStatHook()
評(píng)論