STM32F103 外部中断(EXTI)介绍以及代码
STM32 外部中断/事件控制器由19个产生事件/中断要求的边沿检测器组成。每个输入线可以独立地配置输入类型(脉冲或挂起)和对应的触发事件(上升沿或下降沿或者双边沿都触发)。每个输入线都可以被独立的屏蔽。挂起寄存器保持着状态线的中断要求。

对以上序号进行说明:
①InputLine:外部信号输入线,总共有 19 个来源,分别是 GPIO0~15(总共 16 个),正好连接到 EXTI0~15,EXTI16 连接到 PVD 输出,EXTI17 连接到 RTC 闹钟事件,EXTI18 连接到 USB,所以 /19 代表 19 个通道
②Edge Detect :边缘检测,可以是上升沿触发,也可以是下降沿触发,还可以是上升沿和下降沿都可以分别触发,对应图中 ②-1 和 ②-2
③Software interrupt event register:软件中断事件寄存器
④Pending request register:挂起寄存器
⑤interrupt mask register:中断屏蔽寄存器
整个外部中断的流程是这样的
1、选择外部信号输入线
2、信号选择以什么方式来触发,可以是上升沿或下降沿等
3、信号经过或门到 Pending request register,如果发生了触发,该寄存器的 PRx 位将置 1
4、最后,整个信号和中断屏蔽寄存器经过与门到 NVIC,这要求中断屏蔽寄存器必须置 1
如果用 GPIO 作为外部中断,需要配置 AFIO,来选择是哪个端口,可以是 GPIOA/GPIOB/GPIOC/GPIOD/GPIOE/GPIOF/GPIOG,需要注意的是,对于同一个 Pin 脚,只能选择配置一个端口,例如我配置 Pin15 为 GPIOC,那么就不能再用用 GPIOA/B/D/E/F/G 15 作为 EXTI ,如下图所示

代码设计思路:
1、初始化 GPIOC15 为下拉输入模式
2、初始化 EXTI,为上升沿触发
3、配置 NVIC
4、编写中断服务函数
5、每进一次中断,OLED 显示屏上计数就会+1
#include "stm32f10x.h" // Device header
/* EXTI 通过 AFIO_EXTICR1 的 EXTI0[3:0] 位选择配置为 PA0/PB0/PC0...
* 选择用 C15 作为 EXTI 的接口,整个流程如下
* ①初始化 GPIOC15,配置下拉输入(因为我要配置上升沿触发),配置 AFIO
* ②初始化 EXTI
* ③配置 NVIC
* ④编写中断服务函数
* ⑤用 OLED 显示屏记录进入中断的次数
*/
//将 GPIO 初始化为浮空输入模式
void EXTI_GPIOInit(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//开启 AFIO 时钟配置进入中断的 GPIO 端口
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource15);//配置 AFIO 来选择需要的 GPIO
}
//外部中断初始化
void EXTI15_Init(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line15;//因为是 GPIOC15,所以选择为外部通道 15
EXTI_InitStructure.EXTI_LineCmd = ENABLE;//打开中断使能
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//选择是中断事件还是中断
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;//选择触发中断的方式,有上升压、下降沿还有上升和下降沿
EXTI_Init(&EXTI_InitStructure);
}
void NVIC15_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;//选择中断向量表中的中断
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_Init(&NVIC_InitStructure);
}
void All_Init(void)
{
EXTI_GPIOInit();
EXTI15_Init();
NVIC15_Init();
}
#include "stm32f10x.h" // Device header
#include "OLED7.h"
#include "OLED.h"
#include "Delay.h"
#include "EXTI.h"
uint8_t flag = 0;
int main(void)
{
uint8_t num = 0;
OLED7_Init();
All_Init();
OLED7_ShowString(1, 1, "Hello");
for (; ;)
{
if(flag)
{
flag = 0;
OLED7_ShowNum(1, 8, num, 3);
num++;
Delay_ms(500);
}
}
return 0;
}
void EXTI15_10_IRQHandler(void)
{
if (EXTI_GetITStatus(EXTI_Line15))
{
flag = 1;
EXTI_ClearITPendingBit(EXTI_Line15);
}
}