当前位置: 首页 > article >正文

STM32F4_外部中断详解(EXTI)

目录

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


http://www.kler.cn/a/6843.html

相关文章:

  • 足球虚拟越位线技术FIFA OT(二)
  • MySQL时间字段TIMESTAMP和DATETIME
  • SDF,一个从1978年运行至今的公共Unix Shell
  • 前后端交互之动态列
  • 集群聊天服务器(9)一对一聊天功能
  • PostgreSQL技术内幕18:物理备份工具pg_basebackup
  • row_number 和 cte 使用实例:分组轮流排班
  • 【独家】华为OD机试 - 狼羊过河 or 羊、狼、农夫过河(C 语言解题)
  • 基于单片机的室内空气质量检测系统设计_kaic
  • 2023年全国最新二级建造师精选真题及答案44
  • IOS - 某段子APP分析
  • 接口测试4:企业微信接口自动化
  • 实现js程序在vscode控制台输出的方法(看完方便多了)
  • 红黑树(算法导论版)
  • nginx反向代理网页502、SSL_do_handshake()握手失败
  • 聊聊MySQL主从延迟
  • SpringBoot整合XXL分布式任务调度(图文详细)
  • ThreeJS-VR小岛(二十七)
  • JSwebAPI ,0基础第一天
  • Windows配置虚拟网络
  • 市场监管总局关于对锂离子电池等产品实施强制性产品认证管理的公告
  • GitHub使用技巧
  • ASEMI代理HMC717ALP3E原装ADI(亚德诺)车规级HMC717ALP3E
  • Kafka3.0.0版本——生产者同步发送消息 (API代码示例)
  • 【SSM】Spring6(七.Spring IoC注解式开发)
  • 第四届国际工业信息安全应急大会完美落幕,赛宁网安载誉满满!