ARM架构与编程——异常与中断实战:GPIO中断编程

GPIO中断编程

目的:实现KEY1中断,按下、松开按键,串口输出相应信息。
实现流程:
在这里插入图片描述

1.1 设置PA0为外部中断输入引脚

//key.c
#include "exti.h"
#include "nvic.h"
#include "string.h"

typedef struct
{
  volatile unsigned int EVCR;
  volatile unsigned int MAPR;
  volatile unsigned int EXTICR[4];
  volatile unsigned int RESERVED0;
  volatile unsigned int MAPR2;  
} AFIO_TypeDef;

void key_Init(void)
{
    AFIO_TypeDef *afio = (AFIO_TypeDef *)0x40010000;
    
    unsigned int *pReg;
    unsigned int *pRegA;
    
    /* 1.初始化GPIO引脚PA0,设置为输入引脚 */
    /* enable GPIOA*/
    pReg = (unsigned int *)(0x40021000 + 0x18);
    *pReg |= (1 << 3) | (1 << 2);
    
    
    /* 设置GPIOA0为输入 */
    pRegA = (unsigned int *)(0x40010800 + 0x00);
    *pRegA &= ~(3);     /* mode0 = 0b00 */
    *pRegA &= ~(3 << 2);    /* cnf0 = 0b00 */ 
    *pRegA |= (1 << 2);

    /* 2.设置为EXTI0 */
    afio->EXTICR[0] &= ~0xf;     //设置PA0作为EXTI0
}

1.2 设置EXTI0

1.触发方式
设置双边沿触发,
设置RTSR寄存器中的bit0 为1:上升沿触发

在这里插入图片描述

设置FTSR寄存器中的bit0 为1:下降沿触发

在这里插入图片描述

设置IMR寄存器中的bit0 为1 ,不屏蔽中断,即使能中断

在这里插入图片描述

//exti.c
typedef struct
{
  volatile unsigned int IMR;
  volatile unsigned int EMR;
  volatile unsigned int RTSR;
  volatile unsigned int FTSR;
  volatile unsigned int SWIER;
  volatile unsigned int PR;
} EXTI_TypeDef;

void exti_Init(void)
{
    EXTI_TypeDef *exti = (EXTI_TypeDef *)0x40010400;
    
    /* 1.设置触发方式:双边沿触发 */
    exti->RTSR |= (1<<0);
	exti->FTSR |= (1<<0);
    
    /* 2.使能中断:能够向NVIC发出中断 */
    exti->IMR |= (1<<0);
    
}

1.3 设置NVIC,使能里面的EXTI0

在这里插入图片描述

//nvic.c
/* core_cm3.h */
typedef struct
{
  volatile unsigned int ISER[8];         /*!< Offset: 0x000 (R/W)  Interrupt Set Enable Register           */
  volatile unsigned int RESERVED0[24];   
  volatile unsigned int ICER[8];         /*!< Offset: 0x080 (R/W)  Interrupt Clear Enable Register         */
  volatile unsigned int RSERVED1[24];    
  volatile unsigned int ISPR[8];         /*!< Offset: 0x100 (R/W)  Interrupt Set Pending Register          */
  volatile unsigned int RESERVED2[24];   
  volatile unsigned int ICPR[8];         /*!< Offset: 0x180 (R/W)  Interrupt Clear Pending Register        */
  volatile unsigned int RESERVED3[24];   
  volatile unsigned int IABR[8];         /*!< Offset: 0x200 (R/W)  Interrupt Active bit Register           */
  volatile unsigned int RESERVED4[56];   
  volatile unsigned char  IP[240];             /*!< Offset: 0x300 (R/W)  Interrupt Priority Register (8Bit wide) */
  volatile unsigned int RESERVED5[644];
  volatile unsigned int STIR;            /*!< Offset: 0xE00 ( /W)  Software Trigger Interrupt Register     */
}  NVIC_Type;

void nvic_Init(void)
{
    NVIC_Type *nvic = (NVIC_Type *)0xE000E100;
    
    /* 1.使能EXTI0中断 ,bit6对应的就是中断 DCD     EXTI0_IRQHandler           ; EXTI Line 0*/
    nvic->ISER[0] |= (1<<6);

}

ISER0中的bit0对应异常向量表中的第16项(向量表从第0项开始)。根据中断向量表,我们需要设置 ISER[0] 里面的第6位
在这里插入图片描述

1.4 设置CPU里面的寄存器

最后,我们设置CPU里面的某个寄存器,让它可以去处理中断。

 //cpu_int_enable();

我们在汇编中实现上述操作:
1.向量表中添加中断处理函数

; Vector Table Mapped to Address 0 at Reset
                AREA    RESET, DATA, READONLY
				EXPORT  __Vectors
				IMPORT EXTI0_IRQHandler

__Vectors       DCD     (0x20000000+0x10000)                  
                DCD     Reset_Handler              ; Reset Handler
				DCD     0                ; NMI Handler
                DCD     HardFault_Handler          ; Hard Fault Handler
                DCD     0          ; MPU Fault Handler
                DCD     0           ; Bus Fault Handler
                DCD     UsageFault_Handler_asm         ; Usage Fault Handler
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     SVC_Handler                ; SVCall Handler
                DCD     0           ; Debug Monitor Handler
                DCD     0                          ; Reserved
                DCD     0             ; PendSV Handler
                DCD     SysTick_Handler            ; SysTick Handler
				
				; External Interrupts
                DCD     0            ; Window Watchdog
                DCD     0             ; PVD through EXTI Line detect
                DCD     0          ; Tamper
                DCD     0             ; RTC
                DCD     0           ; Flash
                DCD     0             ; RCC
                DCD     EXTI0_IRQHandler           ; EXTI Line 0	    ;在这里进行中断处理
				
				AREA    |.text|, CODE, READONLY

**2.在Reset_Handler 中使能CPU中断

				;使能cpu中断
				CPSIE I  ; 清除PRIMASK,使能中断

通过操作PRIMASK 寄存器来实现:
在这里插入图片描述
把PRIMASK的bit0设置为1,就可以屏蔽所有优先级可配置的中断。
可以使用这些指令来设置它:

CPSIE I  ; 清除PRIMASK,使能中断
CPSID I  ; 设置PRIMASK,禁止中断

或者:
MOV R0, #1
MSR  PRIMASK R0  ; 将1写入PRIMASK禁止所有中断

MOV R0, #0
MSR PRIMASK, R0  ; 将0写入PRIMASK使能所有中断

EXTI0_IRQHandler函数的实现

//在key.c中实现
void EXTI0_IRQHandler(void)
{
    /* GPIOA input data register */
	unsigned int * pRegA = (unsigned int *)(0x40010800 + 0x08);
    
    if ((*pRegA & (1<<0)) == 0)     /* key1被按下 */
    {
        puts("KEY1 pressed!\n\r");
    }
    else
    {
        puts("KEY1 released!\n\r");
    }
    
    /* 清除中断 */
    exti_clear_int(0);
    nvic_clear_int(6);
    
}

1.5 还要清除相应的寄存器

在设置完上面的一系列寄存器之后,如果没有清除中断,串口将会不断地执行打印操作,所以我们需要从源头开始沿着路线清除中断;即从外部中断控制器EXTI出开始清除

1.先清除EXTI
在这里插入图片描述

//exti.c
void exti_clear_int(int bit)
{
	EXTI_TypeDef * exti = (EXTI_TypeDef *)0x40010400;
	exti->PR |= (1<<bit);
}
//key.c
exti_clear_int(0);

2.再清除NVIC
在这里插入图片描述

//nvic.c
void nvic_clear_int(int bit)
{
    NVIC_Type *nvic = (NVIC_Type *)0xE000E100;
    
    if (bit <= 31)
        nvic->ICPR[0] |= (1<<bit);
}
//key.c
nvic_clear_int(6);

main.c

int mymain()
{
	key_Init();
    exti_Init();
    nvic_Init();
    //cpu_int_enable();
}

程序执行结果:
在这里插入图片描述

扩展
报错:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值