文章目录
示例代码下载
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
-
它只清除
SRCPND
与INTPND
寄存器对应于数据中设置为1的位的位置,因此清除哪一个中断,只需要对应为写1即可
-
SRCPND
(SOURCE PENDING (SRCPND) REGISTER)
-
INTPND
(INTERRUPT PENDING (INTPND) REGISTER)