μC/OS-II在80x86上的移植
OSTaskStkInit()
OSTaskCreateHook()
OSTaskDelHook()
OSTaskSwHook()
OSTaskStatHook()
OSTimeTickHook()
實際需要修改的只有OSTaskStkInit()函數,其他五個函數需要聲明,但不一定有實際內容。這五個函數都是用戶定義的,所以OS_CPU_C.C中沒有給出代碼。如果用戶需要使用這些函數,請將文件OS_CFG.H中的#define constant OS_CPU_HOOKS_EN設為1,設為0表示不使用這些函數。
程序清單L 9.9 18.2Hz 的OSTickISR()函數.
_OSTickISRPROCFAR
;
PUSHA; 保存被中斷任務的CPU環境
PUSHES
PUSHDS
;
MOVAX,SEG_OSIntNesting;載入 DS
MOVDS,AX
;
INCBYTEPTR_OSIntNesting;標示uC/OS-II進入中斷
;
INT081H; 調用DOS的時鐘中斷處理函數
;
CALLFARPTR_OSTimeTick; 調用OSTimeTick()函數
;
CALLFARPTR_OSIntExit;標示uC/OS-IIof中斷結束
;
POPDS; 恢復被中斷任務的CPU環境
POPES
POPA
;
IRET; 返回被中斷任務
;
_OSTickISRENDP
圖F9.7 傳遞參數 pdata的堆棧初始化結構

9.05.01 OSTaskStkInit()
該函數由OSTaskCreate()或OSTaskCreateExt()調用,用來初始化任務的堆棧。初始狀態的堆棧模擬發生一次中斷后的堆棧結構。圖F9.7說明了OSTaskStkInit()初始化后的堆棧內容。請注意,圖中的堆棧結構不是調用OSTaskStkInit()任務的,而是新創建任務的。
當調用OSTaskCreate()或OSTaskCreateExt()創建一個新任務時,需要傳遞的參數是:
任務代碼的起使地址,參數指針(pdata),任務堆棧頂端的地址,任務的優先級。
OSTaskCreateExt()還需要一些其他參數,但與OSTask StkInit()沒有關系。
OSTaskStkInit()(程序清單L9.10)只需要以上提到的3個參數(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);/* 放置向函數傳遞的參數 (2)*/
*stk--=(INT16U)FP_OFF(pdata);
*stk--=(INT16U)FP_SEG(task);/* 函數返回地址(3)*/
*stk--=(INT16U)FP_OFF(task);
*stk--=(INT16U)0x0202;/*SW 設置為中斷開啟 (4)*/
*stk--=(INT16U)FP_SEG(task);/* 堆棧頂端放置指向任務代碼的指針*/
*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=當前CPU的 DS寄存器 (6)*/
return((void*)stk);
}
由于80x86堆棧是16位寬的(以字為單位)[程序清單L9.10(1)],OSTaskStkInit()將創立一個指向以字為單位內存區域的指針。同時要求堆棧指針指向空堆棧的頂端。
筆者使用的BorlandC/C++編譯器配置為用堆棧而不是寄存器來傳送參數pdata,此時參數pdata的段地址和偏移量都將被保存在堆棧中[程序清單L9.10(2)]。
堆棧中緊接著是任務函數的起始地址[程序清單L9.10(3)],理論上,此處應該為任務的返回地址,但在μC/OS-II中,任務函數必須為無限循環結構,不能有返回點。
返回地址下面是狀態字(SW)[程序清單L9.10(4)], 設置狀態字也是為了模擬中斷發生后的堆棧結構。堆棧中的SW初始化為0x0202,這將使任務啟動后允許中斷發生;如果設為0x0002,則任務啟動后將禁止中斷。需要注意的是,如果選擇任務啟動后允許中斷發生,則所有的任務運行期間中斷都允許;同樣,如果選擇任務啟動后禁止中斷,則所有的任務都禁止中斷發生,而不能有所選擇。
如果確實需要突破上述限制,可以通過參數pdata向任務傳遞希望實現的中斷狀態。如果某個任務選擇啟動后禁止中斷,那么其他的任務在運行的時候需要重新開啟中斷。同時還要修改OSTaskIdle()和OSTaskStat()函數,在運行時開啟中斷。如果以上任何一個環節出現問題,系統就會崩潰。所以筆者還是推薦用戶設置SW為0x0202,在任務啟動時開啟中斷。
堆棧中還要留出各個寄存器的空間,注意寄存器在堆棧中的位置要和運行指令PUSHA,PUSHES,和PUSHDS和壓入堆棧的次序相同。 上述指令在每次進入中斷服務程序時都會調用[程序清單L9.10(5)]。AX,BX,CX,DX,SP,BP,SI,和DI的次序是和指令PUSHA的壓棧次序相同的。如果使用沒有PUSHA指令的8086處理器,就要使用多個PUSH指令壓入上述寄存器,且順序要與PUSHA相同。 在程序清單L9.10中每個寄存器被初始化為不同的值, 這是為了調試方便。
Borland編譯器支持偽寄存器變量操作,可以用_DS關鍵字取得CPUDS寄存器的值,程序清單
L9.10中(6)標記處用_DS直接把DS寄存器拷貝到堆棧中。
堆棧初始化工作結束后,OSTaskStkInit()返回新的堆棧棧頂指針,OSTaskCreate()或
OSTaskCreateExt()將指針保存在任務的OS_TCB中。
9.05.02 OSTaskCreateHook()
OS_CPU_C.C中未定義,此函數為用戶定義。
9.05.03 OSTaskDelHook()
OS_CPU_C.C中未定義,此函數為用戶定義。
9.05.04 OSTaskSwHook()
OS_CPU_C.C中未定義,此函數為用戶定義。其用法請參考例程3。
9.05.05 OSTaskStatHook()
評論