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); //初始化串口,设置波特率115200LED_Init(); //初始化LEDBEEP_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,映射按键KEY2SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource3); //PE3连接中断线3,映射按键KEY1SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource4); //PE4连接中断线4,映射按键KEY0//以下之所以要分开设置EXTI初始化函数,是因为KEY_UP是高电平1有效,KEY0/KEY1/KEY2是低电平0有效,//所以上升沿和下降沿需要分开设置EXTI_InitStructure.EXTI_Line=EXTI_Line0;//中断线0EXTI_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/4EXTI_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;//外部中断0NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能外部中断0NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x00;//抢占优先级0NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x02;//响应优先级2NVIC_Init(&NVIC_InitStructure);//初始化中断优先级NVIC_InitStructure.NVIC_IRQChannel=EXTI2_IRQn;//外部中断2NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能外部中断2NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x03;//抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x02;//响应优先级2NVIC_Init(&NVIC_InitStructure);//初始化中断优先级NVIC_InitStructure.NVIC_IRQChannel=EXTI3_IRQn;//外部中断3NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能外部中断3NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02;//抢占优先级2NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x02;//响应优先级2NVIC_Init(&NVIC_InitStructure);//初始化中断优先级NVIC_InitStructure.NVIC_IRQChannel=EXTI4_IRQn;//外部中断4NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能外部中断4NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01;//抢占优先级1NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x02;//响应优先级2NVIC_Init(&NVIC_InitStructure);//初始化中断优先级
}// 这里和51的外部中断的优先级顺序是相同的,抢占优先级等级越低
6.3 exti.h
#ifndef _EXTI__H_
#define _EXTI__H_void EXTIX_Init(void);#endif
STM32F4_外部中断详解(EXTI)相关推荐
- STM32开发 -- 外部中断详解
如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/87376865 在讲三轴加速度计的时候,提到外部中断.接下来就看看中断为什么这 ...
- 【STM32学习笔记】(13)——外部中断详解
EXTI 简介 EXTI(External interrupt/event controller)-外部中断/事件控制器,管理了控制器的 20 个中断/事件线.每个输入线可以独立地配置 ...
- STM32 外部中断详解(原理+配置代码)
本文介绍了STM32基于标准外设库的外部中断配置,以及基于参考手册如何更加寄存器配置外部中断 文章目录 1 前言 2 STM32的外部中断 3 中断服务函数的映射关系 4 外部中断的配置 5 寄存器的 ...
- STM32入门笔记03_EXTI外部中断详解+案例:红外对射计数、旋转编码器计数
EXTI外部中断 中断的相关概念 中断源: 可以引起中断的事件称为中断源 中断: 在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成 ...
- 单片机中段程序_单片机外部中断详解及程序
单片机在自主运行的时候一般是在执行一个死循环程序,在没有外界干扰(输入信号)的时候它基本处于一个封闭状态.比如一个电子时钟,它会按时.分.秒的规律来自主运行并通过输出设备(如液晶显示屏)把时间显示出来 ...
- STM32 中断详解
目录 1 EXTI控制器 2 NVIC控制器 3 code 中断,在单片机中占有非常重要的地位.代码默认地从上向下执行,遇到条件或者其他语句,会按照指定的地方跳转.而在单片机执行代码的过程中,难免会有 ...
- linux内核中断详解
linux内核中断详解 1.中断的硬件触发流程 外设:如果外设有操作或者有数据可用,那么就会产生一个电信号,这个电信号发送给中断控制器. 中断控制器:中断控制器接收到外设发来的电信号以后,进行进一步的 ...
- 51单片机中断详解(上)
一.中断的概念 中断发生 CPU在处理某一事件A时,发生了另一事件B请求CPU迅速去处理 中断响应和中断服务 CPU暂时中断当前的工作,转去处理事件B 中断返回 待CPU将事件B处理完毕后,再回到原来 ...
- 【stm32】中断详解
stm32中断的顺序: 1)初始化 IO 口. 2)开启 AFIO 时钟 3)EXTI配置. 4)NVIC配置. 5)编写中断服务函数. 1 NVIC中断优先级管理 CM3 内核支持 256 个中断, ...
最新文章
- AJAX 传值数据类型问题
- Android判断Service是否运行
- 【Java数据结构】自己实现一个HahMap(实现其put, toString, get方法)
- php访问者信息,如何通过PHP检索访问者的ISP?
- ElasticSearch 动态映射与静态映射_08
- 多个python文件打包成exe_Python 3.4 .py文件打包成exe可执行文件方法
- mysql not exists优化_MySQL优化--NOT EXISTS和LEFT JOIN方式差异
- 20145209 《信息安全系统设计基础》第10周学习总结
- Nginx默认虚拟主机、 Nginx用户认证、Nginx域名重定向、访问日志·····
- C/C++与lua实现互调
- Socket.IO文档(1)
- 网管必读-常用网络命令
- tomcat 如何进行优化?优化方案有哪些?
- win10 ie浏览器安装Flash Player Debugger解决方案
- Battleship!
- 需要查询前一次该厂商,料号的单价, 这个sql语句很难写,你碰到过没有
- 【二次分配问题】基于遗传算法 (GA)、粒子群优化 (PSO) 和萤火虫算法 (FA) 求解二次分配( QAP)问题(MATLAB 实现)
- 金蝶cloud 常用数据库表
- linux time效率,time(),gettimeofday()及GetTickCount()效率比较
- sql 语句操作,修改字段中字符串的一部分