【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)的EXTI03: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)
  {
  }
}
相关推荐
恒锐丰科技林技术员2 小时前
EG2181D 半桥栅极驱动芯片详解:高压 MOS/IGBT 驱动实用器件
经验分享·嵌入式硬件·硬件工程
国科安芯3 小时前
面向卫星测控应答机的抗辐射MCU信号采集与定时控制研究
单片机·嵌入式硬件·mcu·架构·卫星·商业航天·抗辐射
CC城子3 小时前
EtherNet/IP I/O 丢包排查(linux系统)
linux·单片机·tcp/ip·ethernetip
新晨单片机设计3 小时前
S010A-基于STM32单片机水温控制系统(数码管显示)【Proteus仿真+Keil程序+原理图】
stm32·单片机·嵌入式硬件
事界见闻4 小时前
高性能电机控制MCU选型对比:精度、功耗与实时性如何兼得?
单片机·嵌入式硬件
Brilliantwxx4 小时前
【STM32】 初认识USART串口
linux·stm32·单片机·嵌入式硬件·架构
分享资料5 小时前
用小电容消除高频信号的原因
嵌入式硬件·硬件工程
沐欣工作室_lvyiyi5 小时前
基于STM32的人脸识别门禁系统的设计与实现(论文+源码)
stm32·单片机·嵌入式硬件
zcmodeltech9 小时前
智慧矿山沙盘模型多场景控制系统设计——基于STM32与Modbus RTU的智能开采、无人矿卡、数字孪生全场景联动方案
数据库·stm32·单片机·嵌入式硬件·物联网
qq_402995759 小时前
Secure Boot Part 3 —— 信任根和信任链
arm开发·stm32·信任链