中断服务函数管理

本文详细解析了ARM架构下的中断处理流程,包括中断函数结构、异常处理、硬件中断信号响应及现场保存恢复过程。同时介绍了通过中断服务函数管理与调用实现按键控制的具体方法,涉及按键初始化、中断触发配置及中断服务函数设计。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

中断函数的结构
这里是由硬件检测到中断信号跳转过来
o_irq:
/* 执行到这里之前:
* 1. lr_irq保存有被中断模式中的下一条即将执行的指令的地址
* 2. SPSR_irq保存有被中断模式的CPSR
* 3. CPSR中的M4-M0被设置为10010, 进入到irq模式
* 4. 跳到0x18的地方执行程序
*/

/* sp_irq未设置, 先设置它 */
ldr sp, =0x33d00000

/* 保存现场 */
/* 在irq异常处理函数中有可能会修改r0-r12, 所以先保存 */
/* lr-4是异常处理完后的返回地址, 也要保存 */
sub lr, lr, #4
stmdb sp!, {r0-r12, lr}  

/* 处理irq异常 */
bl handle_irq_c

/* 恢复现场 */
ldmia sp!, {r0-r12, pc}^  /* ^会把spsr_irq的值恢复到cpsr里 */

定义一个函数指针数组,存放中断服务函数
typedef void(*irq_func)(int);
irq_func irq_array[32];

中断服务函数注册函数
void register_irq(int irq, irq_func fp)
{
irq_array[irq] = fp;

INTMSK &= ~(1<<irq);

}
中断服务函数 对实体的中断服务函数进行管理、调用
void handle_irq_c(void)
{
/* 分辨中断源 */
int bit = INTOFFSET;

/* 调用对应的处理函数 */
irq_array[bit](bit);

/* 清中断 : 从源头开始清 */
SRCPND = (1<<bit);
INTPND = (1<<bit);	

}

/* 初始化按键, 设为中断源 /
void key_eint_init(void)
{
/
配置GPIO为中断引脚 /
GPFCON &= ~((3<<0) | (3<<4));
GPFCON |= ((2<<0) | (2<<4)); /
S2,S3被配置为中断引脚 */

GPGCON &= ~((3<<6) | (3<<22));
GPGCON |= ((2<<6) | (2<<22));   /* S4,S5被配置为中断引脚 */


/* 设置中断触发方式: 双边沿触发 */
EXTINT0 |= (7<<0) | (7<<8);     /* S2,S3 */
EXTINT1 |= (7<<12);             /* S4 */
EXTINT2 |= (7<<12);             /* S5 */

/* 设置EINTMASK使能eint11,19 */
EINTMASK &= ~((1<<11) | (1<<19));

register_irq(0, key_eint_irq);
register_irq(2, key_eint_irq);
register_irq(5, key_eint_irq);

}
void key_eint_irq(int irq)
{
unsigned int val = EINTPEND;
unsigned int val1 = GPFDAT;
unsigned int val2 = GPGDAT;

if (irq == 0) /* eint0 : s2 控制 D12 */
{
	if (val1 & (1<<0)) /* s2 --> gpf6 */
	{
		/* 松开 */
		GPFDAT |= (1<<6);
	}
	else
	{
		/* 按下 */
		GPFDAT &= ~(1<<6);
	}
	
}
else if (irq == 2) /* eint2 : s3 控制 D11 */
{
	if (val1 & (1<<2)) /* s3 --> gpf5 */
	{
		/* 松开 */
		GPFDAT |= (1<<5);
	}
	else
	{
		/* 按下 */
		GPFDAT &= ~(1<<5);
	}
	
}
else if (irq == 5) /* eint8_23, eint11--s4 控制 D10, eint19---s5 控制所有LED */
{
	if (val & (1<<11)) /* eint11 */
	{
		if (val2 & (1<<3)) /* s4 --> gpf4 */
		{
			/* 松开 */
			GPFDAT |= (1<<4);
		}
		else
		{
			/* 按下 */
			GPFDAT &= ~(1<<4);
		}
	}
	else if (val & (1<<19)) /* eint19 */
	{
		if (val2 & (1<<11))
		{
			/* 松开 */
			/* 熄灭所有LED */
			GPFDAT |= ((1<<4) | (1<<5) | (1<<6));
		}
		else
		{
			/* 按下: 点亮所有LED */
			GPFDAT &= ~((1<<4) | (1<<5) | (1<<6));
		}
	}
}

EINTPEND = val;

}

//出入均设有缓冲区,大小可任意设置。 //可供使用的函数名: //char getbyte(void);从接收缓冲区取一个byte,如不想等待则在调用前检测inbufsign是否为1。 //getline(char idata *line, unsigned char n); 获取一行数据回车结束,必须定义最大输入字符数 //putbyte(char c);放入一个字节到发送缓冲区 //putbytes(unsigned char *outplace,j);放一串数据到发送缓冲区,自定义长度 //putstring(unsigned char code *puts);发送一个定义在程序存储区的字符串到串口 //puthex(unsigned char c);发送一个字节的hex码,分成两个字节发。 //putchar(uchar c,uchar j);输出一个无符号字符数的十进制表示,必须标示小数点的位置,自动删除前面无用的零 //putint(uint ui,uchar j);输出一个无符号整型数的十进制表示,必须标示小数点的位置,自动删除前面无用的零 //delay(unsigned char d); 延时n x 100ns //putinbuf(uchar c);人工输入一个字符到输入缓冲区 //CR;发送一个回车换行 //************************************************************************* #include <w77e58.h> #define uchar unsigned char #define uint unsigned int #define OLEN 32 /* size of serial transmission buffer */ idata unsigned char outbuf[OLEN]; /* storage for transmission buffer */ unsigned char idata *outlast=outbuf; //最后由中断传输出去的字节位置 unsigned char idata *putlast=outbuf; //最后放入发送缓冲区的字节位置 #define ILEN 12 /* size of serial receiving buffer */ idata unsigned char inbuf[ILEN]; unsigned char idata *inlast=inbuf; //最后由中断进入接收缓冲区的字节位置 unsigned char idata *getlast=inbuf; //最后取走的字节位置 bit outbufsign0; //最后一个数据覵BUF发完标志 发完=0 bit outbufsign; //输出缓冲区非空标志 有=1 bit inbufsign; //接收缓冲区非空标志 有=1 bit inbufful; //输入缓冲区满标志 满=1 #define CR putstring("\r\n") //CR=回车换行 //***************************** //延时n x 100ns void delay(unsigned char d) //在源程序开头定义是否用w77e58或22。1184M晶振 {unsigned char j; do{ d--; //110592 & 89c52 #ifndef cpuw77e58 #ifndef xtal221184 j=21; //k=38 cpu80320 100us k="21" cpu 8052 #else j=42; #endif #else #ifndef xtal221184 j=38; #else j=76;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值