瞭解ARM體系CPU的7種工作模式 瞭解S3C2410/S3C2440中斷體繫結構 掌握S3C2410/S3C2440的中斷服務程式的編寫方法 ...
本章目標: 瞭解ARM體系CPU的7種工作模式 瞭解S3C2410/S3C2440中斷體繫結構 掌握S3C2410/S3C2440的中斷服務程式的編寫方法 9.1 S3C2410/S3C2440 中斷體繫結構 9.1.1 ARM體系CPU 的7種工作模式 ARM體系的CPU有以下7種工作模式: ① 用戶模式(usr):ARM處理器正常的程式執行狀態; ② 快速中斷模式(fiq):用於高速數據傳輸或通道處理; ③ 中斷模式(irq):用於通用的中斷處理; ④ 管理模式(svc):操作系統使用的保護模式; ⑤ 數據訪問終止模式(abt):當數據或指令預取終止時進入該模式,可用於虛擬存儲及 存儲保護; ⑥ 系統模式(sys):運行具有特權的操作系統任務; ⑦ 未定義指令中止模式(und):當未定義的指令執行時進入該模式,可用於支持硬體協 處理器的軟體模擬。 可以通過軟體來進行模式切換,或者發生各類中斷、異常時CPU自動進入相應的模式。 除了用戶模式外,其他6種工作模式屬於特權模式。大多數程式運行與用戶模式,進入特權 模式是為了處理中斷、異常,或者訪問被保護的系統資源。 另外,ARM體系的CPU有以下兩種工作狀態。 ① ARM狀態:此時處理器執行32位的字對齊的ARM指令; ② Thumb狀態:此時處理器執行16位的、半字對齊的Thumb指令。 實際上,本書所有程式都是在ARM狀態下運行的,而CPU一上電就處於ARM狀態,所 以無需關心CPU的狀態。 ARM920T有31個通用的32位寄存器和6個程式狀態寄存器。這37個寄存器分為7組,進 入某個工作模式時,就是用它那組的寄存器。有些寄存器,不同的工作模式下有自己的副 本,當切換到另一個模式時,那個模式的寄存器副本將被使用:這些寄存器被稱為備份寄 存器(圖9.1中使用灰色三角形標記的寄存器)。 圖中R0~R15可以直接訪問,這些寄存器中除R15外都是通用寄存器,即它們既可以 用於保存數據,也可以用於保存地址。另外,R13~R15稍有不同。 R13被稱為“ 棧指針 ” 寄存器,通常被用來保存棧指針; R14被稱為“ 程式連接 ”寄存器或“ 連接 ”寄存器,當執行BL子程式調用指令時,R14中 得到R15(程式計數器PC)的備份。而發生中斷或異常時,對應的R14_svr、R14_irq、 R14_fiq、R14_abt或R14_und中保存R15返回值。 R15是程式計數器。 快速中斷模式有7個備份寄存器R8~R14(即R8_fiq~R14_fiq),這使得進入快速中斷模式 執行很大部分程式時(只要它們不改變R0~R7),甚至不需要保存任何寄存器。用戶模式、 管理模式、數據訪問終止模式和未定義指令中止模式都含有兩個獨占的寄存器副本R13和 R14,這樣可以令每個模式擁有自己的棧指針寄存器和連接寄存器。 每種工作模式除R0~R15共16個寄存器外,還有第17個寄存器——CPSR,即“當前程式 狀態寄存器”。其中一些位被用來標識各種狀態,一些位被用來標識當前處於什麼工作模式。 CPSR中各位意義如下,如圖9.2所示。 (1)T位:置位時,CPU處於Thumb狀態:否則處於ARM狀態。 (2)中斷禁止位:I位和F位屬於中斷禁止位。它們被置位時,IRQ中斷、FIQ中斷分別 被禁止。 (3)工作模式位:表明CPU當前處於什麼工作模式。可以編寫這些位,使CPU進入指 定的工作模式。 除CPSR外,還有快速中斷模式、中斷模式、管理模式、數據訪問終止模式和未定義指 令中止模式等5種工作模式和一個寄存器——SPSR(程式狀態保存寄存器)。當切換進這些 模式時,在SPSR中保存前一個模式的CPSR值,返回前一個模式時,將SPSR的值恢復到 CPSR中。 綜上所述,當一個異常發生時,將切換進入相應的工作模式(異常模式),這時ARM920T CPU核將自動完成如下事情: (1)在異常模式的連接寄存器R14中保存前一個模式的下一條即將執行的指令地址。 對於ARM狀態,這個值是當前PC值加4或加8(參考表9.1); (2)將CPSR的值複製到異常模式的SPSR; (3)將CPSR的工作模式位設為這個異常對應的工作模式; (4)令PC值等於這個異常模式在異常向量表中的地址,即跳轉去執行異常向量表中的相應指令。 相反地,從異常模式返回之前的工作模式時,需要通過軟體完成如下事情: (1)將之前保存在連接寄存器中的前一工作模式的一個指令地址減去一個適當的值(參考 表9.1)後賦給PC寄存器; (2)將SPSR的值複製回CPSR; 9.1.2 S3C2410、S3C2440中斷控制器 對於不同的CPU,中斷的處理只是細節不同。S3C2410/S3C2440的中斷控制器結構 如圖9.4所示,可以看出中斷的處理細節。 SUBSRCPND和SRCPND寄存器表明有哪些中斷被觸發了,正在等待處理(pending); SUBMASK(INTSUBMSK寄存器)和MASK(INTMSK寄存器)用於屏蔽某些中斷。 圖中“Request sources(with sub-register)”表示INT_RXD0、INT_TXD0等中斷源(S3C2410 中這類中斷有11個,而S3C2440中有15個)。它們不同於“Request sources(without sub-register)”。 (1)“Request sources(without sub-register)”中的中斷源被觸發之後,SRCPND寄存器中 相應位被置1,如果此中斷沒有被INTMSK寄存器屏蔽掉或快速中斷的話,它將被進一步處理。 (2)對於“Request sources(with sub-register)”中的中斷源被觸發之後,SUBSRCPND寄存器 中的相應位被置1,如果此中斷沒有被INTSUBMSK寄存器屏蔽的話,它在SRCPND寄存器中 的相應位也被置1,之後的處理過程就和“Request sources(without sub-register)”一樣了。 繼續沿著圖9.4的箭頭前進:在SRCPND寄存器中,被觸發的中斷的相應位被置1,等待處理。
(1)如果被觸發的中斷中有快速中斷(FIQ)——MODE (INTMOD寄存器)中為1的位對應的 中斷時FIQ,則CPU進入快速中斷模式(FIQ Mode)進行處理。 註意:FIQ只能分配一個,即INTMOD中只能有一位設為1。 (2)對於一般中斷IRQ,可能同時又幾個中斷觸發,未被INTMSK寄存器屏蔽的中斷經過比較 後,選出優先順序最高的中斷,此時中斷在INTPND寄存器中的相應位被置1,然後CPU進入中斷模 式(IRQ Mode)進行處理。中斷處理服務程式可以通過讀取INTPND寄存器或者INTOFFSET寄存器 來確定中斷源。 圖9.4中的“Priority”表示中斷的優先順序判斷,通過PRIORITY寄存器進行設置,這在9.1.3小節介紹。
綜上所述,使用中斷的步驟如下: (1)設置好中斷模式和快速終端模式下的棧: 當發生 中斷IRQ時,CPU進入 中斷模式,這時使用 中斷模式下的棧; 當發生快速中斷FIQ時,CPU進入快速中斷模式,這時使用快速中斷模式下的棧。 (2)準備好中斷處理函數。 ① 異常向量。 在異常向量表中設置好當進入中斷模式或快速中斷模式時的跳轉函數,它們的異常向量 地址分別為:0x0000 0018、0x0000 001c。 ② 中斷服務程式(ISR)。 IRQ、FIQ的跳轉函數,最終將調用具體中斷的服務函數。 對於IRQ,讀取INTPND寄存器或INTOFFSET寄存器的值來確定中斷源,然後分別處理。 對於FIQ,因為只有一個中斷可以設為FIQ,無須判斷中斷源。 ③ 清除中斷:如果不清除中斷,則CPU會誤認為有發生了一次這個中斷。 可以調用ISR之前清除中斷,也可以在調用ISR之後清除,這取決於在ISR執行過程中,這 個中斷是否可能繼續發生、是否能夠丟棄。 如果可能發生並不能丟棄,則在調用ISR之前清除中斷,這樣在ISR執行過程中發生的中斷 能夠被各寄存器再次記錄並通知CPU; 如果不會發生或者可以丟棄,則在調用ISR之後清除中斷。 (3)進入、退出中斷模式或快速中斷模式時,需要保存、恢復中斷程式的運行環境。 ① 對於IRQ,進入和退出的代碼如下:
1 sub lr, lr, #4 @計算返回地址 2 stmdb sp!, {r0-r12, lr} @保存使用的寄存器 3 ... ... @處理中斷 4 ldmia sp!, {r0-r12, pc}^ @中斷返回 5 @^表示將spsr的值賦給cpsr進入和退出IRQ ② 對於FIQ,進入和退出的代碼如下:
1 sub lr, lr #4 @計算計算返回地址 2 stmdb sp!, {r0-r7, lr} @保存使用到的寄存器 3 ... ... @快速處理中斷 4 sdmia sp!, {r0-r7, pc}^ @快速中斷返回 5 @^表示將spsr的值賦給cpsr進入和退出FIQ (4)根據具體中斷,設置相關外設。比如對於GPIO中斷,需要將相應引腳的功能設為 “外部中斷”、設置中斷觸發條件(低電平觸發、高電平觸發、下降沿觸發還是上升沿觸發) 等。一些中斷擁有自己的屏蔽寄存器,還要開啟它。 (5)對於“Request sources(without sub-register)”中的中斷,將INTSUBMSK寄存 器中相應位設為0。 (6)確定使用此中斷的方式:FIQ還是IRQ。 ① 如果是FIQ,則在INTMOD寄存器中設置相應位為1; ② 如果是IRQ,則在RIOPITY寄存器中設置優先順序; (7)如果是IRQ,將INTMSK寄存器中相應位設為0(FIQ不受INTMSK寄存器控制); (8)設置CPSR寄存器中的I-bit(對於IRQ)或F-bit(對於FIQ)為0,使能IRQ或FIQ。 9.1.3 中斷控制寄存器 SUBSRCPND、INTSUBMSK這兩個寄存器中相同的位對應相同的中斷; SRCPND、INTMSK、INTMOD、INTPND這4個寄存器中相同的位對應相同的中斷。 下麵沿著圖9.4的箭頭方向講解所涉及的寄存器。 1.SUBSRCPND寄存器(SUB SOURCE PENDING) SUBSRCPND寄存器被用來標識INT_RXD0、INT_TXD0等中斷(S3C2410中這類中斷有11 個,而S3C2440中有15個)是否發生,每位對應一個中斷。當這些中斷發生並且被INTSUBMSK 寄存器(下麵介紹)屏蔽,則它們中的若幹位將“彙集”出現在SRCPND寄存器(下麵介紹)的 一位上。比如SUBSRCPND寄存器中的3個中斷INT_RXD0、INT_TXD0、INT_ERR0,只要有一個 發生了且沒有被屏蔽,則SRCPND寄存器中的INT_UART0位被置1。 要清除中斷時,向SUBSRCPND寄存器中某位寫入1即可令此位為0;寫入0無效,數據 不變。 SUBSRCPND寄存器中各位對應的中斷、SUBSRCPND寄存器中哪幾位“彙集”成SRCPND 寄存器中的哪一位,請參考數據手冊。 2.INTSUBMSK寄存器 被用來屏蔽SUBSRCPND寄存器所標識的中斷。其中的某位被設為1時,對應中斷被屏蔽。 3.SRCPND寄存器 其中的每一位被用來表示一個(或一類)中斷是否已經發生,即圖9.4中輸入“SRCPND” 的兩類中斷:使用SUBSRCPND/INTSUBMSK控制的中斷;不適用SUBSRCPND/INTSUBMSK控制的中 斷。 SRCPND寄存器的操作與SUBSRCPND寄存器類似,想相除某一位,向該位寫入1。 SRCPND中各位對應哪個(哪類)中斷,請參考數據手冊。 4.INTMSK寄存器
被用來屏蔽SRCPND寄存器所標識的中斷。其中某些位被設為1時,對應中斷被屏蔽。 本寄存器只能屏蔽被設為IRQ的中斷,不能屏蔽被設為FIQ的中斷,請參考下麵的 INTMOD寄存器。 5.INTMOD寄存器 本寄存器中某位被設為1時,對應中斷被設為FIQ,即此中斷發生時,CPU進入FIQ 模式,這通常用來處理特別緊急的中斷。 註意:同一時間內,INTMOD中只能有一位被設為1。 6.PRIORITY寄存器 上面INTMOD寄存器中,將設為1的中斷成為快速中斷(FIQ),其餘為0的中斷成為普通 中斷(IRQ)。 當有多個普通中斷同時發生時,中斷控制器將選出最高優先順序的中斷,首先處理它。 優先順序判斷通過7個仲裁器完成,包括6個一級和1個二級仲裁器,結構圖如圖9.5所示。 每個仲裁器含6個輸入引腳REQ0~REQ5。對於每個仲裁器,PRIORITY寄存器使用3位來 控制其行為:一位被用於選擇仲裁器的工作模式,被稱為ARB_MODE;兩位被用於控制各輸入 信號的優先順序,稱為ARB_SEL。 SRB_SEL的取值和REQ0~REQ5的優先順序如表9.2所示。 當某個仲裁器的ARB_MODE位被設為0時,它的ARB_SEL位是不會自動變化的,此時這個 仲裁器的6個輸入引腳的優先順序固定不變(當然,可以通過軟體修改ARB_SEL來改變它們的優 先級)。當ARB_MODE位被設為1時,ARB_SEL會隨著“已經被服務的REQx(x:1~4)”自動變化, 順序如表9.3所示。 結合表9.2、表9.3可知:當ARB_MODE為1時,某個REQx(x:1~4)被服務之後,它的 優先順序變為REQ0~REQ4中的最低。 PRIORITY寄存器中位[0:6]對應這7個仲裁器的ARB_MODE位(位[0]是ARB_MODE0,依 此類推),位[7:20]位對應這7個仲裁器的ARB_SEL位([7:8]是ARB_SEL0,依此類推)。 7.INTPND寄存器 經過中斷優先順序仲裁器選出優先順序最高的中斷後,這個中斷在本寄存器中的相應 位被置1,隨後,CPU進入中斷模式處理它。 同一時間內,此寄存器只有一位被置1;在ISR中,可以根據這個位確定是哪個中斷。 清除中斷時,向這個位寫入1。 8.INTOFFSET寄存器 這個寄存器被用來表示INTPND寄存器中哪位被置1了,即INTPND寄存器中位[x]為1時, INTOFFSET寄存器的值為x(x為0~31)。 在清除SRCPND、INTPND寄存器時,本寄存器被自動清除。 9.2 中斷控制器操作實例:外部中斷 9.2.1 按鍵中斷代碼詳解 開發板上,K1~K4四個按鍵所接的CPU引腳可以設成外部中斷功能。本程式的main 函數是一個不做任何事的無線迴圈,程式的功能完全靠中斷來驅動:當按下某個按鍵時, CPU調用其中斷服務程式來點亮對應的LED。 程式代碼在/work/hardware/int目錄下,有4個源文件:head.S、init.c、interrupt.c和 main.c,1個頭文件s3c24xx.h。 1.head.S代碼詳解 先看head.S文件:
1 @************************************* 2 @File:head.S 3 @功能:初始化、設置中斷模式、系統模式的棧,設置好中斷處理函數 4 @************************************* 5 6 .extern main 7 .text 8 .global _start 9 _start: 10 @************************************* 11 @中斷向量,本程式中,除了Reset和HandleIRQ外,其他異常都沒有使用 12 @************************************* 13 b Reset 14 15 @ 0x04:未定義指令終止模式的向量地址 16 HandleUndef: 17 b HandleUndef 18 19 @ 0x08:管理模式的向量地址,通過SWI指令進入此模式 20 HandleSWI: 21 b HandleSWI 22 23 @ 0x0c:指令預取終止導致的異常向量的向量地址 24 HandlePrefetchAbort: 25 b HandlePrefetchAbort 26 27 @ 0x10:數據訪問終止導致的異常向量地址 28 HandleDataAbort: 29 b HandleDataAbort 30 31 @ 0x14:保留 32 HandleNotUsed: 33 b HandleNotUsed 34 35 @ 0x18:中斷模式的向量地址 36 b HandleIRQ 37 38 @ 0x1c:快速中斷模式的向量地址 39 HandleFIQ: 40 b HandleFIQ 41head.S 上面的第17、21、25、29、33、36和40行等共7條指令所在地址為0x00、0x04、......、 0x1c,這些地址上的指令被稱為“異常向量”。當發生各類異常時,CPU進入對應的工作模 式,並跳轉去執行它的“異常向量”。比如,當複位時,CPU進入系統模式,並跳轉到0x00 地址開始執行;當發生中斷時,CPU進入中斷模式,並跳到0x18地址開始執行。 本程式中,只使用到“複位”和“中斷”對應異常向量,其他異常向量沒有實際作用。 0x00地址處的指令為“ b Reset ”,在系統複位後,這條指令將跳去執行標號“Reset”開始 的代碼,它們完成一些初始化,代碼如下:
1 接上面 2 42行 Reset: 3 43行 ldr sp, =4096 @設置棧指針,以下都是C函數,需要在調用前設置好棧 4 44行 bl disable_watch_dog @關閉看門狗 5 45行 6 46行 msr cpsr_c, #0xd2 @進入中斷模式 7 47行 ldr sp, =3072 @設置中斷模式棧指針 8 48行 9 49行 msr cpsr_c, #0xdf @進入系統模式 10 50行 ldr sp, =4096 @設置系統模式棧指針 11 51行 @起始複位之後,CPU就處於系統模式 12 52行 @前面的“ldr sp, =4096”完成同樣的功能,此句可省略 13 53行Reset代碼 註意,這是還沒有完成所有初始化,所以還不能開中斷——第46、49行的代碼中,CPSR寄存 器的I位、F位都被設為1.第47、50行中sp寄存器並不是同一個寄存器,前者為sp_irq,後者為sp_sys。 繼續向下看代碼:
接上面 54行 bl init_led @初始化LED的GPIO管腳 55行 bl init_irq @調用中斷管腳初始化函數,在init.c中 56行 msr cpsr_c, #0x5f @設置I-bit=0,開啟IRQ中斷 57行 58行 ldr lr, =halt_loop @設置返回地址 59行 ldr pc, =main @調用main函數 60行 halt_loop: 61行 b halt_loopmain函數中不做任何事的無限迴圈,當按下按鍵時,這個迴圈被打斷,CPU進入中斷模式,執行 第36行的“ b HandleIRQ ”的指令。 標號“HandleIRQ”開始的代碼用於處理中斷,如下所示:
1 接上面 2 62行 HandleIRQ: 3 63行 sub lr, lr #4 @計算返回地址 4 64行 stmdb sp!, {r0-r12, lr} @保存使用到的寄存器 5 65行 @註意,此時的sp是中斷模式的sp 6 66行 @初始值是上面設置的3072 7 67行 8 68行 ldr lr, =int_return @設置調用ISR即EINT_Handle函數後的返回地址,即為第71行指令的地址 9 69行 ldr pc, =EINT_Handle @調用中斷服務函數,在interrupt.c中 10 70行 int_return: 11 71行 ldmia sp!, {r0-r12, pc}^ @中斷返回,^表示將spsr的值複製到cpsr 12 72行HandleIRQ 第63行請參考表9.1,lr寄存器的值等於被中斷指令的地址加4,所以返回地址為lr-4。 第64行用於保存被中斷程式的運行環境,即各個寄存器。其中的sp為中斷模式的棧。 在上面的47行初始化。這樣,r0~r12、lr這14個寄存器被保存在中斷模式的棧中。 第69行調用中斷服務函數EINT_Handle(代碼在interrupt.c中,下麵詳述)。 當EINT_Handle函數處理完所有發生的中斷後,返回71行的指令。它恢復前面第64行 保存的各個寄存器,即恢復被中斷程式的運行環境 :從棧中恢復r0~r12、pc這14個寄存器 的值,同時,將SPSR寄存器的值複製到CPSR(在進入中斷模式時,CPU自動將原來的 CPSR的值保存到SPSR中),這導致CPU切換到原來的工作模式。 2.init.c中與中斷相關的代碼詳解 下麵詳細講述前面略過的init_irq函數,它在init.c中
1 37行 /* 2 38行 * 初始化GPIO引腳為外部中斷 3 39行 * GPIO引腳為外部中斷時,預設低電平觸發,IRQ方式(不用設置INTMOD) 4 40行 */ 5 41行 void init_irq() 6 42行 { 7 // S2,S3對應的2根引腳設為中斷引腳 EINT0,ENT2 8 43行 GPFCON &= ~(GPF0_msk | GPF2_msk); 9 44行 GPFCON |= GPF0_eint | GPF2_eint; 10 // S4對應的引腳設為中斷引腳EINT11 11 GPGCON &= ~GPG3_msk; 12 GPGCON |= GPG3_eint; 13 45行 14 46行 //對於EINT11,需要在EINTMASK寄存器中使能它們 15 47行 EINTMASK &= ~(1<<11); 16 48行 17 49行 /* 18 50行 *設定優先順序 19 51行 *ARB_SEL0 = 00b,ARB_MODE0 = 0;REQ1 > REQ3,即EINT0 > EINT2 20 52行 *仲裁器1、6無須設置 21 53行 *最終: 22 54行 *EINT0 > EINT2 > EINT11, EINT19、即K4 > K3 > K1、K2 23 55行 *EINT11和EINT19的優先順序相同 24 56行 */ 25 57行 PRIORITY = (PRIORITY & ((~0x01) | (0x3 << 7))) | (0x0 << 7); 26 58行 27 59行 //EINT0、EINT2、EINT8_23使能 28 60行 INTMSK &= (~(1 << 0)) & (~(1 << 2)) & (~(1 << 5)); 29 61行 }init.c 使用GPIO的中斷功能時,需要確定它們的中斷觸發方式,我們使用預設的低電平觸發, 所以無須額外設置。 第47行在EINTMASK寄存器中開啟EINT11和19中斷,EINT0和EINT2中斷不受 EINTMASK寄存器控制。這個寄存器可以屏蔽的中斷請參考數據手冊。 第57行用於設置中斷優先順序。請參考圖9.5,EINT0和2被接到仲裁器0的REQ1、REQ3, 程式中設置ARB_SEL0為0(即0b00,參考表9.2),所以REQ1的優先順序高於REQ3。 程式中設置ARB_MODE0為0,所以仲裁器0中各優先順序保持不變。 EINT8~EINT23公用仲裁器1的REQ1。 仲裁器0、1的輸出接到仲裁器6的REQ0、REQ1,而仲裁器的REQ0優先順序總是高於REQ1, 所以這4個控制的優先順序如下:EINT0 > EINT2 > EINT11。 本程式使用GPIO預設的中斷模式——IRQ方式(不是FIQ),所以不用設置INTMOD寄存器。 最後,在第60行,將INTMSK寄存器中EINT0、2、8_23這3個(類)中斷對應的位設為0, 使能中斷(註意,即使在這裡,中斷仍未完全開啟,head.S第56行才打開最後一個開關)。 3.interrupt.c中的中斷處理函數 上面講解了有關的初始化、中斷的進入和退出,真正的處理函數為EINT_Handle,它被稱 為中斷服務程式(ISR),代碼在interrupt.c中,如下所示:
1 #include "s3c24xx.h" 2 3 void EINT_Handle() 4 { 5 unsigned long oft = INTOFFSET; 6 unsigned long val; 7 8 switch( oft ) 9 { 10 // S2被按下 11 case 0: 12 { 13 GPFDAT |= (0x7<<4); // 所有LED熄滅 14 GPFDAT &= ~(1<<4); // LED1點亮 15 break; 16 } 17 18 // S3被按下 19 case 2: 20 { 21 GPFDAT |= (0x7<<4); // 所有LED熄滅 22 GPFDAT &= ~(1<<5); // LED2點亮 23 break; 24 } 25 26 // K4被按下 27 case 5: 28 { 29 GPFDAT |= (0x7<<4); // 所有LED熄滅 30 GPFDAT &= ~(1<<6); // LED4點亮 31 break; 32 } 33 34 default: 35 break; 36 } 37 38 //清中斷 39 if( oft == 5 ) 40 EINTPEND = (1<<11); // EINT8_23合用IRQ5 41 SRCPND = 1<<oft; 42 INTPND = 1<<oft; 43 }interrupt.c 第5行用來讀取INTOFFSET寄存器,用來標識INTPND寄存器中哪位被設為1。此值位0時 表示INTPND寄存器的位[0]為1,即EINT0中斷發生了,這說明K4被按下,以此類推。 註意:清除中斷時,順序很重要,先EINTPEND,然後是SRCPND,最後是INTPND。 4.主函數 在main.c中什麼也不做,如下所示:
1 int main() 2 { 3 while(1); 4 return 0; 5 }main.c 為了更形象地瞭解本程式,下麵用圖9.6.來演示代碼的執行過程,註意其中SP、PC寄存器的變化。 9.2.2 實例測試 在源碼目錄INT下執行make命令生成int.bin,燒入NAND Flash後,按下複位鍵啟動。輪流按下K1~K4, LED1~LED4被輪流點亮;同時按下K3、K4時,只有LED4被點亮。 附:代碼: 鏈接: https://pan.baidu.com/s/1kV24a9L 密碼: tfab