中断实验(2)

接上一篇文章,上面写到外部中断的3层屏蔽。由于我们今天用到的器材TQ2440,的4个按键K1~K4使用的是
EINT0、EINT1、EINT2、EINT4,这四个中断,其中三个都只需要打开最后一级屏蔽。

下面我们一边对着代码一边介绍怎样打开屏蔽。最后实现中断。首先,我们的程序包含4个需要自己编写的文件,head.S  init.c interrupt.c main.c

首先看head.S,是用汇编写成的,基本定义了整个程序的框架。

.extern    main
.text
.global
_start_start:

b Reset                            @一开始先定义中断向量表,这个必须按照arm说明书上规定的终端向量位置来写,如果写的位置不对,是无法进行中断跳转的,比如在地址0x0位置就一定是 “复位中断”



HandleUndef:

b HandleUndef                 @0x04 未定义指令终止模式的向量地址



HandleSWI:                         @0x08   管理模式的向量地址,通过SWIft指令进入此向量地址

b HandleSWI



HandlePrefetchAbort:

b HandlePrefetchAbort  @0x0c指令预取终止导致的异常的向量地址



HandleDataAbort:

b HandleDataAbort         @0x10数据访问终止导致的异常的向量地址


HandleNotUsed:

b HandleNotUsed            @0x14保留




b HandleIRQ                   @0x18这个就是我们要用到的IRQ中断,0x18是它的向量地址,有人可能要问为什么这里的写法和上面不同,没有HandleIRQ:这个标签。这是因为我们会在下面详细定义,如果像上面那样写,其实是相当于,假如发生了DataAbort中断,就只能在一个死循环里不断运行。


HandleFIQ:                         @0x1c快中断模式的向量地址

b HandleFIQ


Reset:                               @这里就开始详细定义系统复位指令

ldr r0,=0x53000000           @下面这3句汇编实现了一个功能:关看门狗
mov r1,#0x0
str r1,[r0]


msr cpsr_c,#0xd2              @在arm汇编中,唯一能更改cpsr的指令就是msr, cpsr_c是CPSR的低8位,      下面我们来认真分析一下,首先把0xd2换算成2进制,就是110 10010,可参见CPSR各bit的定义,可知CPSR的低5位是工作模式位,如果定义为10010就是进入IRQ(中断模式), 于是这条指令的意义就是进入中断模式

ldr sp,=3072                        @进入中断模式后,这里设置了中断模式下的栈指针,请注意,中断模式是有自己的堆栈寄存器的,就是r13,在这里设置好堆栈指针是因为我们后面会用到


msr cpsr_c,#0xdf                @回到系统模式

ldr sp,=1024*4                    @设置系统模式的栈指针,注意,在这里设置栈指针也是为后面使用C语言服务。


bl init_irq                           @跳转到init_irq,这里直接跳转到了C语言的标签,init_irq,其实就是init_irq函数,
这个函数会在后文详细解释,作用是初始化IRQ中断
msr cpsr_c,#0x5f          @这里打开了IRQ中断,同样把0x5f换算成2进制,010 11111,后5位不变,依然在系统模式下,前3位,第一位就是IRQ禁止位,设置为0就是打开IRQ中断。


ldr lr,=halt_loop               @设置返回地址,arm的返回地址都放在lr寄存器中,lr寄存器就是r14

ldr pc,=main                     @调用main函数

halt_loop:                         @下面是一个死循环

b halt_loop



HandleIRQ:                       @注意,这里就是我们前面提到的,详细定义处理IRQ中断的标签。

sub lr, lr,#4                       @计算返回地址,由于进入异常工作模式时,连接寄存器中保存了前一工作模式的一个指令地址,将它减去一个适当的值,最后付给pc寄存器就可以完成退出中断,具体减去的值需要查表

stmdb sp!, { r0-r12,lr }      @这一条指令一步就完成了保存现场的任务,将R0~R12还有lr的数据保存在堆栈寄存器中,堆栈寄存器在保存第一个值之前增加,增长方式为向下增长。sp指针我们在之前定义过了,现在就用到了


ldr lr,=int_return             @设置调用EINT_Hanle函数后的返回地址

ldr pc,=EINT_Handle     @调用中断服务函数,同样是一个C函数,在interrupt.c中,之后会详细介绍.

int_return:

ldmia sp!, { r0-r12,pc }^        @中断返回,^表示将spsr的值复制到cpsr,同样,相当于一步恢复现场



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值