【STM32】外部中断
00. 目录
文章目录
- 00. 目录
- 01. 外部中断简介
- 02. 外部中断配置
- 03. 外部中断步骤
- 04. 硬件设计
- 05. 程序示例一
- 06. 程序示例二
- 07. 附录
- 08. 声明
01. 外部中断简介
外部中断的代码主要分布在固件库的 stm32f4xx_exti.h 和 stm32f4xx_exti.c 文件中。
STM32F4 的每个 IO 都可以作为外部中断的中断输入口,这点也是 STM32F4 的强大之处。STM32F407 的中断控制器支持 22
个外部中断/事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。
STM32F407 的 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 唤醒事件。
从上面可以看出,STM32F4 供 IO 口使用的中断线只有 16 个,但是 STM32F4 的 IO 口却远远不止 16 个,那么 STM32F4 是怎么把 16 个中断线和 IO 口一一对应起来的呢?于是 STM32就这样设计,GPIO 的管教 GPIOx.0~GPIOx.15(x=A,B,C,D,E,F,G,H,I)分别对应中断线 0~15。这样每个中断线对应了最多 9 个 IO 口,以线 0 为例:它对应了 GPIOA.0、GPIOB.0、GPIOC.0、GPIOD.0、GPIOE.0、GPIOF.0、GPIOG.0,GPIOH.0,GPIOI.0。而中断线每次只能连接到 1 个 IO口上,这样就需要通过配置来决定对应的中断线配置到哪个 GPIO 上了。下面我们看看 GPIO跟中断线的映射关系图:
02. 外部中断配置
2.1 使能 IO口时钟,初始化 IO
我们要使用 IO 口作为中断输入,所以我们要使能相应的 IO 口时钟,以及初始化相应的 IO 口为输入模式
2.2 开启 SYSCFG 时钟,设置 IO 口与中断线的映射关系
只要我们使用到外部中断,就必须打开 SYSCFG 时钟。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能 SYSCFG 时钟
配置 GPIO 与中断线的映射关系。在库函数中,配置 GPIO 与中断线的映射关系的函数 SYSCFG_EXTILineConfig ()来实现的:
void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex);
该函数将 GPIO 端口与中断线映射起来,程序示例:
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
2.3 初始化线上中断,设置触发条件
中断线上中断的初始化是通过函数 EXTI_Init()实现的。EXTI_Init()函数的定义是:
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
程序示例
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line= EXTI_Line4;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure); //初始化外设 EXTI 寄存器
2.4 配置中断分组(NVIC ),并使能中断
我们设置好中断线和 GPIO 映射关系,然后又设置好了中断的触发模式等初始化参数。既然是外部中断,涉及到中断我们当然还要设置 NVIC 中断优先级。
NVIC_InitTypeDef NVIC_InitStructure;
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); //中断优先级分组初始化
2.5 编写中断服务函数
我们配置完中断优先级之后,接着要做的就是编写中断服务函数。中断服务函数的名字是在 MDK 中事先有定义的。这里需要说明一下,STM32F4 的 IO 口外部中断函数只有 7 个,分别为:
DCD EXTI0_IRQHandler ; EXTI Line0
DCD EXTI1_IRQHandler ; EXTI Line1
DCD EXTI2_IRQHandler ; EXTI Line2
DCD EXTI3_IRQHandler ; EXTI Line3
DCD EXTI4_IRQHandler ; EXTI Line4
DCD EXTI9_5_IRQHandler ; External Line[9:5]s
DCD EXTI15_10_IRQHandler ; External Line[15:10]s
中断线 0-4 每个中断线对应一个中断函数,中断线 5-9 共用中断函数 EXTI9_5_IRQHandler,中断线 10-15 共用中断函数EXTI15_10_IRQHandler。在编写中断服务函数的时候会经常使用到两个函数,第一个函数是判断某个中断线上的中断是否发生(标志位是否置位)
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
这个函数一般使用在中断服务函数的开头判断中断是否发生。另一个函数是清除某个中断线上的中断标志位:
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
这个函数一般应用在中断服务函数结束之前,清除中断标志位。
03. 外部中断步骤
使用 IO 口外部中断的一般步骤:
1)使能 IO 口时钟,初始化 IO 口为输入。
2)使能 SYSCFG 时钟,设置 IO 口与中断线的映射关系。
3)初始化线上中断,设置触发条件等。
4)配置中断分组(NVIC),并使能中断。
5)编写中断服务函数。
04. 硬件设计
探索者 STM32F4 开发板上载有的 4 个按钮(KEY_UP、KEY0、KEY1 和 KEY2),来控制板上的 2 个 LED(DS0 和 DS1)和蜂鸣器,其中 KEY_UP 控制蜂鸣器,按一次叫,再按一次停;KEY0 控制 DS0,按一次亮,再按一次灭;KEY1 控制 DS1,
效果同 KEY2;KEY2 则同时控制 DS0 和 DS1,按一次,它们的状态就翻转一次。
05. 程序示例一
KEY0控制LED1的翻转
exti.h文件
#ifndef __EXTI_H__
#define __EXTI_H__#include "sys.h"//中断初始化函数void EXTIX_Init(void);#endif /*__EXTI_H__*/
exti.c文件
#include "exti.h"
#include "key.h"
#include "led.h"
#include "delay.h"
#include "usart.h"//中断初始化函数void EXTIX_Init(void){EXTI_InitTypeDef EXTI_InitStruct;NVIC_InitTypeDef NVIC_InitStruct;//按键初始化KEY_Init();//初始化SYSCFG时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//KEY0 --> PE4SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource4);//配置中断EXTI_InitStruct.EXTI_Line = EXTI_Line4;EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;EXTI_InitStruct.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStruct);//配置中断分组NVIC_InitStruct.NVIC_IRQChannel = EXTI4_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);}//中断线4处理函数
void EXTI4_IRQHandler(void)
{printf("KEY0按下啦....\r\n");//消抖delay_ms(10);if (0 == KEY0){LED1 = !LED1;}//清中断EXTI_ClearITPendingBit(EXTI_Line4);
}
main.c文件
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "beep.h"
#include "key.h"
#include "exti.h"int main(void)
{ BEEP = 0;LED1 = 0;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);BEEP_Init();LED_Init();delay_init(168);uart_init(115200);//外部中断初始化EXTIX_Init();while(1){printf("程序正在运行.....\r\n");delay_ms(1000);}
}
06. 程序示例二
exti.h文件
#ifndef __EXTI_H__
#define __EXTI_H__#include "sys.h"//中断初始化函数void EXTIX_Init(void);#endif /*__EXTI_H__*/
exti.c文件
#include "exti.h"
#include "key.h"
#include "led.h"
#include "beep.h"
#include "delay.h"
#include "usart.h"//中断初始化函数void EXTIX_Init(void){EXTI_InitTypeDef EXTI_InitStruct;NVIC_InitTypeDef NVIC_InitStruct;//按键初始化KEY_Init();//初始化SYSCFG时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//KEY0 --> PE4SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource4);//KEY1 --> PE3SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource3);//KEY1 --> PE2SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource2);//KEY_UP --> PA0SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);//配置中断 KEY0 KEY1 KEY2EXTI_InitStruct.EXTI_Line = EXTI_Line4 | EXTI_Line3 | EXTI_Line2;EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;EXTI_InitStruct.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStruct);//配置中断 KEY_UPEXTI_InitStruct.EXTI_Line = EXTI_Line0;EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;EXTI_InitStruct.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStruct);//配置中断分组 KEY0NVIC_InitStruct.NVIC_IRQChannel = EXTI4_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);//配置中断分组 KEY1NVIC_InitStruct.NVIC_IRQChannel = EXTI3_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);//配置中断分组 KEY2NVIC_InitStruct.NVIC_IRQChannel = EXTI2_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);//配置中断分组 WK_UPNVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);}//中断线4处理函数
void EXTI4_IRQHandler(void)
{printf("KEY0按下啦....\r\n");//消抖delay_ms(10);if (0 == KEY0){LED1 = !LED1;}//清中断EXTI_ClearITPendingBit(EXTI_Line4);
}//中断线3处理函数
void EXTI3_IRQHandler(void)
{printf("KEY1按下啦....\r\n");//消抖delay_ms(10);if (0 == KEY1){LED2 = !LED2;}//清中断EXTI_ClearITPendingBit(EXTI_Line3);
}//中断线2处理函数
void EXTI2_IRQHandler(void)
{printf("KEY2按下啦....\r\n");//消抖delay_ms(10);if (0 == KEY2){LED1 = !LED1;LED2 = !LED2;}//清中断EXTI_ClearITPendingBit(EXTI_Line2);
}//中断线0处理函数
void EXTI0_IRQHandler(void)
{printf("KEY_UP按下啦....\r\n");//消抖delay_ms(10);if (1 == WK_UP){BEEP = !BEEP;}//清中断EXTI_ClearITPendingBit(EXTI_Line0);
}
main.c文件
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "beep.h"
#include "key.h"
#include "exti.h"int main(void)
{ BEEP = 0;LED1 = 0;LED2 = 0;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);BEEP_Init();LED_Init();delay_init(168);uart_init(115200);//外部中断初始化EXTIX_Init();while(1){printf("程序正在运行.....\r\n");delay_ms(1000);}
}
07. 附录
7.1 【STM32】STM32系列教程汇总
网址:【STM32】STM32系列教程汇总
08. 声明
该教程参考了正点原子的《STM32 F4 开发指南》
【STM32】外部中断相关推荐
- STM32外部中断与各通道对应关系
EXTI0_IRQn的值,其实就是EXTI0中断向量在中断向量表中的位置(STM32技术参考手册中断向量表position栏中的数值) 一:外部中断使用配置过程: (1)配置时钟信号 (2)引脚属性 ...
- STM32外部中断干扰解决方案
STM32 外部中断很容易受干扰误触发,无论上拉下拉设置都没有效果,最后采用软件判断解决该问题. 进入外部中断程序需同时判断引脚电平是否和上升触发和下降触发一致,这个判断很重要. void EXTI3 ...
- STM32外部中断总结
STM32外部中断总结 STM32的外部中断是我们在学习stm32的一个必要模块,外部中断的用途可以增加人机交互的体验,也可以增加程序的执行效率.下面将以一个小实验来记录外部中断的使用需要注意的事项 ...
- STM32——外部中断
目录 外部中断简述 什么是外部中断 传统单片机与新型单片机外部中断区别 STM32外部中断请求 STM32中断线与IO口的对应 STM32 中断服务函数 外部中断与中断服务函数的对应 中断服务函数列表 ...
- 采用STM32外部中断模式控制LED灯亮灭
文章目录 实验工具 一.STMCube配置项目 1.配置引脚 2.配置EXIT 3.配置SYS 4.配置GPIO 5.创建代码 二.使用KEil配置代码 1.打开生成的项目,找到stm32f1xx_i ...
- 【嵌入式STM32-05】STM32 外部中断 EXTI 基本原理|库函数程序代码|寄存器
STM32外部中断 1.中断基本原理 中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行 中断 ...
- STM32外部中断与(NVIC)中断优先级管理
文章目录 1.中断介绍 1.中断的概念 2.中断的产生 3.中断处理的流程 2.STM32内嵌向量中断控制器NVIC 1.NVIC控制器的寄存器 2.STM32中断配置 3.STM32外部中断EXIT ...
- STM32外部中断与看门狗
STM32外部中断与看门狗 前面说过中断的概念了,但是没有细究,中断除了内部中断(比如运行错误),还能受到外部中断 文章目录 STM32外部中断与看门狗 一 外部中断描述 1.1 外部中断描述 1.2 ...
- stm32 外部中断学习
今天我们看看STM32的外部中断实验. STM32 供 IO 口使用的中断线只有 16 个,但是 STM32 的 IO 口却远远不止 16 个,那么 STM32 是怎么把 16 个中断线和 IO 口一 ...
- stm32外部中断_STM32学习笔记 | 电源管理及低功耗设计要点
一款好的电子产品,都需要认真考虑电源管理的问题,电池供电的产品更应该注意低功耗的实现. STM32电源介绍 嵌入式开发直播课 - STM32 USART串口的应用 - 创客学院直播室www.make ...
最新文章
- 大数据读书笔记(1)
- MYSQL 添加外键报错
- 知乎的 Flink 数据集成平台建设实践
- 信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言—— 1066:满足条件的数累加
- 列举python的5个数据类型_python公开课|新公布的5个python核心数据类型,这些细节你难道还不不知道吗...
- Google Protocol Buffers 2.3.0 for java 快速开始
- 技术分享 | 基于EOS的Dapp开发
- php 数组设置为空,PHP数组设置空值
- XStream将XML转换为JAVA对象快速指南
- 理解[].forEach.call()
- Android--应用开发1(应用程序框架)
- AT指令集超详细解析(内含EC20模块datasheet)
- 处于托管模式时无法删除mcafee解决办法
- 【每日最爱一句】2013.06.10
- SAP工具箱通用条件/加点率配置
- 12092009小记
- LTE PWS CMAS CBS消息
- qlearningα越大或越小_高频电子线路习题及答案
- css鼠标点击后取消光标焦点,光标设置透明
- 创业时代,喔,创业时代,有一点可爱有一点呆
热门文章
- Cocos2dx 中 倒计时保留2位数写法
- [ZJOI2010]数字计数
- C#使用BackgroundWorker实现多线程
- MFC中滑动条的使用
- python 回测模块_回测调用研究模块总结(慎用Python3 PacVer 2.0)
- python简单定义_python定义类的简单用法
- 【数据结构总结】第一章:数据结构基本概念
- java中从str1中删除所有str2_Java中str1.equals(str2)和str1==str2的区别
- mysql profiling表_mysql8 参考手册-INFORMATION_SCHEMA PROFILING表
- 移动端与pc端的区别 及 ios的 兼容性问题