Chinaunix首页 | 论坛 | 博客
  • 博客访问: 99923
  • 博文数量: 20
  • 博客积分: 1610
  • 博客等级: 上尉
  • 技术积分: 230
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-22 16:05
文章分类

全部博文(20)

文章存档

2012年(1)

2011年(8)

2010年(11)

我的朋友

分类: 嵌入式

2010-10-10 03:06:39

这个例子演示了ARM汇编如何去编写一个中断响应程序。

对于外部引脚的中断,需要配置外部引脚为中断模式(EINT)。

之后如果需要配置引脚的触发方式,默认采用低电平触发方式,你还是设置成高电平触发、上升沿触发、下降沿触发、两边沿触发。这些方式的设置在EXTINTn中设置。接着可以设置中断屏蔽位INTMASK。

最后就是编写中断响应程序了。

中断响应程序中的需要固定的设置

;返回地址等于中断地址减4
sub lr, lr, #4
;保存现场
stmdb {r0-r12,lr}

;这里需要关中断,否则程序一直响应某个中断

;恢复现场
ldmia {r0-r12,pc}^


GPFCON EQU 0x56000050
GPFDAT EQU 0x56000054
GPGCON EQU 0x56000060
GPGDAT EQU 0x56000064

SRCPND EQU 0X4A000000
INTMSK EQU 0X4A000008
PRIORITY EQU 0x4A00000C
INTPND EQU 0X4A000010
INTOFFSET EQU 0x4A000014
EINTMASK EQU 0x560000a4
EINTPEND EQU 0x560000a8

    AREA KEY_LED_INT, CODE, READONLY ;这里表示此区域是只读代码"KEY_LED"
    EXPORT _ENTRY ;引入程序入口
    
_ENTRY

    b START ;程序从START开始执行
    b . ;0x4
    b . ;0x8
    b . ;0xc
    b . ;0x10
    b . ;0x14
    b IRQ_HANDLER ;0x00000018中断入口
    b . ;0x1c

;程序从这里开始运行
START
    ldr sp, =4096 ;初始化当前模式(系统模式)栈指针
    
    msr cpsr_c, #0x92 ;设置当前模式为中断模式
    ldr sp, =3072 ;初始化中断模式的栈指针
    
    bl INIT_CONF ;跳转到中断初试化
    
    msr cpsr_c, #0x5f ;定义当前模式为系统模式,并开启中断允许
    
    
LOOP
    ;将LED熄灭
    ldr r0, =GPFDAT
    mov r1, #0xff
    str r1, [r0]
    b LOOP

INIT_CONF
    ;GPIO的配置
    ;这里包括K1~K4中断配置和LED1~LED4的配置
    ldr r0, =GPFCON
    ldr r1, =0x55aa
    str r1, [r0]
    
    ;K5和K6的配置,配置成中断模式
    ldr r0, =GPGCON
    ldr r1, =0x00800080
    str r1, [r0]
    
    ;初始化将led都熄灭
    ldr r0, =GPFDAT
    mov r1, #0xf0
    str r1, [r0]
    
    ;初始化中断屏蔽位
    ldr r0, =INTMSK
    ldr r1, = 0xffffffd0
    str r1, [r0]

    ;初始化外中断屏蔽位
    ldr r0, =EINTMASK
    ldr r1, = 0xf7f7ff ;
    str r1, [r0]
    
    ;函数返回
    mov pc, lr
    
IRQ_HANDLER
    ;返回地址等于中断地址减4
    sub lr, lr, #4
    ;保存现场
    stmdb {r0-r12,lr}
    
    ;得到offset寄存器的值,它反映了触发中断的中断号
    ldr r0, =INTOFFSET
    ldr r2, [r0]
    
    ;得到LED的状态数据寄存器
    ldr r0, =GPFDAT
    ldr r1, [r0]
    
    ;判断是否触发了INT0,即按键1的中断
    cmp r2, #0
    ;是则重新布置LED状态
    moveq r1, #0xef
    beq INIT_OVER
    
    ;INT1,按键2
    cmp r2, #1
    moveq r1, #0xdf
    beq INIT_OVER
    
    ;INT2,按键3
    cmp r2, #2
    moveq r1, #0xcf
    beq INIT_OVER
    
    ;INT3, 按键4
    cmp r2, #3
    moveq r1, #0xbf
    beq INIT_OVER
    
    ;INT5,它可能是按键5和6发生了中断,按键5和6引脚比较特殊
    cmp r2, #5
    ;如果不是,跳转到结束标志
    bne INIT_OVER
    ;如果是,就看EINTPEND的值,它必定有一个中断被置1
    ldr r2, =EINTPEND
    ldr r3, [r2]
    
    ;如果是11号引脚发生中断,即按键5发生了中断
    tst r3, #0x800 ;2^11
    movne r1, #0xaf
    bne INIT_OVER
    
    ; 如果是19号引脚发生中断,即按键6发生了中断
    tst r3, #0x80000 ;2^19
    movne r1, #0x9f
    bne INIT_OVER
    
    
INIT_OVER
    ;更新LED状态
    str r1, [r0]
    
    ;清除所有中断
    ldr r0, =EINTPEND
    mov r1, #0xfffffff
    str r1, [r0]
    
    ldr r0, =INTPND
    mov r1, #0xff
    str r1, [r0]
    
    ldr r0, =SRCPND
    mov r1, #0xff
    str r1, [r0]

    ;恢复现场
    ldmia {r0-r12,pc}^
    
    END


阅读(2801) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~