【STM32】外部中断

1.EXTI简介

外部中断/事件控制器(EXTI)管理了控制器的23个中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。 EXTI可以实现对每个中断/事件线进行单独配置,可以单独配置为中断或者事件,以及触发事件的属性。

产生中断线路目的是把输入信号输入到NVIC,进一步会运行中断服务函数,实现功能,这样是软件级的。 而产生事件线路目的就是传输一个脉冲信号给其他外设使用,并且是电路级别的信号传输,属于硬件级的。

另外,EXTI是在APB2总线上的,在编程时候需要注意到这点。

2.中断/事件线

EXTI有23个中断/事件线,每个GPIO都可以被设置为输入线,占用EXTI0至EXTI15,还有另外七根用于特定的外设事件,见表 EXTI中断/事件线

七根特定外设中断/事件线由外设触发,具体用法参考《STM32F4xx中文参考手册》中对外设的具体说明。

EXTI中断/事件线

中断/事件线 输入源
EXTI0 PX0(X可为A,B,C,D,E,F,G,H,I)
EXTI1 PX1(X可为A,B,C,D,E,F,G,H,I)
EXTI2 PX2(X可为A,B,C,D,E,F,G,H,I)
EXTI3 PX3(X可为A,B,C,D,E,F,G,H,I)
EXTI4 PX4(X可为A,B,C,D,E,F,G,H,I)
EXTI5 PX5(X可为A,B,C,D,E,F,G,H,I)
EXTI6 PX6(X可为A,B,C,D,E,F,G,H,I)
EXTI7 PX7(X可为A,B,C,D,E,F,G,H,I)
EXTI8 PX8(X可为A,B,C,D,E,F,G,H,I)
EXTI9 PX9(X可为A,B,C,D,E,F,G,H,I)
EXTI10 PX10(X可为A,B,C,D,E,F,G,H,I)
EXTI11 PX11(X可为A,B,C,D,E,F,G,H,I)
EXTI12 PX12(X可为A,B,C,D,E,F,G,H,I)
EXTI13 PX13(X可为A,B,C,D,E,F,G,H,I)
EXTI14 PX14(X可为A,B,C,D,E,F,G,H,I)
EXTI15 PX15(X可为A,B,C,D,E,F,G,H)
EXTI16 可编程电压检测器(PVD)输出
EXTI17 RTC闹钟事件
EXTI18 USB OTG FS唤醒事件
EXTI19 以太网唤醒事件
EXTI20 USB OTG HS(在FS中配置)唤醒事件
EXTI21 RTC入侵和时间戳事件
EXTI22 RTC唤醒事件

EXTI0至EXTI15用于GPIO,通过编程控制可以实现任意一个GPIO作为EXTI的输入源。由上表可知, EXTI0可以通过SYSCFG外部中断配置寄存器1(SYSCFG_EXTICR1)的EXTI0[3:0]位选择配置为PA0、PB0、PC0、PD0、PE0、PF0、PG0、PH0或者PI0, 见图 EXTI0输入源选择 。其他EXTI线(EXTI中断/事件线)使用配置都是类似的。

3.外部中断标准库函数

c 复制代码
typedef struct {
    uint32_t EXTI_Line;                 // 中断/事件线
    EXTIMode_TypeDef EXTI_Mode;         // EXTI模式
    EXTITrigger_TypeDef EXTI_Trigger;   // 触发事件
    FunctionalState EXTI_LineCmd;       // EXTI控制
} EXTI_InitTypeDef;
  1. EXTI_Line:EXTI中断/事件线选择, 可选EXTI0至EXTI22,可参考表 18‑1选择。

  2. EXTI_Mode:EXTI模式选择, 可选为产生中断(EXTI_Mode_Interrupt)或者产生事件(EXTI_Mode_Event)。

  3. EXTI_Trigger:EXTI边沿触发事件, 可选上升沿触发(EXTI_Trigger_Rising)、下降沿触发( EXTI_Trigger_Falling)或者上升沿和下降沿都触发( EXTI_Trigger_Rising_Falling)。

  4. EXTI_LineCmd:控制是否使能EXTI线, 可选使能EXTI线(ENABLE)或禁用(DISABLE)。

外部中断的一般配置步骤:

  1. 使能SYSCFG时钟,在APB2总线上。
  2. 初始化GPIO口为输入。
  3. 设置IO口与中断线的映射关系。
  4. 初始化线上中断,设置触发条件等。
  5. 配置中断分组(NVIC),并使能中断。
  6. 编写中断服务函数,清除中断标志位。

4.软件实现

我们的电路板没有按键,所以使用一个GPIO接地模拟触发下拉中断,来控制LED翻转。当然手动飞线接地会有毛刺,下文代码没有考虑这些方面的处理。

c 复制代码
#ifndef __BSP_EXTI_H
#define __BSP_EXTI_H

#ifdef __cplusplus
extern "C"{

#endif

#include "stm32f4xx.h"

#define MY_EXTI_LINE            EXTI_Line3
#define MY_EXIT_IRQ             EXTI3_IRQn
#define MY_EXIT_IRQHandler      EXTI3_IRQHandler

//PG3引脚为外部下拉中断的接口
#define MY_EXTI_PIN             GPIO_Pin_3
#define MY_EXTI_GPIO_Port       GPIOG
#define MY_EXTI_GPIO_CLK        RCC_AHB1Periph_GPIOG
#define MY_EXTI_PIN_SOURCE      EXTI_PortSourceGPIOG
#define MY_EXTI_Port_SOURCE     EXTI_PinSource3


void Init_EXTI(void);
	
#ifdef __cplusplus
}
#endif

#endif
c 复制代码
#include "bsp_exti.h"
#include "bsp_led.h"
#include "stdio.h"

void Init_EXTI(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);//使能外部中断时钟
	RCC_APB2PeriphClockCmd(MY_EXTI_GPIO_CLK,ENABLE);//使能GPIO时钟
	
	//初始化GPIO
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Pin=MY_EXTI_PIN;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN;
	//GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
	GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;
	GPIO_InitStruct.GPIO_Speed=GPIO_Fast_Speed;
	GPIO_Init(MY_EXTI_GPIO_Port,&GPIO_InitStruct);
	
	//设置IO口与中断线的映射关系
	SYSCFG_EXTILineConfig(MY_EXTI_PIN_SOURCE,MY_EXTI_Port_SOURCE);
	
	//初始化线上中断,并设置触发条件
	EXTI_InitTypeDef EXIT_InitStruct;
	EXIT_InitStruct.EXTI_Line=MY_EXTI_LINE;
	EXIT_InitStruct.EXTI_LineCmd=ENABLE;
	EXIT_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;
	EXIT_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;
	EXTI_Init(&EXIT_InitStruct);
	
	//配置中断控制器并使能中断
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel=MY_EXIT_IRQ;
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;
	NVIC_Init(&NVIC_InitStruct);
}

void MY_EXIT_IRQHandler(void)
{
	//这里的ITStatus可以不需要判断,因为该中断函数就一个Line3。
	//但是其他的中断线会共用一个中断服务函数,所以就需要判断是哪一个中断线
	if(SET==EXTI_GetITStatus(MY_EXTI_LINE))
	{
		LED_TOGGLE();
		EXTI_ClearITPendingBit(MY_EXTI_LINE);
		printf("MY_EXIT_IRQHandler\r\n");
	}
}
c 复制代码
int main(void)
{
	//设置中断分组
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	
	Init_USART();
	
	Init_LED();
	
	Init_EXTI();
	
  /* Infinite loop */
  while (1)
  {
  }
}
相关推荐
Hungry_1110 分钟前
SPI通信协议
单片机·嵌入式硬件·spi·嵌入式软件
长安——归故李29 分钟前
51单片机彩灯控制与数码管结合
汇编·单片机·嵌入式硬件·青少年编程·c#·51单片机·硬件工程
天天爱吃肉82181 小时前
Zcanpro搭配USBCANFD-200U在新能源汽车研发测试中的应用指南(周立功/致远电子)
单片机·嵌入式硬件·汽车·学习方法
Czzzzlq1 小时前
STM32基础教程——输入捕获模式测量PWM频率
stm32·单片机·嵌入式硬件
三歪爱三玖2 小时前
【蓝桥杯】单片机设计与开发,RTC实时时钟
单片机·蓝桥杯·实时音视频
ZaaaaacK4 小时前
STM32技能综合巩固
stm32·单片机·嵌入式硬件
年轮不改4 小时前
STM32智能手表——任务线程部分
stm32·智能手表
yuanbenshidiaos5 小时前
stm32面试
stm32·嵌入式硬件·面试
charlie1145141915 小时前
STM32F103C8T6单片机的起始点:使用GPIO输出点亮我们的第一个小灯(标准库篇)
stm32·单片机·嵌入式硬件
DOMINICHZL6 小时前
国产MCU替代STM32全解析:主流方案对比与实战指南
stm32·单片机·嵌入式硬件·gd32