OSTickISR()

在9.03.05節中,我們已經提到過實時系統中時鐘節拍發生頻率的問題,應該在10到100Hz之間。但由於PC環境的特殊性,時鐘節拍由硬件產生,間隔54.93ms (18.20648Hz)。我們將時鐘節拍頻率設爲200Hz。PC時鐘節拍的中斷向量爲0x08,µC/OS-II將此向量截取,指向了µC/OS的中斷服務函數OSTickISR(),而原先的中斷向量保存在中斷129(0x81)中。爲滿足DOS的需要,原先的中斷服務還是每隔54.93ms(實際上還要短些)調用一次。圖F9.6爲安裝µC/OS-II前後的中斷向量表。
在µC/OS-II中,當調用OSStart()啓動多任務環境後,時鐘中斷的作用是非常重要的。但在PC環境下,啓動µC/OS-II之前就已經有時鐘中斷髮生了,實際上我們希望在µC/OS-II初始化完成之後再發生時鐘中斷,調用OSTickISR()。與此相關的有下述過程:

PC_DOSSaveReturn() 函數(參看PC.C):該函數由main()調用,任務是取得DOS下時鐘中斷向量,並將其保存在0x81中。

main() 函數:
	設定中斷向量0x80指向任務切換函數OSCtxSw()
	至少創立一個任務
	當初始化工作完成後調用OSStart()啓動多任務環境

第一個運行的任務:
設定中斷向量0x08指向函數OSTickISR()
將時鐘節拍頻率從18.20648改爲200Hz
在程序清單L9.6給出了函數OSTickISR()的僞碼。和µC/OS-II中的其他中斷服務程序一樣,OSTickISR()首先在被中斷任務堆棧中保存CPU寄存器的值,然後調用OSIntEnter()。µC/OS-II要求在中斷服務程序開頭調用OSIntEnter(),其作用是將記錄中斷嵌套層數的全局變量OSIntNesting加1。如果不調用OSIntEnter(),直接將OSIntNesting加1也是允許的。接下來計數器OSTickDOSCtr減1[程序清單L9.6(3)],每發生11次中斷,OSTickDOSCtr減到0,則調用DOS的時鐘中斷處理函數[程序清單L9.6(4)],調用間隔大約是54.93ms。如果不調用DOS時鐘中斷函數,則向中斷優先級控制器(PIC)發送命令清除中斷標誌。如果調用了DOS中斷,則此項操作可免,因爲在DOS的中斷程序中已經完成了。隨後,OSTickISR()調用OSTimeTick(),檢查所有處於延時等待狀態的任務,判斷是否有延時結束就緒的任務[程序清單L9.6(6)]。在OSTickISR()的最後調用OSIntExit(),如果在中斷中(或其他嵌套的中斷)有更高優先級的任務就緒,並且當前中斷爲中斷嵌套的最後一層。OSIntExit()將進行任務調度。注意如果進行了任務調度,OSIntExit()將不再返回調用者,而是用新任務的堆棧中的寄存器數值恢復CPU現場,然後用IRET實現任務切換。如果當前中斷不是中斷嵌套的最後一層,或中斷中沒有改變任務的就緒狀態,OSIntExit()將返回調用者OSTickISR(),最後OSTickISR()返回被中斷的任務。
程序清單L9.7給出了OSTickISR()的完整代碼。

程序清單L 9.6	OSTickISR()僞碼.
void OSTickISR (void)
{
    Save processor registers;	(1)
    OSIntNesting++;	(2)
    OSTickDOSCtr—-;	(3)
    if (OSTickDOSCtr == 0) {
        Chain into DOS by executing an 'INT 81H' instruction;	(4)
    } else {
        Send EOI command to PIC (Priority Interrupt Controller);	(5)
    }
    OSTimeTick();	(6)
    OSIntExit();	(7)
    Restore processor registers;	(8)
    Execute a return from interrupt instruction (IRET);	(9)
}

程序清單L9.7	OSTickISR().
_OSTickISR  PROC   FAR
;
    PUSHA                          ; 保存被中斷任務的CPU環境
    PUSH ES
    PUSH DS
;
    MOV  AX, SEG _OSTickDOSCtr     ; 載入 DS 
    MOV  DS, AX
;
    INC  BYTE PTR _OSIntNesting    ; 標示 uC/OS-II 進入中斷
;
    DEC  BYTE PTR DS:_OSTickDOSCtr
    CMP  BYTE PTR DS:_OSTickDOSCtr, 0
    JNE  SHORT _OSTickISR1         ; 每11個時鐘節拍(18.206 Hz)調用DOS時鐘中斷
;
    MOV  BYTE PTR DS:_OSTickDOSCtr, 11
    INT  081H                      ; 調用DOS時鐘中斷處理過程
    JMP  SHORT _OSTickISR2

_OSTickISR1:
    MOV  AL, 20H                   ; 向中斷優先級控制器發送命令,清除標誌位.
    MOV  DX, 20H                   ;
    OUT  DX, AL                    ; 
;
_OSTickISR2:
    CALL FAR PTR _OSTimeTick       ; 調用OSTimeTick()函數
;
    CALL FAR PTR _OSIntExit        ; 標示uC/OS-II退出中斷
;
    POP  DS                        ; 恢復被中斷任務的CPU環境
    POP  ES
    POPA
;
    IRET                           ; 返回被中斷任務
;
_OSTickISR  ENDP

如果不更改DOS下的時鐘中斷頻率(保持18.20648 Hz),OSTickISR()函數還可以簡化。程序清單L9.8爲18.2 Hz的OSTickISR()函數的僞碼。同樣,函數開頭要保存所有的CPU寄存器[程序清單L9.8(1)],將OSIntNesting加1[程序清單L9.8(2)]。接下來調用DOS的時鐘中斷處理過程[程序清單L9.8(3)],此處就不需要清除中斷優先級控制器的操作了,因爲DOS的時鐘中斷處理中包含了這一過程。然後調用OSTimeTick()檢查任務的延時是否結束[程序清單L9.8(4)],最後調用OSIntExit()[程序清單L9.8(5)]。結束部分是恢復CPU寄存器的內容[程序清單L9.8(6)],執行IRET指令返回被中斷的任務。如果採用8.2 Hz的OSTickISR()函數,系統初始化過程就不用調用PC_SetTickRate(),同時將文件OS_CFG.H中的常量OS_TICKS_PER_SEC由200改爲18。
程序清單L9.9給出了18.2 Hz OSTickISR()的完整代碼。

程序清單L 9.8	18.2Hz OSTickISR()僞碼.
void OSTickISR (void)
{
    Save processor registers;	(1)
    OSIntNesting++;	(2)
    Chain into DOS by executing an 'INT 81H' instruction;	(3)
    OSTimeTick();	(4)
    OSIntExit();	(5)
    Restore processor registers;	(6)
    Execute a return from interrupt instruction (IRET);	(7)
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章