ARM基本介面之外部中斷實驗
實驗名稱:ARM基本介面之外部中斷實驗
實驗目的:
1. 瞭解中斷的作用;
2. 掌握嵌入式系統中斷的處理流程;
3. 掌握ARM外部中斷程式設計。
實驗內容(含步驟):
1. 總體步驟:先編譯,啟動目標機,待顯示2440後,進行建立連結,下載,執行,觀察是否顯示HELLOO,按下EXINT2按鈕看led燈是否變換顯示效果
2. 實驗過程:在實驗過程中,始終顯示硬體連線失敗,組員認為是目標機與電腦連線問題,拔了插過,但仍然不行,後來多次更換電腦連線,花費了大量時間,終於解決問題,然後在緊迫的時間內修改程式碼,編譯,連結,下載,執行,終於成功顯示效果。理解原理後,通過在主程式中執行數碼管顯示程式碼,使得宿主機能正確顯示
3.程式碼如下:
/****************************************************************************/ /*實驗現象: 共陽數碼管顯示HELLOO,觸發外部中斷後,led燈由奇數管亮(滅)轉變為偶數管亮(滅)*/ /****************************************************************************/ #define U8 unsigned char /*HELLOO的字元編碼*/ unsigned char hello[6] = { 0x89, 0x86, 0xc7, 0xc7, 0xc0, 0xc0, }; /*六個數碼管只亮一個的狀態編碼*/ unsigned char con[6] = { 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe }; void myDelay(int time); Void Delay(int time); /******************************************************************** // Function name : Isr_Init // Description : 中斷初始化功能 // Return type : void // Argument : void *********************************************************************/ void Isr_Init(void) { pISR_UNDEF = (unsigned)HaltUndef; pISR_SWI = (unsigned)HaltSwi; pISR_PABORT = (unsigned)HaltPabort; pISR_DABORT = (unsigned)HaltDabort; rINTMOD = 0x0; //中斷模式設定為IRQ rINTMSK = BIT_ALLMSK; //All interrupt is masked. rINTSUBMSK = BIT_SUB_ALLMSK; //All sub-interrupt is masked. } /******************************************************************** // Function name : Isr_Request // Description : 註冊中斷函式(中斷請求) // Return type : void // Argument : int irq_no // #define IRQ_EINT0 1 // #define IRQ_EINT1 2 // #define IRQ_EINT2 3 // #define IRQ_EINT3 4 //** // #define IRQ_EINT4_7 5 // #define IRQ_EINT8_23 6 // #define IRQ_NOTUSED6 7 // #define IRQ_BAT_FLT 8 // #define IRQ_TICK 9 // #define IRQ_WDT 10 // #define IRQ_TIMER0 11 // #define IRQ_TIMER1 12 // #define IRQ_TIMER2 13 // #define IRQ_TIMER3 14 // #define IRQ_TIMER4 15 // #define IRQ_UART2 16 // #define IRQ_LCD 17 // #define IRQ_DMA0 18 // #define IRQ_DMA1 19 // #define IRQ_DMA2 20 // #define IRQ_DMA3 21 // #define IRQ_SDI 22 // #define IRQ_SPI0 23 // #define IRQ_UART1 24 // #define IRQ_NOTUSED24 25 // #define IRQ_USBD 26 // #define IRQ_USBH 27 // #define IRQ_IIC 28 // #define IRQ_UART0 29 // #define IRQ_SPI1 30 // #define IRQ_RTC 31 // #define IRQ_ADC 32 // Argument : void* irq_routine *********************************************************************/ //第一個引數表示中斷請求源, 第二個引數為該中斷請求源定義的中斷服務函式 void Irq_Request(int irq_no, void* irq_routine) { if(irq_no >= IRQ_MIN && irq_no <= IRQ_MAX) *(unsigned int*)((irq_no - 1) * sizeof(unsigned int) + (unsigned int)(_ISR_STARTADDRESS+0x20)) = (unsigned int)irq_routine; // _ISR_STARTADDRESS+0x20 就是跳過前面的異常向量,進入IRQ中斷向量的入口 // 三級跳到指定地址,即從flash中跳到了RAM的中斷入口,然後又從中斷入口跳到中斷//分發例程入口 } /******************************************************************** // Function name : Irq_Enable // Description : 開中斷 // Return type : void // Argument : int irq_no *********************************************************************/ //引數表示中斷請求源,該函式使能某中斷 void Irq_Enable(int irq_no) { if(irq_no >= IRQ_MIN && irq_no <= IRQ_MAX) rINTMSK &= ~(1 << (irq_no - 1));//全部置零,使能中斷 } /******************************************************************** // Function name : Irq_Disable // Description : 關中斷 // Return type : void // Argument : int irq_no *********************************************************************/ //引數表示中斷請求源,該函式禁止某中斷 void Irq_Disable(int irq_no) { if(irq_no >= IRQ_MIN && irq_no <= IRQ_MAX) rINTMSK |= (1 << (irq_no - 1));//置1,禁止中斷 } /******************************************************************** // Function name : Irq_Clear // Description : 清除中斷 // Return type : void // Argument : int irq_no *********************************************************************/ //引數表示中斷請求源,該函式清除某中斷請求 void Irq_Clear(int irq_no) { rSRCPND = (1 << (irq_no - 1));//置1,將該暫存器的相應位清零 rINTPND = (1 << (irq_no - 1));//置1,將該暫存器的相應位清零 rINTPND; } /***************************************************************************** // Function name : eint2_isr // Description : 主函式 // Return type : void // Argument : void *****************************************************************************/ void Main(void) { /* 配置系統時鐘 */ ChangeClockDivider(2,1); U32 mpll_val = 0 ; mpll_val = (92<<12)|(1<<4)|(1); ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3); /* 中斷初始化 */ Isr_Init(); /* 初始化埠 */ Port_Init(); /* 初始化串列埠 */ Uart_Init(0,115200); Uart_Select(0); /* 列印提示資訊 */ PRINTF("\n---外部中斷測試程式---\n"); PRINTF("\n請將UART0與PC串列埠進行連線,然後啟動超級終端程式(115200, 8, N, 1)\n"); PRINTF("\n外部中斷測試開始\n"); /* 請求中斷 */ Irq_Request(IRQ_EINT3, eint3_isr); /* 使能中斷 */ Irq_Enable(IRQ_EINT3); dither_count2 = 0; dither_count3 = 0; while(1){ int i, j; int flag = 1; for(j=0; ; j++) { *((U8*) 0x20007000) = 0x80; /* 數碼管從0到F依次將字元顯示出來 */ for(i=0;i<6;i++){ /* 查表並輸出資料 */ *((U8*) 0x20007000) = con[i] ; *((U8*) 0x20006000) = hello[i]; myDelay(1); } dither_count3++; } } } /***************************************************************************** // Function name : eint3_isr // Description : EINT3中斷處理程式 // Return type : int // Argument : void *****************************************************************************/ void eint3_isr(void) { Irq_Clear(IRQ_EINT3);//清除中斷 if(dither_count3 > 10)//如果count大於10,變換led顯示 { dither_count3 = 0;//清零 Led_Display(nLed);//led顯示 nLed = ~nLed; } }
實驗總結:
lg:在計算機組成原理和作業系統中都接觸過中斷,有個大概瞭解,但都是理論上的,通過這次外部中斷實驗,有種理論聯絡實際的感覺,想起了組成原理說過的MASK。實驗中知道了註冊中斷,開中斷,清除中斷對中斷暫存器INTMSK,SRCPND,INTPND的寫操作,和中斷執行的三級跳,對中斷有了更深入的理解
zhy:這次的實驗,我們組花了很多時間在裝置的連線上,實際修改程式碼,操作比較少,所以就有了更多的時間去看程式碼。在程式碼中具體實現了中斷的整個過程,用了兩個重要的暫存器:中斷掛起暫存器(INTPND),中斷遮蔽暫存器(INTMSK),什麼時候置0還是置1都是有依據的。這次的外部中斷是外部通過按按鈕來進行中斷,並讓
wq:以前學過的中斷都是比較表面的,理解的也比較淺,通過這次的中斷實驗,進入到硬體底層,我們對機器內的中斷過程有了更加深入的瞭解。以及註冊中斷、開中斷、清除中斷的具體函式實現。這次的外部中斷是通過按鍵來中斷的現行程式,使得LED燈可以變換顯示。但是非常遺憾這次實驗由於我們組連線機器時間過長,導致實驗時間極短,並沒有學得盡興。
yy:這次實驗的課題是ARM基本介面之外部中斷,中斷的典型步驟是:儲存現場,模式切換,獲取中斷源,處理中斷,中斷返回。不得不說這次的實驗較以往難度更高,程式碼讀起來也更加晦澀難懂,也涉及到了更多關於底層的知識,但實驗完成之後確實感覺對中斷有了進一步的瞭解
cxy:這次實驗的內容是中斷。以前經常在作業系統和計算機組成原理上聽到中斷的介紹,但是一直沒有真正瞭解過中斷的具體實現。這次實驗讓我瞭解中斷的具體。