STM32 - 使用EXTI处理外部中断

使用EXTI处理外部中断

1.任务描述

使用开发板上的KEY1按键,达到开/关LED彩灯的目的

2. 编程思路及要点

编程思路

检测GPIO中断,在中断服务函数里面,实现开/关LED彩灯

编程要点

1) 初始化用来产生中断的 GPIO;

2) 初始化 EXTI;

3) 配置 NVIC;

4) 编写中断服务函数;

3 示例代码

为了方便移植,首先定义GPIO引脚

//宏定义
#define KEY1_INT_GPIO_PORT 				GPIOA
#define KEY1_INT_GPIO_CLK 				(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO)
#define KEY1_INT_GPIO_PIN 				GPIO_Pin_0
#define KEY1_INT_EXTI_PORTSOURCE 	GPIO_PortSourceGPIOA
#define KEY1_INT_EXTI_PINSOURCE 	GPIO_PinSource0
#define KEY1_INT_EXTI_LINE 				EXTI_Line0
#define KEY1_INT_EXTI_IRQ 				EXTI0_IRQn

#define KEY1_IRQHandler 					EXTI0_IRQHandler


#define KEY2_INT_GPIO_PORT 				GPIOC
#define KEY2_INT_GPIO_CLK 				(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO)
#define KEY2_INT_GPIO_PIN 				GPIO_Pin_13
#define KEY2_INT_EXTI_PORTSOURCE 	GPIO_PortSourceGPIOC
#define KEY2_INT_EXTI_PINSOURCE 	GPIO_PinSource13
#define KEY2_INT_EXTI_LINE 				EXTI_Line13
#define KEY2_INT_EXTI_IRQ 				EXTI15_10_IRQn

#define KEY2_IRQHandler           EXTI15_10_IRQHandler

void EXTI_Key_Config(void);

配置NVIC

static void NVIC_Configuration(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;

	/* 配置 NVIC 为优先级组 1 */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

	/* 配置中断源:按键 1 */
	NVIC_InitStructure.NVIC_IRQChannel = KEY1_INT_EXTI_IRQ;
	/* 配置抢占优先级:1 */
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	/* 配置子优先级:1 */
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	/* 使能中断通道 */
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	/* 配置中断源:按键 2,其他使用上面相关配置 */
	NVIC_InitStructure.NVIC_IRQChannel = KEY2_INT_EXTI_IRQ;
	/* 配置子优先级:2 */
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
	
	NVIC_Init(&NVIC_InitStructure);
}

配置EXTI

void EXTI_Key_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	EXTI_InitTypeDef EXTI_InitStructure;

	/*开启按键 GPIO 口的时钟*/
	RCC_APB2PeriphClockCmd(KEY1_INT_GPIO_CLK,ENABLE);

	/* 配置 NVIC 中断*/
	NVIC_Configuration();

	/*--------------------------KEY1 配置---------------------*/
	/* 选择按键用到的 GPIO */
	GPIO_InitStructure.GPIO_Pin = KEY1_INT_GPIO_PIN;
	/* 配置为浮空输入 */
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);

	/* 选择 EXTI 的信号源 */
	GPIO_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE, \
		KEY1_INT_EXTI_PINSOURCE);
	EXTI_InitStructure.EXTI_Line = KEY1_INT_EXTI_LINE;

	/* EXTI 为中断模式 */
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	/* 上升沿中断 */
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
	/* 使能中断 */
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);

	/*开启按键 GPIO 口的时钟*/
	RCC_APB2PeriphClockCmd(KEY2_INT_GPIO_CLK,ENABLE);
	
	/*--------------------------KEY2 配置------------------*/
	/* 选择按键用到的 GPIO */
	GPIO_InitStructure.GPIO_Pin = KEY2_INT_GPIO_PIN;
	/* 配置为浮空输入 */
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(KEY2_INT_GPIO_PORT, &GPIO_InitStructure);

	/* 选择 EXTI 的信号源 */
	GPIO_EXTILineConfig(KEY2_INT_EXTI_PORTSOURCE, \
		KEY2_INT_EXTI_PINSOURCE);
	EXTI_InitStructure.EXTI_Line = KEY2_INT_EXTI_LINE;

	/* EXTI 为中断模式 */
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	/* 下降沿中断 */
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
	/* 使能中断 */
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);
}

EXTI 中断服务函数

void KEY1_IRQHandler(void)
{
	//确保是否产生了 EXTI Line 中断
	if (EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET) {
		// LED1 取反
		LED1_TOGGLE;
		//清除中断标志位
		EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);
	}
}

void KEY2_IRQHandler(void)
{
	//确保是否产生了 EXTI Line 中断
	if (EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET) {
		// LED2 取反
		LED2_TOGGLE;
		//清除中断标志位
		EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);
	}
}

 LED 相关的宏

// R-红色
#define LED1_GPIO_PORT GPIOB
#define LED1_GPIO_CLK RCC_APB2Periph_GPIOB
#define LED1_GPIO_PIN GPIO_Pin_5
// G-绿色
#define LED2_GPIO_PORT GPIOB
#define LED2_GPIO_CLK RCC_APB2Periph_GPIOB
#define LED2_GPIO_PIN GPIO_Pin_0
// B-蓝色
#define LED3_GPIO_PORT GPIOB
#define LED3_GPIO_CLK RCC_APB2Periph_GPIOB
#define LED3_GPIO_PIN GPIO_Pin_1


/* 直接操作寄存器的方法控制 IO */
#define digitalHi(p,i) {p->BSRR=i;} //输出为高电平
#define digitalLo(p,i) {p->BRR=i;} //输出低电平
#define digitalToggle(p,i) {p->ODR ^=i;} //输出反转状态


/* 定义控制 IO 的宏 */
#define LED1_TOGGLE digitalToggle(LED1_GPIO_PORT,LED1_GPIO_PIN)
#define LED1_OFF digitalHi(LED1_GPIO_PORT,LED1_GPIO_PIN)
#define LED1_ON digitalLo(LED1_GPIO_PORT,LED1_GPIO_PIN)

#define LED2_TOGGLE digitalToggle(LED2_GPIO_PORT,LED2_GPIO_PIN)
#define LED2_OFF digitalHi(LED2_GPIO_PORT,LED2_GPIO_PIN)
#define LED2_ON digitalLo(LED2_GPIO_PORT,LED2_GPIO_PIN)

#define LED3_TOGGLE digitalToggle(LED2_GPIO_PORT,LED3_GPIO_PIN)
#define LED3_OFF digitalHi(LED2_GPIO_PORT,LED3_GPIO_PIN)
#define LED3_ON digitalLo(LED2_GPIO_PORT,LED3_GPIO_PIN)

/* 基本混色,后面高级用法使用 PWM 可混出全彩颜色,且效果更好 */

//红
#define LED_RED \
	LED1_ON;\
	LED2_OFF\
	LED3_OFF

//绿
#define LED_GREEN \
	LED1_OFF;\
	LED2_ON\
	LED3_OFF

//蓝
#define LED_BLUE \
	LED1_OFF;\
	LED2_OFF\
	LED3_ON


//黄(红+绿)
#define LED_YELLOW \
	LED1_ON;\
	LED2_ON\
	LED3_OFF
//紫(红+蓝)
#define LED_PURPLE \
	LED1_ON;\
	LED2_OFF\
	LED3_ON

//青(绿+蓝)
#define LED_CYAN \
	LED1_OFF;\
	LED2_ON\
	LED3_ON

//白(红+绿+蓝)
#define LED_WHITE \
	LED1_ON;\
	LED2_ON\
	LED3_ON

//黑(全部关闭)
#define LED_RGBOFF \
	LED1_OFF;\
	LED2_OFF\
	LED3_OFF

#define LED_GPIO_PORT 	GPIOB
#define LED_GPIO_CLK 	  RCC_APB2Periph_GPIOB

#define LED_G_GPIO_PIN 	  GPIO_Pin_0
#define LED_B_GPIO_PIN 	  GPIO_Pin_1
#define LED_R_GPIO_PIN 	  GPIO_Pin_5

#define ON         1
#define OFF        0

//通过异或运算来亮灭LED
#define LED_TOGGLE(pin) (LED_GPIO_PORT->ODR ^= pin)

typedef enum
{
	LED_Type_G = 0,
	LED_Type_R,
	LED_Type_B
}LED_Type_E;

void GPIO_LED_Config(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void LED_Switch(LED_Type_E ledType, uint8_t opt);

void LED_GPIO_Config(void);

主函数

int main(void)
{
#if 0
	HSE_SetSysClk(RCC_PLLMul_9);
	
	// 流水灯
	while(1)
	{
		GPIO_LED_Config(LED_GPIO_PORT, LED_G_GPIO_PIN);
	
		Delay(0xfffff);
		LED_Switch(LED_Type_G, ON);
		Delay(0xfffff);
		LED_Switch(LED_Type_G, OFF);
		Delay(0xfffff);
		
		GPIO_LED_Config(GPIOB, LED_R_GPIO_PIN);
	
		Delay(0xfffff);
		LED_Switch(LED_Type_R, ON);
		Delay(0xfffff);
		LED_Switch(LED_Type_R, OFF);
		Delay(0xfffff);
		
		GPIO_LED_Config(GPIOB, LED_B_GPIO_PIN);
	
		Delay(0xfffff);
		LED_Switch(LED_Type_B, ON);
		Delay(0xfffff);
		LED_Switch(LED_Type_B, OFF);
		Delay(0xfffff);
	}
#elif 0
	//通过按键来亮灭LED
	GPIO_LED_Config(LED_GPIO_PORT, LED_R_GPIO_PIN);
	GPIO_KEY_Config(KEY1_GPIO_PORT, KEY1_GPIO_CLK, KEY1_GPIO_PIN);
	
	while(1)
	{
		if( KEY_ON == key_scan(KEY1_GPIO_PORT, KEY1_GPIO_PIN) )
			LED_TOGGLE(LED_R_GPIO_PIN);
	}

//	GPIO_LED_Config(LED_GPIO_PORT, LED_B_GPIO_PIN);
//	GPIO_KEY_Config(KEY2_GPIO_PORT, KEY2_GPIO_CLK, KEY2_GPIO_PIN);
//	
//	while(1)
//	{
//		if( KEY_ON == key_scan(KEY2_GPIO_PORT, KEY2_GPIO_PIN) )
//			LED_TOGGLE(LED_B_GPIO_PIN);
//	}
#else
	/* LED 端口初始化 */
	LED_GPIO_Config();

	/* 初始化 EXTI 中断,按下按键会触发中断,
	* 触发中断会进入 stm32f4xx_it.c 文件中的函数
	* KEY1_IRQHandler 和 KEY2_IRQHandler,处理中断,反转 LED 灯。
	*/
	EXTI_Key_Config();

	/* 等待中断,由于使用中断方式,CPU 不用轮询按键 */
	while (1) {
	}

#endif
}

LED 配置

void LED_GPIO_Config(void)
{
	/*定义一个 GPIO_InitTypeDef 类型的结构体*/
	GPIO_InitTypeDef GPIO_InitStructure;

	/*开启 LED 相关的 GPIO 外设时钟*/
	RCC_APB2PeriphClockCmd( LED1_GPIO_CLK|
		LED2_GPIO_CLK|
		LED3_GPIO_CLK, ENABLE);
	/*选择要控制的 GPIO 引脚*/
	GPIO_InitStructure.GPIO_Pin = LED1_GPIO_PIN;

	/*设置引脚模式为通用推挽输出*/
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

	/*设置引脚速率为 50MHz */
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

	/*调用库函数,初始化 GPIO*/
	GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure);

	/*选择要控制的 GPIO 引脚*/
	GPIO_InitStructure.GPIO_Pin = LED2_GPIO_PIN;

	/*调用库函数,初始化 GPIO*/
	GPIO_Init(LED2_GPIO_PORT, &GPIO_InitStructure);

	/*选择要控制的 GPIO 引脚*/
	GPIO_InitStructure.GPIO_Pin = LED3_GPIO_PIN;

	/*调用库函数,初始化 GPIOF*/
	GPIO_Init(LED3_GPIO_PORT, &GPIO_InitStructure);

	/* 关闭所有 led 灯 */
	GPIO_SetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);

	/* 关闭所有 led 灯 */
	GPIO_SetBits(LED2_GPIO_PORT, LED2_GPIO_PIN);

	/* 关闭所有 led 灯 */
	GPIO_SetBits(LED3_GPIO_PORT, LED3_GPIO_PIN);
}

猜你喜欢

转载自blog.csdn.net/hzhshu_csdn/article/details/113029109