这里写目录标题
- 前言
- 1、EXTI概述
- 2、外部中断配置流程
- 完整代码
前言
注释很详细,放心食用。
1、EXTI概述
- STM32F4的每个IO都可以作为外部中断的中断输入口,这点也是STM32F4的强大之处。
- STM32F407的中断控制器支持22个外部中断/事件请求。每个中断线上都设有状态位,每个中断/事件都有独立的触发(上升沿、下降沿、上升下降沿)和屏蔽设置。
- EXTI线0~15:对应外部IO口的输入中断。
- EXTI线16:连接到PVD输出。
- EXTI线17:连接到RTC闹钟事件。
- EXTI线18:连接到USB OTG FS唤醒事件。
- EXTI线19:连接到以太网唤醒事件。
- EXTI线20:连接到USB OTG HS(在FS中配置)唤醒事件。
- EXTI线21:连接到RTC入侵和时间戳事件。
- EXTI线22:连接到RTC唤醒事件。
通过上面的内容我们可以看出,可以给单片机对应外部IO口使用的中断线仅有(EXTI线0~15)16条,而F407系列单片机的IO口远远不止16个。
所以RAM厂商做了一个巧妙地设计,GPIO的管脚GPIOx.0-GPIOx.15(x=A,B,C,D,E,F,G,H,I)分别对应中断线0~15。这样每个中断线对应了最多9个IO口,以线0为例:它对应了GPIOA.0、GPIOB.0、GPIOC.0、GPIOD.0。如下图所示:
上面提到了,对于这16根中断线,每个中断线上都设有状态位,每个中断/事件都有独立的触发(上升沿、下降沿、上升下降沿)和屏蔽设置。
STM32的IO口外部中断在中断向量表里只分配了7个中断向量,所以我们只能使用下面这七个中断服务函数。
EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt /
EXTI1_IRQn = 7, /!< EXTI Line1 Interrupt /
EXTI2_IRQn = 8, /!< EXTI Line2 Interrupt /
EXTI3_IRQn = 9, /!< EXTI Line3 Interrupt /
EXTI4_IRQn = 10, /!< EXTI Line4 Interrupt /
EXTI9_5_IRQn = 23, /!< External Line[9:5] Interrupts /
EXTI15_10_IRQn = 40, /!< External Line[15:10] Interrupts */
从表中可以看出,中断线0-4每个中断线对应一个中断函数,中断线5-9共用中断函数EXTI9_5_IRQHandler,中断线10-15共用中断函数EXTI15_10_IRQHandler。
2、外部中断配置流程
注:我这里是以PE2的外部按键输入的中断处理举例。
-
1、使能GPIOE端口时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE); -
2、使能SYSCFG时钟:其用于配置外部中断
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE); -
3、初始化GPIO-PE2为输入模式
GPIO_InitTypeDef GPIO_Initstructure;
GPIO_Initstructure.GPIO_Mode=GPIO_Mode_IN;
GPIO_Initstructure.GPIO_OType = GPIO_OType_OD;
GPIO_Initstructure.GPIO_Pin=GPIO_Pin_15;
GPIO_Initstructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Initstructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_Initstructure); -
4、将GPIOE的引脚PE15与外部中断线2连接
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource2); -
5、配置EXTI
EXTI_InitTypeDef EXTI_Initstructure;
EXTI_Initstructure.EXTI_Line=EXTI_Line2; /设置外部中断线为第2条/
EXTI_Initstructure.EXTI_LineCmd=ENABLE; /使能外部中断线/
EXTI_Initstructure.EXTI_Mode=EXTI_Mode_Interrupt; /配置为响应中断。另一种是事件/
EXTI_Initstructure.EXTI_Trigger=EXTI_Trigger_Falling; /下降沿触发中断/
EXTI_Init(&EXTI_Initstructure); -
6、配置NVIC(中断初始化向量参数:配置指定中断线的中断优先级)
NVIC_InitTypeDef NVIC_Initstructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//进行中断优先级分组
NVIC_Initstructure.NVIC_IRQChannel=EXTI2_IRQn;
NVIC_Initstructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Initstructure.NVIC_IRQChannelPreemptionPriority=2; /抢占优先级/
NVIC_Initstructure.NVIC_IRQChannelSubPriority=2; /响应优先级/
NVIC_Init(&NVIC_Initstructure); -
7、编写中断服务函数
void EXTI2_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line2)) /检查外部中断线 2 的中断标志位是否置位/
{
printf(“int!!!\r\n”); /测试程序,可根据自己的硬件情况设置,如点亮一个小灯等/
EXTI_ClearITPendingBit(EXTI_Line2); /清除外部中断线 2 的中断标志位/
}
}
完整代码
key_exti.c
#include "key_exti.h"
/*按键中断*/
void Key_INT_config_E2(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE); /*使能SYSCFG时钟:其用于配置外部中断*/
//EXTI(外部中断)和NVIC(中断优先级控制)不需要配置时钟
//中断信号--》AFIO--》EXTI--》NVIC--》CPU
/*
* 第一步,配置GPIO为输入模式
*/
GPIO_InitTypeDef GPIO_Initstructure;
GPIO_Initstructure.GPIO_Mode=GPIO_Mode_IN;
GPIO_Initstructure.GPIO_OType = GPIO_OType_OD;/*在输入模式下,这句没什么意义*/
GPIO_Initstructure.GPIO_Pin=GPIO_Pin_15;
GPIO_Initstructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Initstructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_Initstructure);
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource2);/*将GPIOE的引脚PE15与外部中断线2连接*/
/*
* 第二步,配置EXTI
*/
EXTI_InitTypeDef EXTI_Initstructure;
EXTI_Initstructure.EXTI_Line=EXTI_Line2; /*设置外部中断线为第2条*/
EXTI_Initstructure.EXTI_LineCmd=ENABLE; /*使能外部中断线*/
EXTI_Initstructure.EXTI_Mode=EXTI_Mode_Interrupt; /*配置为响应中断。另一种是事件*/
EXTI_Initstructure.EXTI_Trigger=EXTI_Trigger_Falling; /*下降沿触发中断*/
EXTI_Init(&EXTI_Initstructure);
/*
*第三步,配置NVIC(中断初始化向量参数:配置指定中断线的中断优先级)
*/
NVIC_InitTypeDef NVIC_Initstructure;
NVIC_Initstructure.NVIC_IRQChannel=EXTI2_IRQn;
NVIC_Initstructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Initstructure.NVIC_IRQChannelPreemptionPriority=2; /*抢占优先级*/
NVIC_Initstructure.NVIC_IRQChannelSubPriority=2; /*响应优先级*/
NVIC_Init(&NVIC_Initstructure);
}
void EXTI2_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line2)) /*检查外部中断线 2 的中断标志位是否置位*/
{
printf("int!!!\r\n");
EXTI_ClearITPendingBit(EXTI_Line2); /*清除外部中断线 2 的中断标志位*/
}
}
key_exti.h
#ifndef __KEY_EXTI_H__
#define __KEY_EXTI_H__
#include "stm32f4xx.h" // Device header
#include <stdbool.h>
#include <stdlib.h>
void Key_INT_config_E2(void);
#endif