原创 lpc2103中断

2011-4-23 11:00 2457 6 6 分类: MCU/ 嵌入式
以前搞过avr的小车,但是没用到中断,最近虚席arm单片机,也想接触一下中断,看了遍视频教程,感觉arm的中断太难了,完全看不明白,现在不打算全都弄明白,就只会用一种模式的中断就行,会用就行,初始化什么的复制粘贴就行,的复制粘贴就行,会用就行,求一段最简单的中断的“模板”,或者最简单的中断实用的教程,高手帮忙,先谢过了,要是确实是所求,追加悬赏20,谢了
这个是使用IRQ中断的一个定时,你看一下
void __irq Timer0_ISR(void);
void Timer0Init(void)
{
T0TC = 0;
T0PR = 24;
T0MCR = 0x03;
T0MR0 = 100000;
T0TCR = 0x01;
VICIntSelect &= ~( 1<<4 );
VICVectCntl0 = 0x20 | 4;
VICVectAddr0 = (unsigned int)Timer0_ISR;
VICIntEnable = ( 1<<4 );
}
void __irq Timer0_ISR(void)
{
}
一下来自我的空间"hi.baidu/ch314156/blog" "">hi.baidu/ch314156/blog


注意要设定选项,不然中断向量表不位于地址0出,也就无法进入中断例程,具体设定方法是:Options for Target'???'->Linker->选中"Use Memory Layout from Target Dialog"

//*****************************************************************************************
//非向量外部中断C例程
//P0.16做键盘输入,P0.18做LED输出




#include<LPC2103.H>
#define LED 1<<18

void __irq WaiBuZhongDuan(void) // 注意要加“__irq”,告诉编译器,
{ //这是中断例程
if((IOSET&LED)==0) IOSET=LED;
else IOCLR=LED; //将P0.0取反
EXTINT=0X01; //清除中断标志,写1清0
VICVectAddr=0; //清0,通知VIC中断结束
}

int main(void)
{
PINSEL1=0X1; //P0.16选为外部中断0引脚输入
IODIR=LED; //P0.18作为LED输出
EXTMODE=0X01; //边沿触发

VICDefVectAddr=(int)WaiBuZhongDuan; //填入中断例程的地址
VICIntEnable=1<<14; //使能EINT0中断
while(1) ;
}
//*****************************************************************************************
PROTEUS仿真见下:



硬件仿真:




补充说明:程序中没有区分IRQ或FIQ,因为VICIntSelect默认为0即所有中断源都是IRQ。


如果中断不能进入,查看一下CPSR中的I位,如果是1,说明CPSR中断标志禁止中断,所以要将I清0,解决办法是利用一个软件中断,进入管理模式,将SPSR的I清0,返回前将SPSR复制到CPSR中。具体做法有待以后解决。本来是想用内嵌汇编的,但是考虑到用户模式不能对CPSR修改。或者修改一下启动代码。


VICDefVectAddr是非向量IRQ的中断例程地址(与此相似的16个向量IRQ的中断例程地址VICVectAddr0~15),中断触发后,VICDefVectAddr(同样,如果是向量IRQ,相应的VICDefVectAddr0~15)中的值自动进入VICVectAddr,所以PC指向VICVectAddr后就进入相应的中断例程。

那么PC为什么会指向VICVectAddr呢?与C51相似的是,ARM的IRQ触发后,PC会跳到0x00000018地址处,查看Startup里的异常向量表,在地址0x00000018处有这样一条指令: LDR PC, [PC, #-0x0FF0],计算一下 0x00000018+8-0x0FF0=0xFFFFF030,(+8是因为三级流水线),0xFFFFF030就是VICVectAddr的地址。

观察一下异常向量表,和C51的中断向量表比较一下,是不是有相似之处:
ARM:
Vectors LDR PC, Reset_Addr ;0x00000000复位
LDR PC, Undef_Addr ;0x00000004未定义异常
LDR PC, SWI_Addr ;0x00000008软件中断
LDR PC, PAbt_Addr ;0x0000000C预取指中止
LDR PC, DAbt_Addr ;0x00000010数据中止
NOP ;0x00000014保留
; LDR PC, IRQ_Addr
LDR PC, [PC, #-0x0FF0] ;0x00000018中断
LDR PC, FIQ_Addr ;0x0000001C快速中断

C51:
ORG 0003H
SJMP INT0
ORG 000BH
SJMP TIME0
ORG 0013H
SJMP INT1
ORG 001BH
SJMP TIME1
ORG 0023H
SJMP SERIAL


VICIntEnable=1<<14是因为外部中断0的编号为14。


“__irq”如果不写,编译器无法正常处理此中断例程,经测试,如果没有,中断例程不能返回正常,具体原因:若不加“__irq”,编译器把此程序看作普通子程序,返回指令是BX RL,若加“__irq”,编译器把此程序看作中断例程,返回指令是SUBS PC,R14,#4,这才是中断返回的正确指令。


EXTINT是外部中断的中断标志位,写1才能清0,写0无效,硬件仿真证明:如果不清0,中断例程将无限循环。顺便说一句:PROTEUS的虚拟仿真结果和事实(硬件仿真)有差异,比如对EXTINT、EXTMODE,VICVectAddr=0没有真实表现,KEIL的软件仿真效果和事实符合的很好。

经测定:如果没有VICVectAddr=0;这一句代码,程序将不会第二次进入中断例程。
PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
6
关闭 站长推荐上一条 /3 下一条