在中斷中執行的程式片段,必需要愈短愈好,以避免在執行中遇到並阻礙了其它的硬體中斷之即時執行。為達成這個目標,程式規畫時必需要分析中斷事件促成的後續處理工作中,那些是愈快愈好(即軟即時Soft Real Time),那一段是限期完成(即硬即時Hard Real Time)。其中只有軟即時段是必需要在中斷中執行。其它工作則只要有機制能夠偵測到中斷事件發生,接續硬體中斷後處理,並且在下一次中斷事件發生前完成工作即可。因此在中斷服務常式中應該執行以下動作
• 軟即時工作:中斷事件計數,旗標輸出,旗標輸入,暫存器輸出,暫存器輸入。
• 接續後續硬即時工作準備:可被動或主動通知後處理程式。
◦ 被動:提供標示變數或則中斷事件計數值,以供硬即時程式輪詢。
◦ 主動:由軟即時程式段將後續工作排入作業系統排程。
在C4M-OS的程式開發環境下,安排中斷向量表觸發中斷服務函式的方式有兩種,其一是傳統的中斷向量表跳接執行中斷服務常式機制,其二是C4M-OS中斷服務常式分享登錄機制。以下我們分別詳述這兩種機制以及程序。
參考圖3. 傳統的中斷向量表執行中斷服務常式機制圖,硬體中斷的程式執行機制是當有一個中斷事件發生而產生中斷要求, 例如IRQ0, IRQn發生,程式指標就會自動跳到該硬體中斷編號專屬的中斷向量表, IntVec0, IntVecn,去找一個函式住址,再向量表上提供的住址跳去那位位址去執行的中斷服務常式,ISR(vec0),ISR(vecn)。
圖3. 傳統的中斷向量表執行中斷服務常式機制圖
這個機制原本需要使用者用組合語言自行安排。然而C語言編譯器,則己經建置了一套安排中斷服務常式的標準語法,使用者只要準備好程式碼並照著標準來做,即可由C語言編譯器代勞完成中斷服務常(駐函)式與中斷向量表鏈結的安排。雖然各家的C語言編譯器都提供了撰寫及安排中斷服務常式與中斷向量表鏈結的語法,但由於ANSI C並沒相關標準規定,因此各家的方式並未統一。這個造成使用到中斷的應用程式,無法跨IDE平台可攜。例如說GCC的C編譯器,與與Keil的C編譯器在中斷服務常式的語法不相容。
另外這一種中斷的安排機制,由於每一個中斷向量對應一個中斷服務常式,若有同一個中斷向量需要同時促成不同的工作執行暫存器讀寫並觸發各自後續工作行時,因為必需要撰寫在同一支中斷服務函式之中,所以而無法獨立禁致能。
編譯器的中斷服務函式撰寫及安排標準
GNU C官方有一套撰寫中斷服務函式並將它連結到中斷向量表的標準方法。在GNU C編譯環境下,中斷服務函式只要依照官方規定方式來撰寫,便能實現中斷向量表與中斷服務函式的連結。
此一方式以例子來說明更為清楚︰
#include
ISR(INT5_vect){
// put user code here
}
• 提供中斷服務常式:上述的函式範例提供的即為GNU C中斷服務常式標準格式,所有中斷都用相同的名稱,其中斷源的分辨只靠中斷向量傳參XXX_vect。 提供中斷服務常式與中斷向量對應:上述的類似函式括號內的傳參XXX_vect,即為對應到中斷向量的名稱。 ATmega128有35個中斷源,提供各週邊硬體主動觸發MCU處理程序其中斷向量表如下表
表1 ATmega128的第1到10中斷向量
表1(續) Atmega128的第11到20中斷向量
表1(續) Atmega128的第21到30中斷向量
表1(續) Atmega128的第31到35中斷向量
表中Source為中斷訊號源的名稱。在GNU C編譯器環境下,只要將訊號源名稱中的空白及逗點等以待間隔符號下引線'_'取代,然後再於名稱的最後接上'_vect'之後即能夠作為代表中斷向量的參數,放進ISR() 括號中以指示本函式連接到該中斷訊號源對應的中斷向量。例如INT4中斷訊號源,對應的中斷向量參數為INT4_vect, 而TIMER2 OVF的中斷向量參數為TIMER2_OVF_vect, USART0,RX中斷向量參數為USART0_RX_vect。
註:ISR(INT5_vect)其實是巨集字串,它會替代
void INT5_vect(void ){…} 中斷服務常式
• 中斷服務執行前後暫存器內容的PUSHPOP:在中斷前後,所必需推入及拉出堆疊的執行狀態暫存器C Compiler都會主動幫助你處理,所以撰寫C的中斷服務常式可以忽略掉這一個動作。