2440裸机编程之四 外部中断


2440有60个中断源(有的中断源还有几个子中断源),中断原理如下图:


中断源使中断源请求寄存器(SRCPND)的相应位置一,中断模式寄存器(INTMOD)选择是IRQ还是FIQ模式,如果是IRQ,在中断屏蔽寄存器(INTMSK)不屏蔽的情况下,会产生中断,同时中断请求寄存器(INTPND)的相应位被置一。

2440 外部中断 编程步骤:
外部中断初始化()
{
引脚初始化: 设置相应引脚为外部中断功能 GPxCON
  选择相应触发模式    EXTINT
中断初始化: 清除SRCPNF、INTPND中的相应中断标志位
  中断例程地址 -> 中断向量表 pISR_EINTx
  使能相应中断 rINTMSK
}

中断例程()  __irq
{
  ……中断程序……
  清除SRCPNF(先)、INTPND(后)中的相应中断标志
}

这是一个外部中断0的实验程序(GPF0作外部中断源):
//********************************************************************
void Main(void)
{     
    int i;
    ……硬件初始化……

Eint0_init();
while(1);
}
void  Eint0_init(void)  //EINT0初始化
{
Uart_Printf("\n外部中断实验:Eint0\n"); 
rGPFCON = rGPFCON & ~7 |  2  ; //设置GPF0 为 外部中断模式
rEXTINT0 = rEXTINT0 & ~7 | 2   ;//设置EINT0 为 下降沿触发
rSRCPND = 1;     //SRCPND写1清0
rINTPND = 1;     //INTPND写1清0
pISR_EINT0 = (U32)Eint0_ISR; //向向量表申请中断向量
rINTMSK = rINTMSK & ~(1);  //禁止EINT0的屏蔽
}

void   Eint0_ISR(void) __irq  //EINT0中断例程
{
Uart_Printf("你按了一次Eint0引脚的按键\n"); 
rSRCPND = 1;  //清楚EINT0中断标志
rINTPND = 1; 
}
//*******************************************************************

运行结果如图:



注意中断标志的清除顺序:SUBSRCPND(如果有)->SRCPND->INTPND  ,如果不这样做,中断例程结束后,还会再次引起额外的中断
注意 pISR_EINT0 = (U32)Eint0_ISR;每一个中断例程运行之前,都要把它的地址交给中断向量表(此指60个中断源的eboot中断向量表,非地址0处的异常中断向量表,IRQ发生时,PC先指向异常中断向量表的IRQ位置,再跳转到eboot中断向量表),以在中断发生时,正确进入相应的中断例程,其实是把INTOFFSET中的中断号转换成(在eboot中断向量表的)偏移地址。



外部中断又24个,但不都是一致的,如下图:

EINT0、EINT1、EINT2、EINT3是四个独立的中断源,而EINT4~7组成一个中断源,EINT8~23组成一个中断源。
那么EINT4~7的中断程序如何写,显然不能用EINT0的方式,不然EINT4~EINT7的四个源相互之间无法被区分开,EINT8~23也同理。
所以为了区分它们,要用到EINTMASK和EINTPEND,EINTMASK每一位对应EINT4~EINT23的屏蔽,其他位保留;EINTPEND每一位对应EINT4~EINT23的中断请求,其他位保留;这样就可以顺利区分EINT4~EINT23了。

下面是Eint2和Eint11的中断程序
//********************************************************************
void Main(void)
{     
    int i;
    ……硬件初始化……

Uart_Printf("\n外部中断实验:Eint2 和 Eint8_23\n");
Eint2_init();
Eint8_23_init(); //EINT11初始化
while(1);
}
void  Eint2_init(void)  //EINT2初始化
{
rGPFCON = rGPFCON & ~3<<4 |  2<<4  ; //设置GPF2 为 外部中断模式
rEXTINT0 = rEXTINT0 & ~7<<8 | 4<<8   ;//设置EINT2 为 上升沿触发
rSRCPND = 1<<2;     //SRCPND写1清0
rINTPND = 1<<2;     //INTPND写1清0
pISR_EINT2 = (U32)Eint2_ISR;  //填入Eint2的中断向量
rINTMSK = rINTMSK & ~(1<<2);  //禁止EINT2的屏蔽
}

void   Eint2_ISR(void) __irq  //EINT2中断例程
{
Uart_Printf("你按了一次Eint2引脚的按键\n"); 
rSRCPND = 1<<2;  //清楚EINT2中断标志
rINTPND = 1<<2;
}

void  Eint8_23_init(void)  //Eint8_23初始化
{
rGPGCON = rGPGCON & ~3<<6 |  2<<6  ; //设置GPG3 为 外部中断模式
rEXTINT1 = rEXTINT1 & ~7<<12 | 2<<12   ;//设置EINT11 为 下降沿触发
rEINTPEND = 1<<11;    //***EINTPEND中的 EINT11位 清0
rSRCPND = 1<<5;     //SRCPND中的 Eint8_23位 清0
rINTPND = 1<<5;     //INTPND中的 Eint8_23位 清0
pISR_EINT8_23 = (U32)Eint8_23_ISR;  //填入Eint8_23的中断向量
rEINTMASK = rEINTMASK & ~(1<<11);  //***禁止EINT11的屏蔽
rINTMSK = rINTMSK & ~(1<<5);  //禁止Eint8_23的屏蔽
}

void   Eint8_23_ISR(void) __irq  //EINT2中断例程
{
Uart_Printf("你按了一次Eint8_23引脚的按键\n");
rEINTPEND = 1<<11;    //***EINTPEND中的 EINT11位 清0
rSRCPND = 1<<5;     //SRCPND中的 Eint8_23位 清0
rINTPND = 1<<5;     //INTPND中的 Eint8_23位 清0
}
//*******************************************************************

结果如下:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值