搜索
bottom↓
回复: 2

LPCARM中断方法大全圣诞裸奔程序详解(更新)

[复制链接]

出0入0汤圆

发表于 2006-12-24 16:45:16 | 显示全部楼层 |阅读模式
/*----------------------------------------------------------------------------------

          LPCARM中断方法大全圣诞裸奔程序详解(更新)

雁塔菜农HotPower   2006.12.25 更新于菜地

----------------------------------------------------------------------------------*/

#include <LPC213xDEF.H>    //ARM菜鸟HotPower创建定义文件(最新为倒塌版)

/*---------------------------------------------------------------------------------

注意:

LPC213XDEF.H文件下载

可将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入0汤圆

发表于 2006-12-27 12:42:28 | 显示全部楼层
把酷帖顶起!把酷帖顶齐!

出0入0汤圆

发表于 2011-4-19 09:03:09 | 显示全部楼层
谢谢 LPC中断
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-6 07:23

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表