热度 28
2012-8-10 13:42
3616 次阅读|
9 个评论
作者:下家山 (请尊重原创,转载请注明:上海索漫科技培训教材http://www.xiajiashan.com ) 我们这里以LPC2136为例。 Lpc2136中有22个中断源,中断控制器提供了16个向量IRQ控制器,分别可以设置16个中断优先级! 其实,要真正体现中断优先级(当低优先级中断服务程序正在执行时,高优先级中断事件到来了,先执行高优先级中断服务程序代码,即高优先级中断会中断低优先级中断服务程序),必须实现中断嵌套! 很多裸奔的arm7或者arm9产品,并没有做中断嵌套,这种产品存在着隐患,而这种隐患常让工程师(开发或维护)无法解释!所以,就出现了,客户把有问题的产品拿到原厂,原厂却说在他哪里是好的,并且当场测试却怎么也测试不出来! ================================================== 假设,我们这里有两个外部中断 EINT1==KEY1===P0.3和EINT3===KEY3====P0.30 而且,我们这里EINT3的中断优先级高于EINT1 当EINT1正在执行的时候,EINT3来了,按照惯例,EINT1会停下来,去执行EINT3的中断,等EINT3的中断服务程序执行完毕,再回头执行EINT1的服务程序。如果我们不用中断嵌套,事情并非如此。 下面是实验代码: #define KEY1 13 #define KEY3 130 #define LED1 116 #define EINT1_NUM 15 #define EINT3_NUM 17 #define P03_FUN_EINT1 36 #define P030_FUN_EINT3 228 #define EINT1_ENABLE 115 #define EINT3_ENABLE 117 /****************************************** 【By 下家山 Q群 75303301 上海松江文汇路928号258室 松江大学城 上海索漫科技 http://www.xiajiashan.com 专注嵌入式(ARM7,Cortex-M0,Cortex-M3,ARM9,linux)培训】***********/ void __irq IRQ_Eint3(void) { while(1) { IO0SET = BEEPCON; } EXTINT = 13; // 清除EINT3中断标志, VICVectAddr=0x00; // 清除中断逻辑, } /*===============================================*/ void __irq IRQ_Eint1(void) { while(1){ IO1CLR = LED1; } EXTINT = 11; // 清除EINT3中断标志, VICVectAddr=0x00; // 清除中断逻辑 } /*************************************************************/ void Init_EXT(void) { PINSEL0 = P03_FUN_EINT1 | P030_FUN_EINT3; // 设置管脚连接,P0.3设置为EINT1, P0.30设置为EINT3 EXTMODE |= 13; // 设置EINT3中断为边沿触发模式 EXTPOLAR = ~(13);// 设置EINT3中断为上升沿触发模式 EXTMODE |= 11; // 设置EINT1中断为边沿触发模式 EXTPOLAR = ~(11);// 设置EINT1中断为上升沿触发模式 EXTINT = 0xF; VICIntSelect = 0x00; // 所有中断通道设置为IRQ中断 VICVectAddr0 = (uint32)IRQ_Eint3; // 设置中断服务程序地址向量 VICVectCntl0 = 0x20 | EINT1_NUM; // 定时器中断通道分配最高优先级(向量控制器) VICVectAddr1 = (uint32)IRQ_Eint1; // 设置中断服务程序地址向量 VICVectCntl1 = 0x20 | EINT1_NUM; // 定时器中断通道分配最高优先级(向量控制器) VICIntEnable = EINT1_ENABLE | EINT3_ENABLE; // 使能EINT1EINT3中断,EINT3在Bit17,EINT1在bit15上 } ======================================================================================= By 下家山 Q群 75303301 上海松江文汇路928号258室 松江大学城 上海索漫科技 http://www.xiajiashan.com 专注嵌入式(ARM7,Cortex-M0,Cortex-M3,ARM9,linux)培训 /*************************************/ void BEEFON(void) { IO0SET =BEEPCON; } /*************************************/ void BEEFOFF(void) { IO0CLR =BEEPCON; } /*************************************/ void init_system() { IO0CLR = BEEPCON; IO0DIR = BEEPCON; IO1SET = LED1; IO1DIR = LED1 ; } /*************************************/ int main (void) { init_system(); Init_EINT(); while(1); return 0; } 上述程序执行结果是,我们先按下KEY1,LED1会亮,当我们再按下KEY3时,蜂鸣器并不会响。 =========================================================================================================================================================改成中断嵌套 ======================================================================================================================================================================= #define KEY1 13 #define KEY3 130 #define LED1 116 #define EINT1_NUM 15 #define EINT3_NUM 17 #define P03_FUN_EINT1 36 #define P030_FUN_EINT3 228 #define EINT1_ENABLE 115 #define EINT3_ENABLE 117 /*************************************/ __inline void enable_IRQ(void) { int tmp; __asm { MRS tmp, CPSR BIC tmp, tmp, #0x80 MSR CPSR_c, tmp } } /*************************************/ /*****************************************************/ void __irq IRQ_Eint3(void) { uint32 vic_enable_bak; vic_enable_bak = VICIntEnable; VICIntEnClr = (EINT3_ENABLE) | (EINT1_ENABLE); //清除自己及比自己优先级更低的中断,以便更高优先级中断响应 VICVectAddr=0x00; // 清除中断逻辑, while(1) { IO0SET = BEEPCON; } EXTINT = 13; // 清除EINT3中断标志, VICIntEnable = vic_enable_bak;//恢复中断 } ======================================================================================= By 下家山 Q群 75303301 上海松江文汇路928号258室 松江大学城 上海索漫科技 http://www.xiajiashan.com 专注嵌入式(ARM7,Cortex-M0,Cortex-M3,ARM9,linux)培训 /*===============================================*/ void __irq IRQ_Eint1(void) { uint32 vic_enable_bak; vic_enable_bak = VICIntEnable; VICIntEnClr = EINT1_ENABLE;//清除自己以便更高优先级中断响应 VICVectAddr=0x00; // 清除中断逻辑,以便VIC可以响应更高优先级IRQ中断 enable_IRQ(); while(1){//一般不会在中断服务程序里面做死循环,但为了更好说明问题使然。 IO1CLR = LED1; } EXTINT = 11; // 清除EINT3中断标志, VICIntEnable = vic_enable_bak; //恢复中断 } /*************************************************************/ void Init_EXT(void) { PINSEL0 = P03_FUN_EINT1 | P030_FUN_EINT3; // 设置管脚连接,P0.3设置为EINT1, P0.30设置为EINT3 EXTMODE |= 13; // 设置EINT3中断为边沿触发模式 EXTPOLAR = ~(13);// 设置EINT3中断为上升沿触发模式 EXTMODE |= 11; // 设置EINT1中断为边沿触发模式 EXTPOLAR = ~(11);// 设置EINT1中断为上升沿触发模式 EXTINT = 0xF; VICIntSelect = 0x00; // 所有中断通道设置为IRQ中断 VICVectAddr0 = (uint32)IRQ_Eint3; // 设置中断服务程序地址向量 VICVectCntl0 = 0x20 | EINT1_NUM; // 定时器中断通道分配最高优先级(向量控制器) VICVectAddr1 = (uint32)IRQ_Eint1; // 设置中断服务程序地址向量 VICVectCntl1 = 0x20 | EINT1_NUM; // 定时器中断通道分配最高优先级(向量控制器) VICIntEnable = EINT1_ENABLE | EINT3_ENABLE; // 使能EINT1EINT3中断,EINT3在Bit17,EINT1在bit15上 } /*************************************/ void BEEFON(void) { IO0SET =BEEPCON; } /*************************************/ void BEEFOFF(void) { IO0CLR =BEEPCON; } /*************************************/ void init_system() { IO0CLR = BEEPCON; IO0DIR = BEEPCON; IO1SET = LED1; IO1DIR = LED1 ; } /*************************************/ int main (void) { init_system(); Init_EINT(); while(1); return 0; } 上述程序执行结果是,我们先按下KEY1,LED1会亮,当我们再按下KEY3时,即使EINT1中断进入了死循环,因为正确设置了中断嵌套,EINT3可以中断EINT1的服务程序运行自己的中断服务程序,蜂鸣器会响。 写于上海松江 作者:下家山(请尊重原创, 转载请注明) http://www.xiajiashan.com,有什么问题可与我联系:ximenpiaoxue4016@sina.com