×
单片机 > 单片机程序设计 > 详情

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

发布时间:2020-08-21 发布时间:
|

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<

INTPND = (1<

}


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


它只清除SRCPND与INTPND寄存器对应于数据中设置为1的位的位置,因此清除哪一个中断,只需要对应为写1即可

SRCPND(SOURCE PENDING (SRCPND) REGISTER)

INTPND(INTERRUPT PENDING (INTPND) REGISTER)




『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
单片机制作超级流水灯