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

2006-12-25 00:26 4777 12 12 分类: MCU/ 嵌入式
LPCARM中断非典方法大全圣诞裸奔程序详解(更新)
雁塔菜农 发表于 2006-12-24 22:00:00


/*----------------------------------------------------------------------------------
          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目录下

 

点击下载本裸奔工程包:uploadfile-/2006-12/1225579810.rar

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


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最高优先级
   IRQ_EINT1;//设置中断服务程序地址见Startup_Table.S
   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个中断向量。
   特别注意非典的默认中断向量内不是中断的地址而是序号16~31.
6. 非典与经典的最大不同在于前者的VIC->VectAddrs[x]内不是地址而是向量数组的序号。
   非典的中断向量地址需要在Startup_Table.s即FLASH内设置。
   而经典的中断向量地址需要在VIC->VectAddrs[x]或VIC->DefVectAddr即RAM内设置真正的中断向量地址。
--------------------------------------------------------------------------------------------*/


  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)31;//16~31都可//定义除VIC->VectAddrs[0]~VIC->VectAddrs[15]外的中断函数


  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中断


/*--------------------------------------------------------------------------
  下列循环是非典的精华所在,其思路请到菜地的[非典型LPCARM之攻防体系]里寻找。
user1/46/cmd.html?do=blogs&id=1240&uid=46


  其他需要Startup_Hot.s支持,以配合非典的拦截工作。
---------------------------------------------------------------------------*/
  for (i = 0;i <= 15; i ++) {
    VIC->VectAddrs = i;//刷新向量地址寄存器VICVectAddr0~VICVectAddr15
  }
 


  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);//软件模拟用户软件中断(失败!!!)


  Enable_IRQ();//注意现在立即进入EINT1硬件中断(因为假定P0.3/P0.14都为高电平)
  VIC->SoftInt = (1 << VICIntSel_SoftInt22);//软件模拟用户软件中断(成功!!!)


  VIC->SoftInt = (1 << VICIntSel_EINT1);//软件模拟向量中断1(成功!!!)


  VIC->Protection = 1;//关闭在用户级对VIC的一些写操作
  VIC->Protection = 0;;//在用户级试图写'0'无效!!!应该用Enable_VIC();或SetVICProtection(0);
  while(i == 0) {//不会进入死循环
    __nop();
  }
 
  i = SetVICProtection(0);//进入特权级打开对VIC的一些写操作的保护


  VIC->IntEnable |= (1 << VICIntSel_SoftInt23);//使能非法用户软件中断
  VIC->IntEnable |= (1 << VICIntSel_SoftInt24);//使能非法用户软件中断
  VIC->IntEnable |= (1 << VICIntSel_SoftInt25);//使能非法用户软件中断
  VIC->IntEnable |= (1 << VICIntSel_SoftInt26);//使能非法用户软件中断


  Disable_IRQ();//关闭向量中断总开关
  PINSEL->PIN_SEL0  |= (P0_7_EINT2 << P0_7_PINSEL);   //选择P0.7为INT2外部中断引脚
  INTCON->EXT_POLAR  &= ~(1 << EXTPOLAR2); //INT2为低电平有效
  INTCON->EXT_MODE   |=  (1 << EXTMODE2); //设置INT2为边沿触发
//  INTCON->EXT_MODE   &= ~(1 << EXTMODE2); //设置INT2为电平触发
  VIC->IntEnable |= (1 << VICIntSel_EINT2);//使能非法外部中断2
/*----------------------------------------------------------------------------------------------
以下几句引发非法用户软件中断后VIC->VectAddr值为VIC->DefVectAddr,故程序飞入IRQ_Default()处执行。
-----------------------------------------------------------------------------------------------*/
  VIC->SoftInt = (1 << VICIntSel_SoftInt23);//软件模拟非法用户软件中断(程序飞)
  VIC->SoftInt = (1 << VICIntSel_SoftInt24);//软件模拟非法用户软件中断(程序飞)
  VIC->SoftInt = (1 << VICIntSel_SoftInt25);//软件模拟非法用户软件中断(程序飞)
  VIC->SoftInt = (1 << VICIntSel_SoftInt26);//软件模拟非法用户软件中断(程序飞)
  VIC->SoftInt = (1 << VICIntSel_EINT2);//软件模拟非法INT2软件中断(程序飞!!!)


  INTCON->EXT_INT = (1 << EINT2);//清除非法INT2中断标志
  VIC->SoftIntClr = (1 << VICIntSel_EINT2);//清除非法INT2软件中断标志


  Enable_IRQ();//开放向量中断总开关


  VIC->Protection = 1;//关闭在用户级对VIC的一些写操作,保护在用户级VIC不被以外改写
  while(i == 0) {//进入死循环
    __nop();
  }
}

文章评论0条评论)

登录后参与讨论
我要评论
0
12
关闭 站长推荐上一条 /2 下一条