/*---------------------------------------------------------------------------------- LPCARM中断方法大全圣诞裸奔程序详解(更新) 雁塔菜农HotPower 2006.12.25 更新于菜地 Http://HotPower.21ic.org/----------------------------------------------------------------------------------*/ #i nclude //ARM菜鸟HotPower创建定义文件(最新为倒塌版) /*--------------------------------------------------------------------------------- 注意: LPC213XDEF.H文件请在 user1/46/archives/2006/16994.html下载 可将LPC213XDEF.H拷贝到Keil\ARM\INC\PHILIPS目录下
void __swi(0) Enable_IRQ(void); void __SWI_0 (void) { int tmp; __asm { MRS tmp, SPSR BIC tmp, tmp, #0x80 MSR SPSR_c, tmp } }
void __swi(1) Disable_IRQ(void); void __SWI_1 (void) { int tmp; __asm { MRS tmp, SPSR ORR tmp, tmp, #0x80 MSR SPSR_c, tmp } }
void __swi(2) Enable_FIQ(void); void __SWI_2 (void) { int tmp; __asm { MRS tmp, SPSR BIC tmp, tmp, #0x40 MSR SPSR_c, tmp } }
void __swi(3) Disable_FIQ(void); void __SWI_3 (void) { int tmp; __asm { MRS tmp, SPSR ORR tmp, tmp, #0x40 MSR SPSR_c, tmp } }
void __swi(4) Enable_VIC(void); void __SWI_4 (void) { VIC->Protection = 0;//开放对VIC的写入保护 }
/*------------------------------------------------------------- SWI中断和VICSoftInt软件中断的区别之处
由于VIC->Protection可以在任何级别随意置'1',即关闭 对VIC的写入,故没必要构造Disable_VIC(); 以下函数SetVICProtection()只是说明SWI中断和VICSoftInt软件 中断的区别,即前者属于非屏蔽中断,且可带参数和返回值。 而后者和属于可屏蔽中断,与VIC中断一样,无参数和返回值。 但VICSoftInt软件中断有别于模块的VIC中断。它可自组中断,也可 模拟系统模块中断。 两者都很灵活,但用途和方法有很大的差异。 SWI中断改进的注解见SWI.s和SWI_Table.s.否则不能正确开关FIQ/IRQ --------------------------------------------------------------*/ unsigned int __swi(5) SetVICProtection(unsigned int val); unsigned int __SWI_5 (unsigned int val) { VIC->Protection = val;//VIC->Protection可以随意置'1',但清'0'必须在管理模式下 return VIC->Protection; }
extern void FIQ_EINT0 (void) __irq { VIC->SoftIntClr = (1 << VICIntSel_EINT0);//增强安全性 INTCON->EXT_INT = (1 << EINT0); //清除INT0中断标志 VIC->VectAddr = 0; }
void IRQ_EINT1 (void) __irq { VIC->SoftIntClr = (1 << VICIntSel_EINT1);;//增强安全性 while(INTCON->EXT_INT & (1 << EINT1)) {//等待P0_3和P0_14都为低电平 INTCON->EXT_INT = (1 << EINT1);//清除INT1中断标志(电平触发必须读后清除!!!) } VIC->VectAddr = 0; }
void IRQ_SOFT (void) __irq { VIC->SoftIntClr = (1 << VICIntSel_SoftInt22);//清除用户软件中断标志 VIC->VectAddr = 0; }
void IRQ_Default (void) __irq { switch(VIC->IRQStatus) { case (1 << VICIntSel_EINT0)://拦截非法INT0中断 INTCON->EXT_INT = (1 << EINT0);//清除非法INT0中断标志 VIC->SoftIntClr = (1 << VICIntSel_EINT0);//清除非法INT0软件中断标志 break; case (1 << VICIntSel_EINT1)://拦截非法INT1中断 INTCON->EXT_INT = (1 << EINT1);//清除非法INT1中断标志 VIC->SoftIntClr = (1 << VICIntSel_EINT1);//清除非法INT1软件中断标志 break; case (1 << VICIntSel_EINT2)://拦截非法INT2中断 INTCON->EXT_INT = (1 << EINT2);//清除非法INT2中断标志 VIC->SoftIntClr = (1 << VICIntSel_EINT2);//清除非法INT2软件中断标志 break; case (1 << VICIntSel_EINT3)://拦截非法INT3中断 INTCON->EXT_INT = (1 << EINT3);//清除非法INT2中断标志 VIC->SoftIntClr = (1 << VICIntSel_EINT3);//清除非法INT3软件中断标志 break; case (1 << VICIntSel_SoftInt23)://拦截非法用户软件中断VICIntSel_SoftInt23 VIC->SoftIntClr = (1 << VICIntSel_SoftInt23);//清除非法用户软件中断标志 break; case (1 << VICIntSel_SoftInt24)://拦截非法用户软件中断VICIntSel_SoftInt24 VIC->SoftIntClr = (1 << VICIntSel_SoftInt24);//清除非法用户软件中断标志 break; case (1 << VICIntSel_SoftInt25)://拦截非法用户软件中断VICIntSel_SoftInt25 VIC->SoftIntClr = (1 << VICIntSel_SoftInt25);//清除非法用户软件中断标志 break; case (1 << VICIntSel_SoftInt26)://拦截非法用户软件中断VICIntSel_SoftInt26 VIC->SoftIntClr = (1 << VICIntSel_SoftInt26);//清除非法用户软件中断标志 break; default: VIC->SoftIntClr = 0xffffff;//清除所有非法用户软件中断标志 } VIC->VectAddr = 0; }
int main(void) { unsigned int i;
Disable_IRQ(); Disable_FIQ();
VIC->IntEnable = 0;//关闭全部中断 VIC->SoftIntClr = 0xffffffff;//清除所有软中断标志 VIC->IntSelect = 0;//全部中断为IRQ中断或默认中断
PINSEL->PIN_SEL0 = 0x00000000;//设置管脚连接GPIO PINSEL->PIN_SEL1 = 0x00000000;//设置管脚连接GPIO P0->IODIR = 0x00000000;//设置P0口为输入 P1->IODIR = 0x00000000;//设置P1口为输入
PINSEL->PIN_SEL0 |= (P0_1_EINT0 << P0_1_PINSEL); //选择P0.1为INT0外部中断引脚 PINSEL->PIN_SEL1 |= (P0_16_EINT0 << P0_16_PINSEL); //选择P0.16也可为INT0外部中断引脚
PINSEL->PIN_SEL0 |= (P0_3_EINT1 << P0_3_PINSEL); //选择P0.3为INT1外部中断引脚 PINSEL->PIN_SEL0 |= (P0_14_EINT1 << P0_14_PINSEL); //选择P0.14也可为INT1外部中断引脚
INTCON->EXT_POLAR = ~(1 << EXTPOLAR0); //INT0为低电平有效
INTCON->EXT_POLAR |= (1 << EXTPOLAR1); //INT1为高电平有效
INTCON->EXT_MODE = (1 << EXTMODE0); //设置INT0为边沿触发
INTCON->EXT_MODE &= ~(1 << EXTMODE1); //设置INT1为电平触发
/*------------------------------------------------------------------ FIQ中断和IRQ中断的区别之处 FIQ中断和IRQ中断都属于可屏蔽中断,他们分别受CPSR的F和I位的控制。
前者不需对VIC->VectAddrs和VIC->VectCntls进行设置,但要想正确地 中断要做几步工作: 1. VIC->IntSelect = (1 << VICIntSel_EINT0); //设置EINT0为FIQ中断 2. VIC->IntEnable |= (1 << VICIntSel_EINT0); //使能EINT0中断 3. 建立FIQ中断函数FIQ_EINT0(). 注意要声明为外部的即extern void FIQ_EINT0 (void) __irq 4. 改写Startup.S的内容。(改写后的注解见Startup.S)
后者需对VIC->VectAddrs和VIC->VectCntls进行设置。方法: 1. VIC->IntSelect &= ~(1 << VICIntSel_EINT1); //设置EINT1为IRQ中断 2. VIC->VectCntls[0] = VICIntSel_Enable | VICIntSel_EINT1;//设置外部中断1分配VIC最高优先级 VIC->VectAddrs[0] = (unsigned int)IRQ_EINT1;//设置中断服务程序地址 VIC->IntEnable |= (1 << VICIntSel_EINT1); //使能EINT1中断 3. 建立IRQ中断函数IRQ_EINT1(). 注意要声明为内部的即void IRQ_EINT1 (void) __irq 4. 不必改写Startup.S的内容。(当然非典就不同了~~~) 5. 当VIC中断向量地址未定义或超出VIC->VectAddrs[15]时,使用默认中断向量VIC->DefVectAddr 向量(数组)向量与默认中断向量最大的不同在于每个向量中断都有1个中断地址,而默认中断向量 只占用1个公共的中断地址但可包含多个中断源。故默认中断向量必须判别是某个具体的中断源。 所以也可以认为默认中断向量是第17个中断向量。 -------------------------------------------------------------------*/
VIC->IntSelect = (1 << VICIntSel_EINT0); //设置EINT0为FIQ中断
VIC->VectCntls[0] = VICIntSel_Enable | VICIntSel_EINT1;//设置外部中断1分配VIC最高优先级 VIC->VectAddrs[0] = (unsigned int)IRQ_EINT1;//设置中断服务程序地址 VIC->IntEnable |= (1 << VICIntSel_EINT1);//使能外部中断1
VIC->VectCntls[1] = VICIntSel_Enable | VICIntSel_SoftInt22;//设置用户软件中断 VIC->VectAddrs[1] = (unsigned int)IRQ_SOFT;//设置用户软件中断服务程序地址 VIC->IntEnable |= (1 << VICIntSel_SoftInt22);//使能用户软件中断 VIC->DefVectAddr = (unsigned int)IRQ_Default;//定义除VIC->VectAddrs[0]~VIC->VectAddrs[15]外的中断函数 for (i = 0; i < 16; i ++) { if ((VIC->VectCntls & VICIntSel_Enable) == 0) {//该中断向量未使能 VIC->VectAddrs = (unsigned int)IRQ_Default;//全部以默认中断来处理 // VIC->VectAddrs = (unsigned int)0;//全部以复位来处理 } }
INTCON->EXT_INT = (1 << EINT0) //清除INT0中断标志 | (1 << EINT1) //清除INT1中断标志 | (1 << EINT2) //清除INT2中断标志 | (1 << EINT3);//清除INT3中断标志
VIC->SoftIntClr = (1 << VICIntSel_EINT0) //清除EINT0软中断标志 | (1 << VICIntSel_EINT1) //清除EINT1软中断标志 | (1 << VICIntSel_EINT1) //清除EINT2软中断标志 | (1 << VICIntSel_EINT1);//清除EINT3软中断标志
VIC->IntEnable = (1 << VICIntSel_EINT0) //使能EINT0中断 | (1 << VICIntSel_EINT1);//使能EINT1中断
VIC->Protection = 1;//关闭在用户级对VIC的一些写操作 VIC->Protection = 0;//试图在用户级打开对VIC的一些写操作的保护 Enable_FIQ();//开放快速中断总开关 VIC->SoftInt = (1 << VICIntSel_EINT0);//软件模拟快速中断0(失败!!!) __nop(); Enable_VIC();//等效为特权级的VIC->Protection = 0; VIC->SoftInt = (1 << VICIntSel_EINT0);//软件模拟快速中断0(成功!!!) __nop();
VIC->SoftInt = (1 << VICIntSel_SoftInt22);//软件模拟用户软件中断(失败!!!) /*---------------------------------------------------------------------------------------------- 注意开中断后会立即进入EINT1硬件中断(因为假定P0.3/P0.14都为高电平) 所以要将P0.3/P0.14都拉低为低电平才可继续执行程序,否则将死在IRQ_EINT1()内!!! 若用软件仿真,可在菜单Peripherals下GPIO下选择Port0,然后点击P0.3/P0.14为低电平!!! -----------------------------------------------------------------------------------------------*/ Enable_IRQ();//注意现在立即进入EINT1硬件中断(因为假定P0.3/P0.14都为高电平) VIC->SoftInt = (1 << VICIntSel_SoftInt22);//软件模拟用户软件中断(成功!!!)
VIC->SoftInt = (1 << VICIntSel_EINT1);//软件模拟向量中断1(成功!!!)
/*---------------------------------------------------------------------------------------------- 以下两句引发VICIntSel_SoftInt23中断后VIC->VectAddr值为VIC->DefVectAddr, 故程序飞入IRQ_Default()处执行。 -----------------------------------------------------------------------------------------------*/ VIC->IntEnable |= (1 << VICIntSel_SoftInt23);//使能非法用户软件中断 VIC->SoftInt = (1 << VICIntSel_SoftInt23);//软件模拟非法用户软件中断(程序飞!!!被IRQ_Default()捕获)
VIC->Protection = 1;//关闭在用户级对VIC的一些写操作 VIC->Protection = 0;;//在用户级试图写'0'无效!!!应该用Enable_VIC();或SetVICProtection(0); while(i == 0) {//不会进入死循环 __nop(); } i = SetVICProtection(0);//进入特权级打开对VIC的一些写操作的保护(此句主要说明SWI中断可带参数或返回) VIC->Protection = 1;//关闭在用户级对VIC的一些写操作,保护在用户级VIC不被以外改写 while(i == 0) {//进入死循环 __nop(); } }
|
文章评论(0条评论)
登录后参与讨论