__irq为一个标识,用来表明一个函数是否为中止函数。关于不同的编译器,__irq在函数名中的方位不相同,例如:
ADS编译器中: void __irq IRQ_Eint0(void);
Keil编译器中 : void IRQ_Eint0(void) __irq;
可是其含义相同,它所完结的使命是标识该函数为中止函数,在编译器编译是调用此函数时,先维护函数进口现场,然后履行中止函数,函数履行结束,康复中止现场,这整个进程不需求用户从头编写代码来完结,由编译器主动完结。因此这也给不具备中止嵌套功用的ARM体系带来了问题,若运用 __irq 时有中止嵌套产生,这现场维护就会紊乱。中止嵌套处理能够自己编写中止进口现场维护代码,并不运用 __irq 标识符号。(小呆:详细怎么编写能够嵌套的中止这儿暂时不做研讨。
总结如下
1、若不想自己编写中止进口现场维护代码,并且运用中无中止嵌套,在中止函数顶用 __irq 来标识咱们的中止函数,不然犯错;
2、若程序中要运用中止嵌套,关于无中止嵌套功用的ARM来说,必定要自己编写中止进口现场维护代码,并且不能用 __irq 标识咱们的中止函数,不然犯错。
__irq关键字
在ADS编译器中,“__irq”专门用来声明IRQ中止服务程序,假如用“__irq”来声明一个函数,那么该函数表明一个IRQ中止服务程序,编译器便会主动在该函数内部添加中止现场维护的代码。相同一个函数,假如将关键字“__irq”去掉,那么编译器便不会添加现场维护的代码,而仅仅作为一个一般函数来处理。
现在我们应该对“__irq”关键字有了必定的了解,那么,是不是一切的IRQ中止服务程序都需求运用“__irq”关键字声明呢?其实,这取决于获取“中止服务程序地址”的办法:
假如在履行中止服务函数之前没有对中止现场进行维护,那么中止服务函数有必要要运用“__irq”关键字进行声明。例如,在0x0000 0018处履行指令“LDR PC, [PC, #-0xff0]”,此刻对应的中止服务函数有必要要运用“__irq”关键字进行声明;假如在履行中止服务函数之前现已对中止现场进行了维护,那么中止服务函数不能运用“__irq”关键字进行声明。
//=========================================
// NAME: main.c
// DESC: 内部定时器4LED灯延时
//=========================================
#define U32 unsigned int
#define _ISR_STARTADDRESS 0x33ffff00
#define pISR_TIMER4(*(unsigned *)(_ISR_STARTADDRESS+0x58))
#define rSRCPND(*(volatile unsigned *)0x4a000000) //Interrupt request status 源挂起寄存器
#define rINTMSK(*(volatile unsigned *)0x4a000008)//Interrupt mask control中止屏蔽寄存器
#define rINTPND(*(volatile unsigned *)0x4a000010) //Interrupt request status 中止挂起寄存器
#define rTCFG0(*(volatile unsigned *)0x51000000)//Timer 0 configuration
#define rTCFG1(*(volatile unsigned *)0x51000004)//Timer 1 configuration
#define rTCON(*(volatile unsigned *)0x51000008)//Timer control
#define rTCNTB4 (*(volatile unsigned *)0x5100003c)//Timer count buffer 4
#define rGPBCON(*(volatile unsigned *)0x56000010) //Port B control
#define rGPBDAT(*(volatile unsigned *)0x56000014) //Port B data
#define rGPBUP(*(volatile unsigned *)0x56000018)//Pull-up control B
void led_init(void)
{
//板载LED为GPB[5:8]
rGPBCON = (rGPBCON & ~(0xff<<10)) | (0x55<<10);//rGPBCON为01 装备为输出
rGPBUP= rGPBUP| (0xf<<5);//rGPBUP为1制止上拉
rGPBDAT = rGPBDAT | (0xf<<5);//LED灯全关
}
void led_display(unsigned char data)
{
//0x0全灭 0xf全亮 0x01 0x02 0x04 0x80 各自灯亮
rGPBDAT = (rGPBDAT & ~(0xf<<5)) | ((~data) <<5);
}
void timer4_init(void)
{
rSRCPND = rSRCPND | (0x1<<14);//清空定时器4源恳求
rINTPND = rINTPND | (0x1<<14); //清空定时器4中止恳求
rINTMSK =rINTMSK & ~(0x1<<14);//翻开定时器4中止
//定时器制造寄存器0
//定时器输入时钟频率 = PCLK / {预分频值+1} / {分频值}
//{预分频值} = 0~255 {分频值} = 2, 4, 8, 16
//25KHz:50MHz/(250*8)=50MHz/(2000)
rTCFG0 = (rTCFG0 & ~(0xff<<8)) | (249<<8);// prescaler1:249
rTCFG1 = (rTCFG1 & ~(0xf<<16)) | (0x2<<16);//divider:8,0b0010
rTCNTB4 = 25000;//让定时器4每隔1秒中止一次 25000=1*25000
rTCON = (rTCON & ~(0x7<<20)) | (0x7<<20);//主动重载、手动更新、发动定时器4
rTCON = (rTCON & ~(0x2<<20));//封闭手动更新
}
void __irq timer4_ISR(void)
{
static int count;
rSRCPND = rSRCPND | (0x1<<14);
rINTPND = rINTPND | (0x1<<14);
//每隔0.5秒LED灯亮一次
if (count == 0)
{
led_display(0xf);//LED亮
count = 1;
}
else if (count == 1)
{
led_display(0x0);//LED灭
count = 0;
}
}
void Main(void)
{
led_init();
timer4_init();
pISR_TIMER4 = (U32)timer4_ISR;
while(1);
}
————————————-
pISR_UNDEF=(unsigned)HaltUndef;
任何地址都能够看作变量的指针.pISR_UNDEF就相当于一个指针变量.pISR_UNDEF=(unsigned)HaltUndef;等于把函数HaltUndef的地址存到这个指针变量里.也便是说_ISR_STARTADDRESS+0x4这个地址里存放着HaltUndef的地址.这段代码的意图是给中止函数赋值.当产生中止时,体系会去pISR_UNDEF界说的地址里取出中止函数的地址也便是HaltUndef的地址,然后履行.就相当于当产生中止时,履行HaltUndef函数.
声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/ceping/baogao/257987.html