实验名称:ARM基本接口之外部中断实验
实验目的:
1. 了解中断的作用;
2. 掌握嵌入式系统中断的处理流程;
3. 掌握ARM外部中断编程。
实验内容(含步骤):
1. 总体步骤:先编译,启动目标机,待显示2440后,进行创建链接,下载,运行,观察是否显示HELLOO,按下EXINT2按钮看led灯是否变换显示效果
2. 实验过程:在实验过程中,始终显示硬件连接失败,组员认为是目标机与电脑连接问题,拔了插过,但仍然不行,后来多次更换电脑连接,花费了大量时间,终于解决问题,然后在紧迫的时间内修改代码,编译,链接,下载,运行,终于成功显示效果。理解原理后,通过在主程序中运行数码管显示代码,使得宿主机能正确显示HELLOO字样,然后通过按下EXINT2按钮请求中断,执行中断服务程序,使得led灯能变换显示
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都是有依据的。这次的外部中断是外部通过按按钮来进行中断,并让led灯实现奇偶间断灯亮起,很有中断的感觉。
wq:以前学过的中断都是比较表面的,理解的也比较浅,通过这次的中断实验,进入到硬件底层,我们对机器内的中断过程有了更加深入的了解。以及注册中断、开中断、清除中断的具体函数实现。这次的外部中断是通过按键来中断的现行程序,使得LED灯可以变换显示。但是非常遗憾这次实验由于我们组连接机器时间过长,导致实验时间极短,并没有学得尽兴。
yy:这次实验的课题是ARM基本接口之外部中断,中断的典型步骤是:保存现场,模式切换,获取中断源,处理中断,中断返回。不得不说这次的实验较以往难度更高,代码读起来也更加晦涩难懂,也涉及到了更多关于底层的知识,但实验完成之后确实感觉对中断有了进一步的了解
cxy:这次实验的内容是中断。以前经常在操作系统和计算机组成原理上听到中断的介绍,但是一直没有真正了解过中断的具体实现。这次实验让我了解中断的具体。