8051的中斷,主要由IE和IP兩暫存器所控制,其中IE控制允許哪一個中斷,IP決定哪個中斷優先,兩暫存器的功能,分別說明如下 :
IE (中斷致能暫存器,預設值為00000000)EA |
---- |
ET2 |
ES |
ET1 |
EX1 |
ET0 |
EX0 |
EA: EA=0, 關閉所有中斷 EA=1, 允許中斷,是允許哪個中斷,還要由各自位元決定 ET2:致能Timer2中斷(只有8052才有) ES:致能串列傳輸中斷 ET1:致能Timer1中斷 EX1:致能INT1中斷 ET0:致能Timer0中斷 EX0:致能INT0中斷 例如要設定允許串列傳輸(UART)和INT0中斷,只要下達 MOV IE,#10010001B 即可 (C語言寫法 IE = 0x91;)
IP(中斷優先權暫存器,預設值為00000000)
---- |
---- |
PT2 |
PS |
PT1 |
PX1 |
PT0 |
PX0 |
PET2=1 Timer2中斷高優先權(只有8052才有) PS=1 串列傳輸中斷高優先權 PT1=1 Timer1中斷高優先權 PX1=1 INT1中斷高優先權 PT0=1 Timer0中斷高優先權 PX0=1 INT0中斷高優先權 例如要設定允許串列傳輸(UART)中斷高優先權,只要下達 MOV IP,#00010000B 即可 (C語言寫法 IP = 0x10;)
中斷向量
8051的IE和IP預設值皆為0,也就是中斷都是預設不啟動的,所以在重置(RESET)時,程式都可以從位址0000開始寫起,但8051為區分是哪一個中斷發生,對每一個中斷,都有其預設的中斷向量,只要中斷發生,就到該位址執行中斷程式,以下表列為各種中斷的中斷向量值。
中斷源 |
中斷向量位址 |
IE0(INT0) |
0003H |
TF0(Timer0) |
000BH |
IE1(INT1) |
0013H |
TF1(Timer1) |
001BH |
RI或TI(UART) |
0023H |
TF2或EXF2(Timer2) |
002BH |
為配合中斷程式的執行,程式一開始的寫法就要做適度的修正。
假設程式中要執行串列傳輸(UART)和INT0中斷,主程式則必須要避開位址0003H和0023H,程式必須修改如下
ORG 00H JMP START ORG 03H ;告訴組譯器,以下指令由位址0003H開始放程式 JMP INT0_INT ;位址0003H~0023H長度不夠,放不下幾個指令,建議跳至後面執行 ORG 23H ;告訴組譯器,以下指令由位址0023H開始放程式 JMP UART_INT START: : 主程式 : INT0_INT: : INT0中斷程式 : RETI ;INT0中斷程式結束 UART_INT: : UART中斷程式 : RETI ;UART中斷程式結束
此外,中斷在任何時候都可能發生,以上述範例為例,如果中斷程式中會不小心更動了主程式某些暫存器的值, 再回到主程式時,會有錯誤發生。因此,中斷程式在一開始執行時,須先將這些暫存器的值放到堆疊,等中斷程式執行 完,要回到主程式前,再將暫存器值從堆疊中取回。 例如:主程式和中斷程式都有用到累加器A,中斷程式 INT0_INT: PUSH ACC : INT0中斷程式 : POP ACC RETI ;INT0中斷程式結束 此外在主程式和中斷程式都有用到R5~R7,但我們並不能寫PUSH R7這種指令,PUSH指令只能對一般RAM(00H~7FH) 和SFR(80H~FF)這種一位元組位址動作,因此範例中將中斷程式改用暫存器庫1的R0~R7(其實際位址在一般RAM的 08H~0FH),因為修改暫存器庫需設定PSW暫存器的RS0和RS1,所以在修改前也需將PSW存入堆疊,等執行完再將PSW取 回,這樣回到主程式久可使用原來的暫存器庫。 INT0_INT: PUSH ACC ;將累加器內的值存到堆疊 PUSH PSW ;將PSW內的值存到堆疊(因以下2指令會影響到PSW內的值) SETB RS0 ;使用暫存器庫1 CLR RS1 : INT0中斷程式 : POP PSW POP ACC RETI 但這樣修改,又可能使的堆疊內的資料出錯,因8051預設堆疊值為07,他的作法是先加1,再存到該值指定的RAM位址,也 就是會從RAM位址08的地方開始放堆疊資料,此部分與暫存器庫1重疊,因此在主程式要先更改堆疊值,將堆疊資料改放到其他 位址,在範例中,主程式將堆疊指標位址移到6F,堆疊資料將從70H開始放置。 MOV SP,#6FH