【ARM】Day8 中断

本文介绍了在STM32MP1xx平台上,如何使用GPIO、EXTI和GIC实现三个按键的中断触发,以及对应的LED灯状态反转。通过HAL库,详细展示了EXTI中断配置、GPIO初始化和GIC中断处理的过程。
摘要由CSDN通过智能技术生成

1. 思维导图

2. 实验要求: 实现KEY1/LEY2/KE3三个按键,中断触发打印一句话,并且灯的状态取反 key1 ----> LED3灯状态取反 key2 ----> LED2灯状态取反 key3 ----> LED1灯状态取反

key3.h

#ifndef __KEY3_H__
#define __KEY3_H__

#include "stm32mp1xx_rcc.h"
#include "stm32mp1xx_gpio.h"
#include "stm32mp1xx_uart.h"
#include "stm32mp1xx_gic.h"
#include "stm32mp1xx_exti.h"

//key1-->PF9
//key2-->PF7
//key3-->PF8

typedef enum
{
	EXTI1 = 1,
	EXTI2,
	EXTI3,
	EXTI4,
	EXTI5,
	EXTI6,
	EXTI7,
	EXTI8,
	EXTI9,
	EXTI10,
	EXTI11,
	EXTI12,
	EXTI13,
	EXTI14,
	EXTI15
}exti_event_t;

//终端触发方式
typedef enum
{
    RISING_TRIGGER = 0,
    FALLING_TRIGGER
} trigger_t;

void hal_exti_init(exti_event_t exti_event,unsigned int ground,trigger_t trigger); 	//RCC/GPIO/EXTI章节初始化
void hal_gic_init(unsigned int interruptid,unsigned int priority) ; 	//GIC章节初始化


#endif

led.h

#ifndef _LED_H__   //防止头文件重复包含_
#define _LED_H__

#include "stm32mp1xx_gpio.h"

//RCC_MP_AHB4ENSETR寄存器封装
#define	RCC_MP_AHB4ENSETR (*(volatile unsigned int*)0x50000A28)


//对引脚编号进行封装
#define GPIO_PIN_0 0
#define GPIO_PIN_1 1
#define GPIO_PIN_2 2
#define GPIO_PIN_3 3
#define GPIO_PIN_4 4
#define GPIO_PIN_5 5
#define GPIO_PIN_6 6
#define GPIO_PIN_7 7
#define GPIO_PIN_8 8
#define GPIO_PIN_9 9
#define GPIO_PIN_10 10
#define GPIO_PIN_11 11
#define GPIO_PIN_12 12
#define GPIO_PIN_13 13
#define GPIO_PIN_14 14
#define GPIO_PIN_15 15


//使用枚举封装MODER寄存器
typedef enum{
	INPUT,	//输入 0
	OUTPUT,	//输出 1
	ALT,	//复用 2
	ANALOG	//模拟 3
}gpio_moder_t;

//使用枚举封装OTYPER寄存器
typedef enum{
	PP,	//推挽 0
	DP	//开漏 1
}gpio_otyper_t;


//使用枚举封装OSPEEDR寄存器
typedef enum{
	LOWSPEED,	//低速 0
	MEDSPEED,	//中速 1
	HIGHSPEED,	//高速 2
	VERYHIGHSPEED	//快速 3 
}gpio_ospeedr_t;

//使用枚举封装PURDR寄存器
typedef enum{
	NO_PUPDR,	//禁止上下拉电阻 0
	PU,	//上拉 1
	PD	//下拉 2
}gpio_pupdr_t;


//封装初始化结构体
typedef struct{
	gpio_moder_t moder;	//模式寄存器
	gpio_otyper_t otyper;	//输出类型寄存器
	gpio_ospeedr_t ospeedr;	//输出速率寄存器
	gpio_pupdr_t pupdr;	//是否上下电阻寄存器
}gpio_init_t;

//使用枚举封装ODR寄存器
typedef enum{
	GPIO_RESET_T,	//熄灭 0
	GPIO_SET_T	//点亮 1
}gpio_status_t;


//函数功能:GPIO引脚初始化操作
//参数1:GPIO组号
//参数2:引脚编号
//参数3:初始化内容
void hal_gpio_init(volatile gpio_t * gpiox,unsigned int pin,gpio_init_t* init);


//函数功能:GPIO引脚操作,写1点亮,写0熄灭
//参数1:GPIO组号
//参数2:引脚编号
//参数3:写的内容
void hal_gpio_write(volatile gpio_t* gpiox,unsigned int pin,gpio_status_t status);


#endif

key3.c

#include "key3.h"


//key1 -----> PF9
//key2 -----> PF7
//key3 -----> PF8
void hal_exti_init(exti_event_t exti_event,unsigned int ground,trigger_t trigger) 	//RCC/GPIO/EXTI章节初始化
{
	//RCC章节初始化
		//使能GPIOF组控制器  -----> RCC_MP_AHB4ENSETR[5] = 1
	RCC->MP_AHB4ENSETR |= (0x1 << 5);

	//GPIO章节初始化
  		//设置KEY1按键为输入模式  -----> GPIOF_MODER[19:18] = 00
  		//设置KEY2按键为输入模式  -----> GPIOF_MODER[15:14] = 00
  		//设置KEY3按键为输入模式  -----> GPIOF_MODER[17:16] = 00
	GPIOF->MODER &= (~(0x3f << 14));

	//EXTI章节初始化
	//1、EXTI_EXTICRn(n=1~4):EXTI external interrupt selection register  ===> 外部中断选择寄存器, 
		//设置KEY1按键与EXTI9进行连接,EXTI_EXTICR3[15:8] = 0x05,
		//设置KEY2按键与EXTI7进行连接,EXTI_EXTICR2[31:24] = 0x05
		//设置KEY1按键与EXTI8进行连接,EXTI_EXTICR3[7:0] = 0x05
	switch(exti_event / 4)
	{
		case 0:
			EXTI->EXTICR1 &= (~(0xff << (exti_event % 4 *8)));
			EXTI->EXTICR1 |= (ground << (exti_event % 4 *8));
			break;
		case 1:
			EXTI->EXTICR2 &= (~(0xff << (exti_event % 4 *8)));
			EXTI->EXTICR2 |= (ground << (exti_event % 4 *8));
			break;
		case 2:	
			EXTI->EXTICR3 &= (~(0xff << (exti_event % 4 *8)));
			EXTI->EXTICR3 |= (ground << (exti_event % 4 *8));
			break;
		case 3:	
			EXTI->EXTICR4 &= (~(0xff << (exti_event % 4 *8)));
			EXTI->EXTICR4 |= (ground << (exti_event % 4 *8));
			break;
		default:break;
	}

	//2、下降沿触发选择寄存器,EXTI_FTSR1[9] = 1,EXTI_FTSR1[7] = 1,EXTI_FTSR1[8] = 1
	if(trigger == RISING_TRIGGER)
	{
		EXTI->RTSR1 |= (0x1 << exti_event);
	}
	else if(trigger == FALLING_TRIGGER)
	{
		EXTI->FTSR1 |= (0x1 << exti_event);
	}
	//3、设置中断屏蔽寄存器,EXTI_IMR1[9] = 1,EXTI_IMR1[7] = 1,EXTI_IMR1[8] = 1
	EXTI->C1IMR1 |= (0x1 << exti_event);
}

void hal_gic_init(unsigned int interruptid,unsigned int priority) 	//GIC章节初始化
{
//1.GICD章节初始化
//设置GICD层组0使能, GICD control register (GICD_CTLR):  GICD_CTLR[0] = 1
	GICD->CTRL |= 1;
//设置GICD层中断使能,GICD interrupt set-enable register x (GICD_ISENABLERx)
	//key1 ----> PF9  ----> EXTI9 ----> 中断号99 ---->  99 / 32 = 3.......3 ----> GICD_ISENABLER3[3] = 1
   	//key2 ----> PF7  ----> EXTI7 ----> 中断号97 ---->  97 / 32 = 3.......1 ----> GICD_ISENABLER3[1] = 1
    //key3 ----> PF8  ----> EXTI8 ----> 中断号98 ---->  98 / 32 = 3.......2 ----> GICD_ISENABLER3[2] = 1
	GICD->ISENABLER[interruptid / 32] |= (0x1 << (interruptid % 32));
//设置GICD层中断优先级寄存器,GICD interrupt priority register x (GICD_IPRIORITYRx)
	//key1 ----> PF9  ----> EXTI9 ----> 中断号99 ---->  99 / 4 = 24.......3 ----> GICD_IPRIORITYR24[31:27] = 0b00000
    //key2 ----> PF7  ----> EXTI7 ----> 中断号97 ---->  97 / 4 = 24.......1 ----> GICD_IPRIORITYR24[15:11]  = 0b00000
   	//key3 ----> PF8  ----> EXTI8 ----> 中断号98 ---->  98 / 4 = 24.......2 ----> GICD_IPRIORITYR24[23:19]  = 0b0000
	GICD->IPRIORITYR[interruptid / 4] &= (~(0x1f << (interruptid % 4 * 8+3)));
	GICD->IPRIORITYR[interruptid / 4] |= (priority << (interruptid % 4 * 8+3));
//设置GICD层中断目标分配给CPU0,GICD interrupt processor target register x (GICD_ITARGETSRx)
	//key1 ----> PF9  ----> EXTI9 ----> 中断号99 ---->  99 / 4 = 24.......3 ----> GICD_ITARGETSR24[25:24] =  0b01 
    //key2 ----> PF7  ----> EXTI7 ----> 中断号97 ---->  97 / 4 = 24.......1 ----> GICD_ITARGETSR24[9:8]   =  0b01 
   	//key3 ----> PF8  ----> EXTI8 ----> 中断号98 ---->  98 / 4 = 24.......2 ----> GICD_ITARGETSR24[17:16]   =  0b01 
	GICD->ITARGETSR[interruptid / 4] &= (~(0x3 << (interruptid % 4 * 8)));
	GICD->ITARGETSR[interruptid / 4] |= (0x1 << (interruptid % 4 * 8));

//2.GICC章节初始化
	//设置GICC层组0使能,GICC input priority mask register (GICC_PMR),GICC_CTLR[0] = 1
	GICC->CTRL |= 1;
	//设置GICC层中断优先级寄存器,GICC control register (GICC_CTLR),GICC_PMR[7:3] = 0b11111
	GICC->PMR |= (0x1f << 3);
}

led.c

#include "led.h"

//函数功能:GPIO引脚初始化操作
//参数1:GPIO组号
//参数2:引脚编号
//参数3:初始化内容
void hal_gpio_init(volatile gpio_t* gpiox,unsigned int pin,gpio_init_t* init)
{
	//1. 设置GPIO引脚模式
	gpiox->MODER &= (~(0x3 << (pin*2)));
	gpiox->MODER |= (init->moder << (pin*2));
	//2. 设置GPIO引脚输出类型
	gpiox->OTYPER &= (~(0x1<<pin));
	gpiox->OTYPER |= (init->otyper << pin);
	//3. 设置GPIO引脚输出速率
	gpiox->OSPEEDR &= (~(0x3 << (pin*2)));
	gpiox->OSPEEDR |= (init->ospeedr << (pin*2));
	//4. 设置GPIO引脚是否需要上下拉电阻
	gpiox->PUPDR &= (~(0x3 << (pin*2)));
	gpiox->PUPDR |= (init->pupdr << (pin*2));
}

//函数功能:GPIO引脚操作,写1点亮,写0熄灭
//参数1:GPIO组号
//参数2:引脚编号
//参数3:写的内容
void hal_gpio_write(volatile gpio_t* gpiox,unsigned int pin,gpio_status_t status)
{
	if(status == GPIO_RESET_T)	//熄灭
	{
		gpiox->ODR &= (~(0x1<<pin));
	}
	else if(status == GPIO_SET_T) 	//点亮
	{
		gpiox->ODR |= (0x1<<pin);
	}
}

do_irq.c

extern void printf(const char *fmt, ...);
unsigned int i = 0;

#include "stm32mp1xx_gic.h"
#include "stm32mp1xx_exti.h"
#include "led.h"

//中断处理函数
void do_irq(void) 
{
	//1.获取中断号 IAR[9:0]
	unsigned int interrupt_id = GICC->IAR & (0x3ff);
	//2.判断终端号,并执行相关操作......
	switch(interrupt_id)
	{
		case 99:
			printf("key1键按下\n");
			GPIOE->ODR ^= (0x1 << 8);	//LED3, PE8
			//3.清除EXTI层中断挂起标志位
			EXTI->FPR1 |= (0x1 << 9);  //key1
			//4.清除GICD层中断挂起标志位
			GICD->ICPENDR[3] |= (0x1 << 3);  //ke1
			break;
		case 97:
			printf("key2键按下\n");
			GPIOF->ODR ^= (0x1 << 10);	//LED2, PF10
			//3.清除EXTI层中断挂起标志位
			EXTI->FPR1 |= (0x1 << 7);  //key2
			//4.清除GICD层中断挂起标志位
			GICD->ICPENDR[3] |= (0x1 << 1);  //key2
			break;	
		case 98:
			printf("key3键按下\n");
			GPIOE->ODR ^= (0x1 << 10);	//LED1, PE10
			//3.清除EXTI层中断挂起标志位
			EXTI->FPR1 |= (0x1 << 8);  //key3
			//4.清除GICD层中断挂起标志位
			GICD->ICPENDR[3] |= (0x1 << 2);  //key3
			break;
	}

	//5.清除中断号
	GICC->EOIR = interrupt_id;
	
}

main.c

#include "key3.h"
#include "led.h"
extern void printf(const char *fmt, ...);
void delay_ms(int ms)
{
	int i,j;
	for(i = 0; i < ms;i++)
		for (j = 0; j < 1800; j++);
}

#define GPIOF_GROUP 0x05
#define KEY1_ID 99
#define KEY2_ID 97
#define KEY3_ID 98

int main()
{
	RCC_MP_AHB4ENSETR |= (0x3<<4);	//使能GPIOE/GPIOF组
	gpio_init_t init = {OUTPUT,PP,LOWSPEED,NO_PUPDR};  //初始化GPIO结构体
 
	//初始化LED灯
	hal_gpio_init(GPIOE,GPIO_PIN_10,&init);	//LED1, PE10
	hal_gpio_init(GPIOF,GPIO_PIN_10,&init);	//LED2, PF10
	hal_gpio_init(GPIOE,GPIO_PIN_8,&init);	//LED3, PE8

	hal_exti_init(EXTI9,GPIOF_GROUP, FALLING_TRIGGER) ; //key1初始化
	hal_exti_init(EXTI7,GPIOF_GROUP, FALLING_TRIGGER) ; //key2初始化
	hal_exti_init(EXTI8,GPIOF_GROUP, FALLING_TRIGGER) ; //key3初始化
	hal_gic_init(KEY1_ID,9);
	hal_gic_init(KEY2_ID,7);
	hal_gic_init(KEY3_ID,8);

	while(1)
	{	

	}
	return 0;
}

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值