【ARM裸板】按键外部中断过程及示例

示例代码下载

1.初始化

  • 设置中断源(让它能发出中断信号)
  • 设置中断控制器(让它能发出中断信号给CPU)
  • 设置CPU总开关(CPSR有I位,设置总开关,使能中断)

处理时要分辨中断源
处理完要清中断

在这里插入图片描述

1.1 中断源

  • 设置按键为中断源引脚
    • 配置引脚为外部中断模式
    • 配置中断为下降沿触发
    • 配置外部中断MASK使能
//初始化外部中断,设置按键为中断源
void key_eint_init(void)
{
	/* 引脚:GPF0、2   GPG3、11 */
	/* 中断:EINT0、2  EINT11、19*/
	GPFCON &= ~((3<<0) | (3<<4)); //清零
	GPFCON |=  ((2<<4) | (2<<0)); //设置[10],配置为外部中断

	GPGCON &= ~((3<<6) | (3<<22));
	GPGCON |=  ((2<<6) | (2<<22)); //设置[10],配置为外部中断

	/* 设置中断触发方式:双边沿触发 */
	EXTINT0 |= (3<<0) | (3<<8); //配置EINT0、2
	EXTINT1 |= (3<<12); //配置EINT11
	EXTINT2 |= (3<<12); //配置EINT19

	/* 设置外部MASK清零使能 */
	EINTMASK &= ((1<<11) | (1<<19));
}

在这里插入图片描述

1.2 中断控制器

  • 设置INTMASK(INTERRUPT MASK (INTMSK) REGISTER)中断屏蔽寄存器
    • 0 = Interrupt service is available.
    • 1 = Interrupt service is masked.
//初始化中断控制器
void interrupt_init(void)
{
	INTMASK &= ~((1<<0) | (1<<2) | (1<<5));//使能中断
}

在这里插入图片描述

1.3 CPU使能中断

  • 设置CPSR的I位
  • 当设置为0时enable,设置为1时disable
mrs r0,cpsr    //读出CPSR
bic r0,r0,#(1<<7) //第7位清零(IRQ)
msr cpsr,r0

在这里插入图片描述
在这里插入图片描述

1.4 start.S设置中断向量表

  • 0x18处调用中断服务函数
/*====================================异常向量表===========================================*/
_start:
	b reset   		 //vector 0x00: reset(0地址对应reset)
 	ldr pc, und_addr //vector 0x04: und  (发生未定义指令异常,则进入“处理未定义异常函数”)绝对跳转,跳转至sdram中
 	ldr pc, swi_addr //vector 0x08: swi
 	b halt           //vector 0x0c: prefetch aboot
 	b halt           //vector 0x10: data aboot
 	b halt           //vector 0x14: reserved
 	bl irq_addr      //vector 0x18: IRQ
  	b halt           //vector 0x1c: FIQ	
    
irq_addr:
	.word do_irq

在这里插入图片描述

1.5 start.S设置中断处理

  • 执行中断处理之前,硬件会处理的事情:
  • 1.lr_irq保存有被中断模式中的下一条即将执行的指令的地址
  • 2.SPSR_irq保存被中断模式CPSR
  • 3.CPSR的[M4:M0]=[10010],进入到irq模式
  • 4.跳到0x08的模式执行程序,即跳到bl do_irq这一指令

1.5.1 设置栈

  • sp_irq 设置栈,因为后面函数需要栈
    ldr sp, =0x33D00000

1.5.2 保存现场

  • 在irq处理函数总有可能需要用到r0~r12,因此先保存下来
  • 由下图可知,lr-4是异常处理完后的返回地址,也需要保存
    sub lr,lr,#4
    stmdb sp!, {r0-r12,lr} 

在这里插入图片描述

1.5.3 处理中断

  • 跳转到中断处理函数中
    bl handle_irq_c

1.5.4 恢复现场

  • 将lr的值赋给pc ,^会把spsr的值恢复到cpsr中
    ldmia sp,{r0-r12,pc}^ 

2.中断服务函数

void handle_irq_c(void)
{
	/* 1.分辨中断源 */
	int bit = INTOFFSET;

	/* 2.调用对应的处理函数 */
	key_eint_irq(bit); //处理中断,清除外部中断标志

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

2.1 分辨中断源

  • 中断偏移寄存器 (INTERRUPT OFFSET (INTOFFSET) REGISTER)
  • 可通过判断INTOFFEST的中的可知当前中断源

在这里插入图片描述

2.2 调用处理函数

  • 该为触发外部中断,因此需要清除外部中断
  • EINTPEND (External Interrupt Pending Register)
  • 清除该中断,只需要对应写1即可,又因为其发生什么中断,对应为会变成1,因此产生什么中断,只需要把该中断的EINTPEND的值写入EINTPEND
	/* 2.调用对应的处理函数 ,清除对应的中断*/
	key_eint_irq(bit); 

在这里插入图片描述

2.3 清中断

  • 从源头开始清:即先清除SRCPND,再清除INTPND

  • 它只清除SRCPNDINTPND寄存器对应于数据中设置为1的位的位置,因此清除哪一个中断,只需要对应为写1即可
    在这里插入图片描述

  • SRCPND(SOURCE PENDING (SRCPND) REGISTER)
    在这里插入图片描述

  • INTPND(INTERRUPT PENDING (INTPND) REGISTER)
    在这里插入图片描述

发布了42 篇原创文章 · 获赞 176 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_39492932/article/details/104111516