前言:
此时同学们对“外部中断程序框图”大约比较着重,朋友们都想要分析一些“外部中断程序框图”的相关文章。那么小编同时在网络上汇集了一些有关“外部中断程序框图””的相关文章,希望大家能喜欢,同学们快快来学习一下吧!外部中断EXTI
实验目的掌握STM32 EXTI外部中断原理。掌握STM32中断优先级含义。掌握GPIO口外部中断程序设计。实验内容编写程序实现单个GPIO口外部中断的触发。编写程序实现多个GPIO口外部中断的触发。硬件设计开发板IO口外部中断硬件电路
微处理器STM32的每一个IO口都可以作为外部中断输入使用。实现IO口电平变化以触发中断的方式有很多,使用外部按键改变IO口电平是最为简单直观的一种方式。
IK-ZET6开发板上设计了4个用户按键S1、S2、S3、S4,分别连接到STM32F103ZET6的PE2~PE5引脚。可以通过操作相应按键控制相应外部中断触发,进入中断服务函数。
图1:开发板IO口外部中断硬件电路
4个用户按键占用的单片机的引脚如下表:
表1:用户按键引脚分配
KEY
颜色
引脚
说明
按键S1
黄色
PE2
独立GPIO
按键S2
黄色
PE3
独立GPIO
按键S3
黄色
PE4
独立GPIO
按键S4
黄色
PE5
独立GPIO
注:独立GPIO表示开发板没有其他的电路使用这个GPIO。STM32外部中断EXTI简介
EXTI是External interrupt/event controller缩写,翻译过来是:外部中断/事件控制器。
微处理器STM32的每一个GPIO口都能配置成一个外部中断触发源,这是意法半导体STM32的强大之处。
STM32F103ZET6支持 19 个外部中断/事件请求,每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。下图为外部中断/事件控制器框图。
图2:外部中断/事件控制器框图
针对微处理器STM32F103外部中断/事件输入线、连接源及中断服务函数汇总如下表:
表2:EXTI相关输入线及中断服务函数
序号
输入线
连接源
中断服务函数
备注
1
输入线0
PA0 ~ PG0
EXTI0_IRQHandler
PA0 ~ PG0中选其一
2
输入线1
PA1 ~ PG1
EXTI1_IRQHandler
PA1 ~ PG1中选其一
3
输入线2
PA2 ~ PG2
EXTI2_IRQHandler
PA2 ~ PG2中选其一
4
输入线3
PA3 ~ PG3
EXTI3_IRQHandler
PA3 ~ PG3中选其一
5
输入线4
PA4 ~ PG4
EXTI4_IRQHandler
PA4 ~ PG4中选其一
6
输入线5
PA5 ~ PG5
EXTI9_5_IRQHandler
PA5 ~ PG5中选其一
7
输入线6
PA6 ~ PG6
PA6 ~ PG6中选其一
8
输入线7
PA7 ~ PG7
PA7 ~ PG7中选其一
9
输入线8
PA8 ~ PG8
PA8 ~ PG8中选其一
10
输入线9
PA9 ~ PG9
PA9 ~ PG9中选其一
11
输入线10
PA10 ~ PG10
EXTI15_10_IRQHandler
PA10 ~ PG10中选其一
12
输入线11
PA11 ~ PG11
PA11 ~ PG11中选其一
13
输入线12
PA12 ~ PG12
PA12 ~ PG12中选其一
14
输入线13
PA13 ~ PG13
PA13 ~ PG13中选其一
15
输入线14
PA14 ~ PG14
PA14 ~ PG14中选其一
16
输入线15
PA15 ~ PG15
PA15 ~ PG15中选其一
17
输入线16
PVD输出
PVD_IRQHandler
软件配置
18
输入线17
RTC闹钟事件
RTCAlarm_IRQHandler
软件配置
19
输入线18
USB唤醒事件
USBWakeUp_IRQHandler
软件配置
注:针对STM32F105和STM32F107互联型产品,输入线总数是20,除上述19个外,还有连接到以太网唤醒事件的输入线。软件设计EXTI寄存器汇集
STM32F103提供了6个用于操作EXTI的寄存器,如下表所示:
表3:EXTI相关寄存器
序号
寄存器名
读/写
功能描述
1
EXTI_IMR
读/写
中断屏蔽寄存器。
2
EXTI_EMR
读/写
事件屏蔽寄存器。
3
EXTI_RTSR
读/写
上升沿触发选择寄存器。
4
EXTI_FTSR
读/写
下降沿触发选择寄存器。
5
EXTI_SWIER
读/写
软件中断事件寄存器。
6
EXTI_PR
只写
挂起寄存器。
每一种寄存器详细的描述在这里不做具体的介绍,大家可以参考目录:“第1部分:开发板硬件资料”--->“2 - 芯片资料”中“STM32英文参考手册_V15”或“STM32中文参考手册_V10”对应的Interrupts and events章节的寄存器部分认真研读。
EXTI库函数汇集
官方提供的最终库函数版本是V3.5版本,该版本库函数提供了8个与EXTI操作有关的库函数,如下表所示:
表4:EXTI相关库函数汇集
序号
函数名
功能描述
1
EXTI_DeInit
将外设 EXTI 寄存器重设为缺省值。
2
EXTI_Init
根据EXTI_InitStruct中指定参数初始化外设EXTI寄存器。
3
EXTI_StructInit
把 EXTI_InitStruct 中的每一个参数按缺省值填入。
4
EXTI_GenerateSWInterrupt
产生一个软件中断。
5
EXTI_GetFlagStatus
检查指定的 EXTI 线路标志位设置与否。
6
EXTI_ClearFlag
清除 EXTI 线路挂起标志位。
7
EXTI_GetITStatus
检查指定的 EXTI 线路触发请求发生与否。
8
EXTI_ClearITPendingBit
清除 EXTI 线路挂起位。
每一种寄存器详细的描述在这里不一一进行介绍,大家可以参考目录:“第1部分:开发板硬件资料”--->“2 - 芯片资料”中“STM32固件库使用手册的中文翻译版”对应的EXTI章节的库函数部分认真研读。
IO口外部中断配置过程
针对STM32F103的GPIO口为外部中断时,软件的配置过程如下:
图3:外部中断软件配置步骤
注:实验例程即是按照上述配置步骤调用相关库函数实现,后有详述。外部中断2实验注:本节对应的实验源码是:“实验5-1:EXTI2外部中断2”。工程需要用到的库文件
在使用库函数建“实验5-1:EXTI2外部中断2”工程时,需要用到的c文件如下表所示。
表5:实验需要用到的C文件
序号
文件名
后缀
功能描述
1
stm32f10x_rcc
.c
复位与时钟控制器。
2
stm32f10x_gpio
.c
通用输入输出。
3
stm32f10x_exti
.c
外部中断/事件。
4
misc
.c
中断向量控制器。
注:STM32 V3.5版本库函数中没有原来版本中单独对于NVIC的外设驱动,把NVIC的外设驱动放在了misc.c中,实际上是代替原来的stm32f10x_nvic.c文件。
可按下图所示在新建工程时添加需要的c文件。
图4:在新建工程中添加所需库函数c文件
表6:实验需要用到的H文件
序号
文件名
后缀
功能描述
1
stm32f10x_rcc
.h
复位与时钟控制器。
2
stm32f10x_gpio
.h
通用输入输出。
3
stm32f10x_exti
.h
外部中断/事件。
4
misc
.h
中断向量控制器。
注:所建工程必须添加上面h文件所在的目录:..\..\ Lib\ F10x_FWLIB\ inc。
在使用该实验工程时,需要用到的h文件如表5所示。需要在MDK中点击魔术棒,打开工程配置窗口,按照下图所示添加头文件包含路径。
图5:如何添加头文件包含路径
编写代码
首先编写初始化PE2为外部中断2,完成的操作有:将PE2配置为上拉输入,使能AFIO复用时钟功能,PE2口映射到EXTI2输入线上,EXTI2初始化,EXTI2的中断优先级配置。具体代码如下。
代码清单:初始化PE2为外部中断2
/******************************************************************************* * 描 述 : 初始化PE2为外部中断2 * 参 数 : 无 * 返回值 : 无 ******************************************************************************/ void EXTI_PE2_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the EXTI_PE2 Clock */ RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOE , ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入 GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource2); //配置PE2管脚为外部中断线路用
EXTI_InitStructure.EXTI_Line = EXTI_Line2; //配置为外部中断线2 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //配置为中断请求 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //输入线路下降沿为中断请求 EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能中断 EXTI_Init(&EXTI_InitStructure);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //NVIC_Group:先占优先级2位,从优先级2位 NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //配置为外部中断2中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //先占优先级为1 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //从优先级为2 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断通道 NVIC_Init(&NVIC_InitStructure); }
然后,编写外部中断2的中断服务函数。代码如下。
代码清单:EXTI2中断服务函数
/************************************************************************************** * 描 述 : 外部中断服务程序 * 入 参 : 无 * 返回值 : 无 **************************************************************************************/ void EXTI2_IRQHandler(void) { led_on(LED_1); //点亮指示灯D1 sw_delay_ms(200); //延时200ms led_off(LED_1); //熄灭指示灯D1 sw_delay_ms(200); //延时200ms led_on(LED_1); //点亮指示灯D1 sw_delay_ms(200); //延时200ms led_off(LED_1); //熄灭指示灯D1 sw_delay_ms(200); //延时200ms
EXTI_ClearITPendingBit(EXTI_Line2); //清除EXTI中断线路挂起位 }注:进中断服务程序会执行用户指示灯D1闪烁2次的任务。
最后,主函数会调用相关函数实现对PE2的配置,在while循环中没有添加任务。如下图所示。
代码清单:主函数
int main(void) { //初始化用于驱动指示灯D1、D2、D3、D4的引脚 leds_init(); //初始化PE2为外部中断2 EXTI_PE2_Init(); //主循环 while(1) { ; //无任务,说明有用户指示灯闪烁来自于外部中断服务函数 } } 实验步骤解压“…\第3部分:标准库教程和实验源码\ 1 - 基础实验程序\”目录下的压缩文件“实验5-1: EXTI2外部中断2”,打开解压后的文件夹,将“EXTI2”文件夹拷贝到合适的目录,如“D\STM32F103ZET6”。启动MDK5.23。在MDK5中执行“Project→Open Project”打开“…\ EXTI2 \projec”目录下的工程“EXTI2.uvproj”。点击编译按钮编译工程。注意查看编译输出栏,观察编译的结果,如果有错误,修改程序,直到编译成功为止。编译后生成的HEX文件“EXTI2.hex”位于工程目录下的“Objects”文件夹中。点击下载按钮下载程序 。如果需要对程序进行仿真,点击Debug按钮,即可将程序下载到STM32F103ZET6中进行仿真。程序运行后,按下开发板按键S1,可观察到指示灯D1闪烁2次。思考题1:分析下按键S1是按下时D1闪烁还是松开时D1闪烁?为什么?外部中断3实验注:本节对应的实验源码是:“实验5-2: EXTI3外部中断3”。工程需要用到的库文件
在使用库函数建“实验5-2: EXTI3外部中断3”工程时,需要用到的c文件以及添加头文件包含路径的方法与介绍“实验5-1: EXTI2外部中断2”完全一样,在此不再赘述。
编写代码
首先编写初始化PE3为外部中断3,完成的操作有:将PE3配置为上拉输入,使能AFIO复用时钟功能,PE3口映射到EXTI3输入线上,EXTI3初始化,EXTI3的中断优先级配置。具体代码如下。
代码清单:初始化PE3为外部中断3
/******************************************************************************* * 描 述 : 初始化PE3为外部中断3 * 参 数 : 无 * 返回值 : 无 ******************************************************************************/ void EXTI_PE3_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; /* Enable the EXTI_PE3 Clock */ RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOE , ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入 GPIO_Init(GPIOE, &GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource3); //配置PE3管脚为外部中断线路用
EXTI_InitStructure.EXTI_Line = EXTI_Line3; //配置为外部中断线3 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //配置为中断请求 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //输入线路上升沿为中断请求 EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能中断 EXTI_Init(&EXTI_InitStructure);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //NVIC_Group:先占优先级2位,从优先级2位 NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn; //配置为外部中断3中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //先占优先级为1 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //从优先级为2 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断通道 NVIC_Init(&NVIC_InitStructure); }
然后,编写外部中断3的中断服务函数。代码如下。
代码清单:EXTI3中断服务函数
/************************************************************************************** * 描 述 : 外部中断服务程序 * 入 参 : 无 * 返回值 : 无 **************************************************************************************/ void EXTI3_IRQHandler(void) { led_on(LED_2); //点亮指示灯D2 sw_delay_ms(200); //延时200ms led_off(LED_2); //熄灭指示灯D2 sw_delay_ms(200); //延时200ms led_on(LED_2); //点亮指示灯D2 sw_delay_ms(200); //延时200ms led_off(LED_2); //熄灭指示灯D2 sw_delay_ms(200); //延时200ms
EXTI_ClearITPendingBit(EXTI_Line3); //清除EXTI中断线路挂起位 } 注:进中断服务程序会执行用户指示灯D2闪烁2次的任务。
最后,主函数会调用相关函数实现对PE3的配置,在while循环中没有添加任务。如下图所示。
代码清单:主函数
int main(void) { //初始化用于驱动指示灯D1、D2、D3、D4的引脚 leds_init(); //初始化PE3为外部中断3 EXTI_PE3_Init(); //主循环 while(1) { ; //无任务,说明有用户指示灯闪烁来自于外部中断服务函数 } } 实验步骤解压“…\第3部分:标准库教程和实验源码\ 1 - 基础实验程序\”目录下的压缩文件“实验5-2: EXTI3外部中断3”,打开解压后的文件夹,将“EXTI3”文件夹拷贝到合适的目录,如“D\STM32F103ZET6”。启动MDK5.23。在MDK5中执行“Project→Open Project”打开“…\ EXTI3 \projec”目录下的工程“EXTI3.uvproj”。点击编译按钮编译工程。注意查看编译输出栏,观察编译的结果,如果有错误,修改程序,直到编译成功为止。编译后生成的HEX文件“EXTI3.hex”位于工程目录下的“Objects”文件夹中。点击下载按钮下载程序 。如果需要对程序进行仿真,点击Debug按钮,即可将程序下载到STM32F103ZET6中进行仿真。程序运行后,按下开发板按键S2,可观察到指示灯D2闪烁2次。思考题1:分析下按键S2是按下时D2闪烁还是松开时D2闪烁?为什么?外部中断4实验注:本节对应的实验源码是:“实验5-3: EXTI4外部中断4”。工程需要用到的库文件
在使用库函数建“实验5-3: EXTI4外部中断4”工程时,需要用到的c文件以及添加头文件包含路径的方法与介绍“实验5-1: EXTI2外部中断2”完全一样,在此不再赘述。
编写代码
首先编写初始化PE4为外部中断4,完成的操作有:将PE4配置为上拉输入,使能AFIO复用时钟功能,PE4口映射到EXTI4输入线上,EXT4初始化,EXTI4的中断优先级配置。具体代码如下。
代码清单:初始化PE4为外部中断4
/******************************************************************************* * 描 述 : 初始化PE4为外部中断4 * 参 数 : 无 * 返回值 : 无 ******************************************************************************/ void EXTI_PE4_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the EXTI_PE4 Clock */ RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOE , ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入 GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource4); //配置PE4管脚为外部中断线路用
EXTI_InitStructure.EXTI_Line = EXTI_Line4; //配置为外部中断线4 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //配置为中断请求 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; //输入线路上升沿或下降沿为中断请求 EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能中断 EXTI_Init(&EXTI_InitStructure);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //NVIC_Group:先占优先级2位,从优先级2位 NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn; //配置为外部中断4中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //先占优先级为1 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //从优先级为2 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断通道 NVIC_Init(&NVIC_InitStructure); }
然后,编写外部中断4的中断服务函数。代码如下。
代码清单:EXTI4中断服务函数
/************************************************************************************** * 描 述 : 外部中断服务程序 * 入 参 : 无 * 返回值 : 无 **************************************************************************************/ void EXTI4_IRQHandler(void) { led_on(LED_3); //点亮指示灯D3 sw_delay_ms(200); //延时200ms led_off(LED_3); //熄灭指示灯D3 sw_delay_ms(200); //延时200ms led_on(LED_3); //点亮指示灯D3 sw_delay_ms(200); //延时200ms led_off(LED_3); //熄灭指示灯D3 sw_delay_ms(200); //延时200ms
EXTI_ClearITPendingBit(EXTI_Line4); //清除EXTI中断线路挂起位 } 注:进中断服务程序会执行用户指示灯D3闪烁2次的任务。
最后,主函数会调用相关函数实现对PE4的配置,在while循环中没有添加任务。如下图所示。
代码清单:主函数
int main(void) { //初始化用于驱动指示灯D1、D2、D3、D4的引脚 leds_init(); //初始化PE4为外部中断4 EXTI_PE4_Init(); //主循环 while(1) { ; //无任务,说明有用户指示灯闪烁来自于外部中断服务函数 } } 实验步骤解压“…\第3部分:标准库教程和实验源码\ 1 - 基础实验程序\”目录下的压缩文件“实验5-3: EXTI4外部中断4”,打开解压后的文件夹,将“EXTI4”文件夹拷贝到合适的目录,如“D\STM32F103ZET6”。启动MDK5.23。在MDK5中执行“Project→Open Project”打开“…\ EXTI4 \projec”目录下的工程“EXTI4.uvproj”。点击编译按钮编译工程。注意查看编译输出栏,观察编译的结果,如果有错误,修改程序,直到编译成功为止。编译后生成的HEX文件“EXTI4.hex”位于工程目录下的“Objects”文件夹中。点击下载按钮下载程序 。如果需要对程序进行仿真,点击Debug按钮,即可将程序下载到STM32F103ZET6中进行仿真。程序运行后,按下开发板按键S3不松开,可观察到指示灯D3闪烁2次。将按下的按键S3松开,可观察到指示灯D3又闪烁2次。思考题1:分析下按键S3按下和松开时D3为什么都会闪烁?外部中断5实验注:本节对应的实验源码是:“实验5-4: EXTI5外部中断5”。工程需要用到的库文件
在使用库函数建“实验5-4: EXTI5外部中断5”工程时,需要用到的c文件以及添加头文件包含路径的方法与介绍“实验5-1: EXTI2外部中断2”完全一样,在此不再赘述。
编写代码
首先编写初始化PE5为外部中断5,完成的操作有:将PE5配置为上拉输入,使能AFIO复用时钟功能,PE5口映射到EXTI5输入线上,EXTI5初始化,EXTI5的中断优先级配置。具体代码如下。
代码清单:初始化PE5为外部中断5
/******************************************************************************* * 描 述 : 初始化PE5为外部中断5 * 参 数 : 无 * 返回值 : 无 ******************************************************************************/ void EXTI_PE5_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the EXTI_PE5 Clock */ RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOE , ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入 GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource5); //配置PE5管脚为外部中断线路用
EXTI_InitStructure.EXTI_Line = EXTI_Line5; //配置为外部中断线5 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //配置为中断请求 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //输入线路下降沿为中断请求 EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能中断 EXTI_Init(&EXTI_InitStructure);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //NVIC_Group:先占优先级2位,从优先级2位 NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; //配置为外部中断5中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //先占优先级为1 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //从优先级为2 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断通道 NVIC_Init(&NVIC_InitStructure); }
然后,编写外部中断5的中断服务函数。代码如下。
代码清单:EXTI5中断服务函数
/************************************************************************************** * 描 述 : 外部中断服务程序 * 入 参 : 无 * 返回值 : 无 **************************************************************************************/ void EXTI9_5_IRQHandler(void) { led_on(LED_4); //点亮指示灯D4 sw_delay_ms(200); //延时200ms led_off(LED_4); //熄灭指示灯D4 sw_delay_ms(200); //延时200ms led_on(LED_4); //点亮指示灯D4 sw_delay_ms(200); //延时200ms led_off(LED_4); //熄灭指示灯D4 sw_delay_ms(200); //延时200ms
EXTI_ClearITPendingBit(EXTI_Line5); //清除EXTI中断线路挂起位 } 注:进中断服务程序会执行用户指示灯D4闪烁2次的任务。此中断服务函数名已与之前中断服务函数有所不同。
最后,主函数会调用相关函数实现对PE5的配置,在while循环中没有添加任务。如下图所示。
代码清单:主函数
int main(void) { //初始化用于驱动指示灯D1、D2、D3、D4的引脚 leds_init(); //初始化PE5为外部中断5 EXTI_PE5_Init(); //主循环 while(1) { ; //无任务,说明有用户指示灯闪烁来自于外部中断服务函数 } } 实验步骤解压“…\第3部分:标准库教程和实验源码\ 1 - 基础实验程序\”目录下的压缩文件“实验5-4: EXTI5外部中断5”,打开解压后的文件夹,将“EXTI5”文件夹拷贝到合适的目录,如“D\STM32F103ZET6”。启动MDK5.23。在MDK5中执行“Project→Open Project”打开“…\ EXTI5 \projec”目录下的工程“EXTI5.uvproj”。点击编译按钮编译工程。注意查看编译输出栏,观察编译的结果,如果有错误,修改程序,直到编译成功为止。编译后生成的HEX文件“EXTI5.hex”位于工程目录下的“Objects”文件夹中。点击下载按钮下载程序 。如果需要对程序进行仿真,点击Debug按钮,即可将程序下载到STM32F103ZET6中进行仿真。程序运行后,按下开发板按键S4,可观察到指示灯D4闪烁2次。思考题1:分析下按键S4是按下时D4闪烁还是松开时D4闪烁?为什么?多个外部中断实验注:本节对应的实验源码是:“实验5-5:多个EXTI外部中断”。工程需要用到的库文件
在使用库函数建“实验5-5:多个EXTI外部中断”工程时,需要用到的c文件以及添加头文件包含路径的方法与介绍“实验5-1: EXTI2外部中断2”完全一样,在此不再赘述。
编写代码
首先编写初始化PE2为外部中断2、PE3为外部中断3、PE4为外部中断4、PE5为外部中断5。具体代码如下。
代码清单:初始化PE2为外部中断2
/******************************************************************************* * 描 述 : 初始化PE2为外部中断2 * 参 数 : 无 * 返回值 : 无 ******************************************************************************/ void EXTI_PE2_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure;
/* Enable the EXTI_PE2 Clock */ RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOE , ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入 GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource2); //配置PE2管脚为外部中断线路用
EXTI_InitStructure.EXTI_Line = EXTI_Line2; //配置为外部中断线2 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //配置为中断请求 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //输入线路下降沿为中断请求 EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能中断 EXTI_Init(&EXTI_InitStructure); }
代码清单:初始化PE3为外部中断3
/******************************************************************************* * 描 述 : 初始化PE3为外部中断3 * 参 数 : 无 * 返回值 : 无 ******************************************************************************/ void EXTI_PE3_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure;
/* Enable the EXTI_PE3 Clock */ RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOE , ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入 GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource3); //配置PE3管脚为外部中断线路用
EXTI_InitStructure.EXTI_Line = EXTI_Line3; //配置为外部中断线3 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //配置为中断请求 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //输入线路下降沿为中断请求 EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能中断 EXTI_Init(&EXTI_InitStructure); }
代码清单:初始化PE4为外部中断4
/ /******************************************************************************* * 描 述 : 初始化PE4为外部中断4 * 参 数 : 无 * 返回值 : 无 ******************************************************************************/ void EXTI_PE4_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure;
/* Enable the EXTI_PE4 Clock */ RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOE , ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入 GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource4); //配置PE4管脚为外部中断线路用
EXTI_InitStructure.EXTI_Line = EXTI_Line4; //配置为外部中断线4 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //配置为中断请求 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //输入线路下降沿为中断请求 EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能中断 EXTI_Init(&EXTI_InitStructure); }
代码清单:初始化PE5为外部中断5
/******************************************************************************* * 描 述 : 初始化PE5为外部中断5 * 参 数 : 无 * 返回值 : 无 ******************************************************************************/ void EXTI_PE5_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure;
/* Enable the EXTI_PE5 Clock */ RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOE , ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入 GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource5); //配置PE5管脚为外部中断线路用
EXTI_InitStructure.EXTI_Line = EXTI_Line5; //配置为外部中断线5 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //配置为中断请求 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //输入线路下降沿为中断请求 EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能中断 EXTI_Init(&EXTI_InitStructure); }
然后,配置外部中断2、外部中断3、外部中断4、外部中断5的中断优先级。代码如下。
代码清单:配置EXTI2、EXTI3、EXTI4、EXTI5中断优先级
/******************************************************************************* * 描 述 : 配置嵌套向量中断控制器 * 参 数 : 无 * 返回值 : 无 ******************************************************************************/ void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //NVIC_Group:先占优先级2位,从优先级2位
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //配置为外部中断2中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //先占优先级为1 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //从优先级为1 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断通道 NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn; //配置为外部中断3中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //先占优先级为1 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //从优先级为2 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断通道 NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn; //配置为外部中断4中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级为2 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //从优先级为2 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断通道 NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; //配置为外部中断5中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级为2 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级为3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断通道 NVIC_Init(&NVIC_InitStructure); }
之后,编写外部中断3的中断服务函数、外部中断3的中断服务函数、外部中断4的中断服务函数、外部中断5的中断服务函数。代码如下。
代码清单:EXTI2中断服务函数
/************************************************************************************** * 描 述 : 外部中断服务程序 * 入 参 : 无 * 返回值 : 无 **************************************************************************************/ void EXTI2_IRQHandler(void) { led_on(LED_1); //点亮指示灯D1 sw_delay_ms(200); //延时200ms led_off(LED_1); //熄灭指示灯D1 sw_delay_ms(200); //延时200ms led_on(LED_1); //点亮指示灯D1 sw_delay_ms(200); //延时200ms led_off(LED_1); //熄灭指示灯D1 sw_delay_ms(200); //延时200ms
EXTI_ClearITPendingBit(EXTI_Line2); //清除EXTI中断线路挂起位 } 注:进中断服务程序会执行用户指示灯D1闪烁2次的任务。
代码清单:EXTI3中断服务函数
/************************************************************************************** * 描 述 : 外部中断服务程序 * 入 参 : 无 * 返回值 : 无 **************************************************************************************/ void EXTI3_IRQHandler(void) { led_on(LED_2); //点亮指示灯D2 sw_delay_ms(200); //延时200ms led_off(LED_2); //熄灭指示灯D2 sw_delay_ms(200); //延时200ms led_on(LED_2); //点亮指示灯D2 sw_delay_ms(200); //延时200ms led_off(LED_2); //熄灭指示灯D2 sw_delay_ms(200); //延时200ms
EXTI_ClearITPendingBit(EXTI_Line3); //清除EXTI中断线路挂起位 } 注:进中断服务程序会执行用户指示灯D2闪烁2次的任务。
代码清单:EXTI4中断服务函数
/************************************************************************************** * 描 述 : 外部中断服务程序 * 入 参 : 无 * 返回值 : 无 **************************************************************************************/ void EXTI4_IRQHandler(void) { led_on(LED_3); //点亮指示灯D3 sw_delay_ms(200); //延时200ms led_off(LED_3); //熄灭指示灯D3 sw_delay_ms(200); //延时200ms led_on(LED_3); //点亮指示灯D3 sw_delay_ms(200); //延时200ms led_off(LED_3); //熄灭指示灯D3 sw_delay_ms(200); //延时200ms
EXTI_ClearITPendingBit(EXTI_Line4); //清除EXTI中断线路挂起位 } 注:进中断服务程序会执行用户指示灯D3闪烁2次的任务。
代码清单:EXTI5中断服务函数
/************************************************************************************** * 描 述 : 外部中断服务程序 * 入 参 : 无 * 返回值 : 无 **************************************************************************************/ void EXTI9_5_IRQHandler(void) { led_on(LED_4); //点亮指示灯D4 sw_delay_ms(200); //延时200ms led_off(LED_4); //熄灭指示灯D4 sw_delay_ms(200); //延时200ms led_on(LED_4); //点亮指示灯D4 sw_delay_ms(200); //延时200ms led_off(LED_4); //熄灭指示灯D4 sw_delay_ms(200); //延时200ms
EXTI_ClearITPendingBit(EXTI_Line5); //清除EXTI中断线路挂起位 } 注:进中断服务程序会执行用户指示灯D4闪烁2次的任务。
最后,主函数会调用相关函数实现对PE2、PE3、PE4、PE5的配置,在while循环中没有添加任务。如下图所示。
代码清单:主函数
int main(void) { //初始化用于驱动指示灯D1、D2、D3、D4的引脚 leds_init(); //初始化PE2为外部中断2 EXTI_PE2_Init(); //初始化PE3为外部中断3 EXTI_PE3_Init(); //初始化PE4为外部中断4 EXTI_PE4_Init(); //初始化PE5为外部中断5 EXTI_PE5_Init(); //配置嵌套向量中断控制器 NVIC_Configuration(); //主循环 while(1) { ; //无任务,说明有用户指示灯闪烁来自于外部中断服务函数 } } 实验步骤解压“…\第3部分:标准库教程和实验源码\ 1 - 基础实验程序\”目录下的压缩文件“实验5-5: 多个EXTI外部中断”,打开解压后的文件夹,将“EXTIs”文件夹拷贝到合适的目录,如“D\STM32F103ZET6”。启动MDK5.23。在MDK5中执行“Project→Open Project”打开“…\ EXTIs \projec”目录下的工程“EXTIs.uvproj”。点击编译按钮编译工程。注意查看编译输出栏,观察编译的结果,如果有错误,修改程序,直到编译成功为止。编译后生成的HEX文件“EXTIs.hex”位于工程目录下的“Objects”文件夹中。点击下载按钮下载程序 。如果需要对程序进行仿真,点击Debug按钮,即可将程序下载到STM32F103ZET6中进行仿真。程序运行后,可按下述操作进行实验:
1)按下开发板按键S1,可观察到指示灯D1闪烁2次。
2)按下开发板按键S2,可观察到指示灯D2闪烁2次。
3)按下开发板按键S3,可观察到指示灯D3闪烁2次。
4)按下开发板按键S4,可观察到指示灯D4闪烁2次。
5)同时按下开发板按键S1、S2时,可观察到指示灯D1最先闪烁2次,然后是D2闪烁2次。
6)同时按下开发板按键S2、S3时,可观察到指示灯D2最先闪烁2次,然后是D3闪烁2次。
7)同时按下开发板按键S3、S4时,可观察到指示灯D3最先闪烁2次,然后是D4闪烁2次。
8)同时按下开发板按键S1、S2、S3、S4时,可观察到指示灯D1最先闪烁2次,然后依次是D2闪烁2次、D3闪烁2次、D4闪烁2次。
9)先按下开发板按键S2,可观察到指示灯D2开始闪烁,待D2完成1次闪烁后,立刻按下按键S1,可观察到D2接着完成第2次闪烁,待D2闪烁结束后,D1闪烁2次。
10)先按下开发板按键S3,可观察到指示灯D3开始闪烁,待D3完成1次闪烁后,立刻按下按键S1,可观察到D3不闪烁,而是D1闪烁2次,待D1闪烁结束后,D3接着完成第2次闪烁。
11)先按下开发板按键S3,可观察到指示灯D3开始闪烁,待D3完成1次闪烁后,立刻按下按键S4,可观察到D3接着完成第2次闪烁,待D3闪烁结束后,D4闪烁2次。
思考题1:分析下上述实验现象和中断优先级的关系?如果各外部中断的中断优先级进行其他配置,又会是怎样的实验现象?
标签: #外部中断程序框图