微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > S3C2440定时器4中断测试程序

S3C2440定时器4中断测试程序

时间:11-26 来源:互联网 点击:
__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;
}
}

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top