STM32F4_外部中断详解(EXTI)

EXTI是STM32中的外部中断/事件控制器,用于管理GPIO的中断和事件。每个中断线可独立配置触发类型和屏蔽,并有相应的寄存器进行控制。配置外部中断包括使能IO口时钟、映射中断线、初始化中断线、设置中断优先级和编写中断服务函数。STM32F4支持22个外部中断,每个中断线可以控制多个IO口。文章提供了配置示例代码和中断服务函数的编写方法。
摘要由CSDN通过智能技术生成

目录

1. EXTI 是什么?

2. EXTI主要特性

3. EXTI框图

3.1 外部中断/事件线映射

4. EXTI寄存器

4.1 中断屏蔽寄存器 EXTI_IMR

4.2 事件屏蔽寄存器 EXTI_EMR

4.3 上升沿触发选择寄存器 EXTI_RTSR

4.4 下降沿触发选择寄存器 EXTI_FTSR

4.5 软件中断事件寄存器 EXTI_SWIER

4.6 挂起寄存器 EXTI_PR

5. 库函数配置外部中断的步骤

6. STM32外部中断程序

6.1 main.c

6.2 exti.c

6.3 exti.h


1. EXTI 是什么?

        EXTI:外部中断/事件控制器包含多达23个用于产生事件/中断请求边沿检测器。每根输入线都可以单独进行配置,以选择类型 (中断或事件) 和相应的触发事件(上升沿触发、下降沿触发或边沿触发)。每根输入线还可以单独屏蔽。挂起寄存器用于保持中断请求的状态线。是用来专门的管理所有的GPIO用来处理中断和事件的。

        中断的意思就是程序在执行过程中,中断就如同一个小插曲,中断或者事件一来,优先执行中断事件,完成中断以后,再执行未完成的程序。(举个简单的例子就是:打比方我们正在家里学习,学习的同时可能你在开水,这个时候,突然门铃响了,门铃响就是一个中断,这个时候就打断了你正在执行的事(学习),你需要先去开门,看一下是否有重要的事;倘若没有很重要的事(处理完中断事件了),你回到座位上重新开始学习;这个时候突然水壶响了,同样水壶响了也是一个中断,需要再一次打断你正在学习的状态,去关一下水壶(再次去处理中断事件);

2. EXTI主要特性

1. 每个中断/事件线上都具有独立的触发和屏蔽。

2. 每个中断线都具有专用的状态位。

3. 支持多达23个软件事件/中断请求。

4. 检测脉冲宽度低于APB2时钟宽度的外部信号。

3. EXTI框图

要产生中断,必须先配置好并使能中断线。根据需要的边沿检测设置2个触发寄存器,同时在中断屏蔽寄存器的相应位写 1 使能中断请求。当外部中断线上出现选定信号沿时,便会产生中断请求,对应的挂起位会置1。在挂起寄存器的对应位写 1 ,将清除该中断请求。

要产生事件,必须先配置好并使能事件线。根据需要的边沿检测设置2个触发寄存器,同时在事件屏蔽寄存器的相应位写 1 允许事件请求。当事件线上出现选定信号沿时,便会产生事件脉冲,对应的挂起位不会置 1。

通过在软件中对软件中断/事件寄存器写 1 ,也可以产生中断/事件请求。

3.1 外部中断/事件线映射

注意:一个中断线可以控制8个IO口的输入

        void EXTI0_IRQHandler(void)是外部中断0的服务函数,负责WK_UP按键的中断检测;    因为原理图上KEY_UP接引脚PA0

        void EXTI2_IRQHandler(void)是外部中断2的服务函数,负责KEY2按键的中断检测;        因为原理图上KEY2接引脚PE2

        void EXTI3_IRQHandler(void)是外部中断3的服务函数,负责KEY1按键的中断检测;        因为原理图上KEY1接引脚PE3

        void EXTI4_IRQHandler(void)是外部中断4的服务函数,负责KEY0按键的中断检测;        因为原理图上KEY0接引脚PE4

        在对上述的理解上需要基于上述图,外部EXTI0是控制PA0/PB0/PC0/PD0/PE0/PF0……  ;简单理解就是EXTI1控制PA1/PB1/PC1/PD1/PE1/PF1…… ; 因此,KEY_UP负责外部中断0的中断服务函数的检测,KEY2负责外部中断2的服务函数的中断检测,KEY1负责外部中断3的服务函数的中断检测,KEY0负责外部中断4的服务函数的中断检测;

4. EXTI寄存器

4.1 中断屏蔽寄存器 EXTI_IMR

中断屏蔽寄存器:EXTI_IMR(Interrupt mask register) 32位寄存器

位31:23  保留,必须保持复位值

位22:0  MRx :x线上的中断屏蔽

                        0:屏蔽来自于x线上的中断请求

                        1:开放来自于x线上的中断请求

4.2 事件屏蔽寄存器 EXTI_EMR

事件屏蔽寄存器 EXTI_EMR(Event mask register) 32位寄存器

位31:23  保留,必须保持复位值

位22:0   MRx:x线上的事件屏蔽

                        0:屏蔽来自x线的事件请求

                        1:开放来自x线的事件请求

4.3 上升沿触发选择寄存器 EXTI_RTSR

上升沿触发选择寄存器 EXIT_RTSR(Rising trigger selection register) 32位寄存器

位31:23 保留,必须保持复位值

位22:0 TRx:线x的上升沿触发事件配置位

                        0:禁止输入线上升沿触发

                        1:允许输入线上升沿触发

4.4 下降沿触发选择寄存器 EXTI_FTSR

下降沿触发选择寄存器 EXIT_RTSR(Falling trigger selection register) 32位寄存器

位31:23 保留,必须保持复位值

位22:0 TRx:线x的下降沿触发事件配置位

                        0:禁止输入线下降沿触发

                        1:允许输入线下降沿触发

4.5 软件中断事件寄存器 EXTI_SWIER

软件中断事件寄存器 EXTI_SWIER(Software interrupt event register)

位 31:23 保留,必须保持复位值。

位 22:0 SWIERx:线 x 上的软件中断 (Software Interrupt on line x)

当该位为“0”时,写“1”将设置 EXTI_PR 中相应的挂起位。如果在 EXTI_IMR 和 EXTI_EMR 中允许产生该中断,则产生中断请求。

通过清除 EXTI_PR 的对应位(写入“1”),可以清除该位为“0”。 

4.6 挂起寄存器 EXTI_PR

挂起寄存器 EXTI_PR(Pending register)

位 31:23 保留,必须保持复位值。

位 22:0 PRx:挂起位 (Pending bit)

                0:没有发生触发请求

                1:发生了选择的触发请求  当在外部中断线上发生了选择的边沿事件,该位被置“1”。

在此位中写入“1”可以清除它,也可以通过改变边沿检测的极性清除。

5. 库函数配置外部中断的步骤

STM32F4的每个IO口都可以作为外部中断的中断输入口,这点也是STM32F4的强大之处(相比于51只有5个中断,2个外部中断、2个定时器中断、1个串口中断)STM32F4的中断控制器支持22个外部中断/事件请求。每个中断都有状态位,每个中断/事件都有独立的触发和屏蔽设置。

STM32F4的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唤醒事件。

库函数配置外部中断的步骤:

1. 使能IO口时钟,初始化IO口为输入

2. 开启SYSCFG时钟,设置IO口与中断线的映射关系;

注意:只要使用到外部中断,必须使能SYSCFG时钟。

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);  //使能SYSCFG时钟 

        配置GPIO与中断线的映射关系函数:

        void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex); 

        ag.    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0); 将中断线0 与GPIOA映射起来,那么GPIOA.0与EXTI 1中断线连接了。

3. 初始化线上中断,设置触发条件

初始化是通过EXTI_Init();来实现的;中断线4上的下降沿触发配置如下:

        EXTI_InitTypeDef EXTI_InitStructure;//设置EXTI结构体结构体变量

        EXTI_InitStructure.EXTI_Line=EXTI_Line4; //中断线标号,配置某个中断线上的中断函数,取值范围:EXTI_Line0~EXTI_Line15

        EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; //中断模式,选值:中断EXTI_Mode_Interrupt和事件EXTI_Mode_Event

        EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;//触发方式,可以是下降沿触发EXTI_Trigger_Falling,上升沿触发                EXTI_Trigger_Rising,或者任意电平(上升沿和下降沿)触发EXTI_Trigger_Rising_Falling

        EXTI_InitStructure.EXTI_LineCmd=ENABLE; //中断使能

        EXTI_Init(&EXTI_InitStructure);  //初始化外设EXTI寄存器

4. 配置好中断分组NVIC,并且使能中断

设置中断线2的中断优先级如下:

        NVIC_InitTypeDef NVIC_InitStructure; //设置NVIC结构体变量

        NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //使能按键外部中断通道

        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2

        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //响应优先级2

        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道

        NVIC_Init(&NVIC_InitStructure); //中断优先级分组初始化

5. 编写中断服务函数

STM32F4的IO口外部中断函数只有7个:

        EXPORT EXTI0_IRQHandler   // 中断线0-4每个中断线对应一个中断函数

        EXPORT EXTI1_IRQHandler

        EXPORT EXTI2_IRQHandler

        EXPORT EXTI3_IRQHandler  

        EXPORT EXTI4_IRQHandler  

        EXPORT EXTI9_5_IRQHandler // 中断线5-9共用中断函数EXPORT EXTI9_5_IRQHandler

        EXPORT EXTI15_10_IRQHandler // 中断线10-15共用EXPORT EXTI15_10_IRQHandler

注意:一个中断线可以控制8个IO口的输入

        void EXTI0_IRQHandler(void)是外部中断0的服务函数,负责WK_UP按键的中断检测;    因为原理图上KEY_UP接引脚PA0

        void EXTI2_IRQHandler(void)是外部中断2的服务函数,负责KEY2按键的中断检测;        因为原理图上KEY2接引脚PE2

        void EXTI3_IRQHandler(void)是外部中断3的服务函数,负责KEY1按键的中断检测;        因为原理图上KEY1接引脚PE3

        void EXTI4_IRQHandler(void)是外部中断4的服务函数,负责KEY0按键的中断检测;        因为原理图上KEY0接引脚PE4

编写中断服务函数时经常使用到的函数:

        ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);// 判断某个中断是否发生(标志位是否置位)

        void EXTI_ClearITPendingBit(uint32_t EXTI_Line);// 清除中断标志位

void EXTI3_IRQHandler(void) 
{ 
if(EXTI_GetITStatus(EXTI_Line3)!=RESET)//判断某个线上的中断是否发生  
{ …中断逻辑…  
EXTI_ClearITPendingBit(EXTI_Line3); //清除LINE上的中断标志位  
} 
}

6. STM32外部中断程序

本程序主要实现:通过中断来检测按键:

按下KEY_UP控制蜂鸣器,一叫一停;KEY2控制DS0,一亮一灭;KEY1控制DS1,一亮一灭;KEY0同时控制DS0和DS1,状态翻转;

6.1 main.c

#include "stm32f4xx.h"
#include "delay.h"
#include "LED.h"
#include "BEEP.h"
#include "Key.h"
#include "usart.h"
#include "exti.h"



int main()
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置中断优先级分组
	delay_init(168); //初始化延迟函数
	uart_init(115200); //初始化串口,设置波特率115200
	LED_Init(); //初始化LED
	BEEP_Init(); //初始化蜂鸣器
	EXTIX_Init(); //初始化外部中断
	LED0=0; //LED0点亮
	while(1)
	{
		printf("OK\r\n");//通过串口发送ok    这里需要注意想要通过串口打印必须引用头文件#include "usart.h"
//更加简单干脆的说:想要使用printf函数,就必须引用该头文件,否则就会报错
		delay_ms(1000);//1秒发送一次
	}
}

6.2 exti.c

#include "delay.h"
#include "Key.h"
#include "BEEP.h"
#include "LED.h"
#include "exti.h"

void EXTI0_IRQHandler(void)  //外部中断线0中断服务函数
{
	delay_ms(10);	//消抖
	if(KEY_UP==1)  //KEY_UP=1 表示按下
	{
		BEEP=!BEEP; //蜂鸣器翻转 
	}		 
	 EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE0上的中断标志位 
}
void EXTI2_IRQHandler(void)//中断线2的外部中断服务函数
{
	delay_ms(10); //按键消抖
	if(KEY2==0)//KEY2按下
	{
		LED0=!LED0;//LED0翻转
	}
	EXTI_ClearITPendingBit(EXTI_Line2);//消除中断线2上的中断标志位
}
void EXTI3_IRQHandler(void)//中断线3的外部中断服务函数
{
	delay_ms(10);//按键消抖
	if(KEY1==0)//KEY1按下
	{
		LED1=!LED1;//LED1翻转
	}
	EXTI_ClearITPendingBit(EXTI_Line3);//消除中断线3上的中断标志位
}
void EXTI4_IRQHandler(void)//中断线4的外部中断服务函数
{
	delay_ms(10);//按键消抖
	if(KEY0==0)//KEY0按下
	{
		LED0=!LED0;//LED0翻转
		LED1=!LED1;//LED1翻转
	}
	EXTI_ClearITPendingBit(EXTI_Line4);//消除中断线4上的中断标志位
}
void EXTIX_Init(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;// 设置中断优先级结构体变量
	EXTI_InitTypeDef EXTI_InitStructure;//设置外部中断结构体结构体变量
	
	Key_Init(); //按键对应的IO口初始化
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE); //使能SYSCFG时钟
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0); //PA0连接中断线0,映射按键KEY_UP   简单来说 接下来四条语句实现把引脚接在对应的中断线上,类似于复用功能
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource2); //PE2连接中断线2,映射按键KEY2
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource3); //PE3连接中断线3,映射按键KEY1
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource4); //PE4连接中断线4,映射按键KEY0
	
	//以下之所以要分开设置EXTI初始化函数,是因为KEY_UP是高电平1有效,KEY0/KEY1/KEY2是低电平0有效,
	//所以上升沿和下降沿需要分开设置
	

	EXTI_InitStructure.EXTI_Line=EXTI_Line0;//中断线0
	EXTI_InitStructure.EXTI_LineCmd=ENABLE;//中断使能
	EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//模式中断
	EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;//上升沿有效 通过原理图可以发现KEY_UP按键左侧接V3.3,右侧接引脚,按键没有按下时,引脚呈现低电平,按键一旦按下,引脚呈现高电平,按键按下也就表示着上升沿有效
	EXTI_Init(&EXTI_InitStructure);//初始化外部中断
	
	EXTI_InitStructure.EXTI_Line=EXTI_Line2 | EXTI_Line3 | EXTI_Line4;//中断线2/3/4
	EXTI_InitStructure.EXTI_LineCmd=ENABLE;//中断使能
	EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//模式中断
	EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;//下降沿  原理图上KEY0/KEY1/KEY2左侧接地,按键一旦按下,表示引脚低电平,也就是下降沿有效
	EXTI_Init(&EXTI_InitStructure);//初始化外部中断
	
	
	NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQn;//外部中断0
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能外部中断0
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x00;//抢占优先级0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x02;//响应优先级2
	NVIC_Init(&NVIC_InitStructure);//初始化中断优先级
	
	NVIC_InitStructure.NVIC_IRQChannel=EXTI2_IRQn;//外部中断2
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能外部中断2
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x03;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x02;//响应优先级2
	NVIC_Init(&NVIC_InitStructure);//初始化中断优先级
	
	NVIC_InitStructure.NVIC_IRQChannel=EXTI3_IRQn;//外部中断3
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能外部中断3
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02;//抢占优先级2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x02;//响应优先级2
	NVIC_Init(&NVIC_InitStructure);//初始化中断优先级
	
	NVIC_InitStructure.NVIC_IRQChannel=EXTI4_IRQn;//外部中断4
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能外部中断4
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01;//抢占优先级1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x02;//响应优先级2
	NVIC_Init(&NVIC_InitStructure);//初始化中断优先级
}

// 这里和51的外部中断的优先级顺序是相同的,抢占优先级等级越低

6.3 exti.h

#ifndef _EXTI__H_
#define _EXTI__H_

void EXTIX_Init(void);

#endif

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值