外部中断实验

介绍了STM32F10x 的中断,就来学习下外部中断。要实现的功能与按键实验一样,即通过按键控制LED,只不过这里采用外部中断方式进行控制。

1. 外部中断介绍

EXTI 简介
STM32F10x 外部中断/事件控制器(EXTI)包含多达20 个用于产生事件/中断请求的边沿检测器。EXTI 的每根输入线都可单独进行配置,以选择类型(中断或事件)和相应的触发事件(上升沿触发、下降沿触发或边沿触发),还可独立地被屏蔽。
EXTI 结构框图

EXTI 框图包含了EXTI 最核心内容,掌握了此框图,对EXTI 就有一个全局的把握,在编程的时候思路就非常清晰。从图中可以看到,总计有EXTI中断线20根,有很多信号线上都有标号9 样的“20”字样,这个表示在控制器内部类似的信号线路有20 个,这与STM32F10x 的EXTI 总共有20 个中断/事件线是吻合的。因此我们只需要理解其中一个的原理,其他的19个线路原理都是一样的。
EXTI 分为两大部分功能,一个产生中断,另一个产生事件,这两个功能从硬件上就有所差别,这个在框图中也有体现。从图中标号3 的位置处就分出了两条线路,一条是3-4-5 用于产生中断,另一条是3-6-7-8 用于产生事件。下面我们就来介绍下这两条线路:
(1)首先看下产生中断的这条线路(1-2-3-4-5)
1.标号1 为输入线,EXTI 控制器有20 个中断/事件输入线,这些输入线可以通过寄存器设置为任意一个GPIO,也可以是一些外设的事件,这部分内容我们会在后面专门讲解。输入线一般是存在电平变化的信号。
2.边沿检测电路,EXTI 可以对触发方式进行选择,通过上升沿触发选择寄存器和下降沿触发选择寄存器对应位的设置来控制信号触发。边沿检测电路以输入线作为信号输入端,如果检测到有边沿跳变就输出有效信号1 给红色框3 电路,否则输出无效信号0。而上升沿和下降沿触发选择这两个寄存器可以控制需要检测哪些类型的电平跳变过程,可以是只有上升沿触发、只有下降沿触发或者上升沿和下降沿都触发。
3.其实就是一个或门电路,一端输入信号线由标号2 提供,一端由软件中断事件寄存器提供,只要有一个为有效信号1,标号3 电路则输出有效信号1,否则为无效信号0。软件中断事件寄存器允许我们使用软件来启动中断/事件线,这个在某些地方非常有用。
4.其实就是一个与门电路,一端输入信号线由标号3 电路输出提供,一端由中断屏蔽寄存器提供,只有当两者都为有效信号1,标号4 电路才会输出有效信号1,否则输出无效。这样我们就可以简单的控制中断屏蔽寄存器来实现是否产生中断的目的。当我们把中断屏蔽寄存器设置为1 时,标号4 输出就取决于标号3 电路的输出。标号3 电路输出的信号会被保存到挂起寄存器内,如果确定标号3 电路输出为1 就会把挂起寄存器对应位置1。

5.将挂起寄存器内容输入到NVIC 内,从而实现系统中断事件的控制。
(2)最后我们再来看下产生事件这条线路(1-2-3-6-7-8),前面1-2-3都是一样的,只是在3 的输出后产生分歧。
6.其实就是一个与门电路,一端来至标号3 电路的输出信号,一端来至事件屏蔽寄存器,只有两者都为有效电平1,标号6 输出才有效。当事件屏蔽寄存器设置为0 时,不管标号3 电路输出为1 还是0,标号6 电路输出均为0。当事件屏蔽寄存器设置为1 时,标号6 电路输出取决于标号3 电路输出,这样就可以简单的控制事件屏蔽寄存器来实现是否产生事件的目的。
7.脉冲发生器电路,其输入端只与标号6 电路输出有关,标号6 输出有效,脉冲发生器才会输出一个脉冲信号。
8.脉冲信号,由标号7 脉冲发生器产生,是事件线路的终端,此脉冲信号可供其他外设电路使用,比如定时器、ADC 等。这样的脉冲信号通常用来触发定时器、ADC 等开始转换。

从上面EXTI 框图可以看出,中断线路最终会输入到NVIC 控制器中,从而会运行中断服务函数,实现中断内功能,这个是软件级的。而事件线路最后产生的脉冲信号会流向其他的外设电路,是硬件级的。在EXTI 框图最顶端可以看到,其外设接口时钟是由PCLK2,即APB2 提供,所以在后面使能EXTI 时钟的时候一定要注意。

外部中断/事件线映射
STM32F10x 的EXTI 具有20 个中断/事件线,对应连接的外设说明如下表所示:

从上表可知,STM32F10x 的EXTI 供外部IO 口使用的中断线有16 根,但是我们使用的STM32F103 芯片却远远不止16 个IO 口, 那么STM32F103 芯片怎么解决这个问题的呢?因为STM32F103 芯片每个GPIO 端口(GPIOx)均有16 个管脚,因此把每个端口的16 个IO 对应那16 根中断线EXTI0-EXTI15 。
比如:
GPIOx.0-GPIOx.15(x=A,B,C,D,E,F,G)分别对应中断线EXTI0-EXTI15,这样一来每个中断线就对应了最多7 个IO 口,比如:GPIOA.0、GPIOB.0、GPIOC.0、GPIOD.0、GPIOE.0、GPIOF.0、GPIOG.0。但是中断线每次只能连接一个在IO 口上,这样就需要通过AFIO 的外部中断配置寄存器1 的EXTIx[3:0]位来决定对应的中断线映射到哪个GPIO 端口上,对于中断线映射到GPIO 端口上的配置函数在stm32f10x_gpio.c 和stm32f10x_gpio.h 中,所以使用到外部中断时要把这个文件加入到工程中。EXTI 的GPIO 映射图如图所示:

EXTI 配置步骤
接下来我们介绍下如何使用库函数对外部中断进行配置。这个也是在编写程序中必须要了解的。具体步骤如下:(EXTI 相关库函数在stm32f10x_exti.c 和stm32f10x_exti.h 文件中)
(1)使能IO 口时钟,配置IO 口模式为输入
由于本章使用开发板上4 个按键IO 口作为外部中断输入线,因此需要使能对应的IO 口时钟及配置IO 口模式,在按键实验章节中,我们就介绍过要把对应IO 口设置为输入模式,这部分配置与按键实验一样。
(2)开启AFIO 时钟,设置IO 口与中断线的映射关系
接下来我们需要将GPIO 映射到对应的中断线上,只要使用到外部中断,就必须先使能AFIO 时钟,前面已经说了它是挂接在APB2 总线上的,所以使能AFIO时钟库函数为:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

然后,我们就可以把GPIO 映射到对应的中断线上,配置GPIO 与中断线映射的库函数如下:

void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_tGPIO_PinSource);

比如我们将中断线0 映射到GPIOA 端口,那么就需要如下配置:

GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);

这时候GPIOA.0 管脚就与中断线0 连接起来,其他端口中断线的映射类似。
(3)配置中断分组(NVIC),使能中断我们知道EXTI 产生中断线路最终是流向NVIC 控制器的,由NVIC 调用中断服务函数,因此我们需要对NVIC 进行配置。NVIC 的配置在上一章介绍STM32 中断的时候已经讲过,这里就不重复,不清楚的朋友可以回过头看下。配置NVIC范例如下:

NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//EXTI0 中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; // 子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC 寄存器

(4)初始化EXTI,选择触发方式
配置好NVIC 后,我们还需要对中断线上的中断初始化,EXTI 初始化库函数,如下:

void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);

函数形参是有一个结构体EXTI_InitTypeDef 类型的指针变量,EXTI_InitTypeDef 结构体成员变量如下:

typedef struct
{
uint32_t EXTI_Line; //中断/事件线
EXTIMode_TypeDef EXTI_Mode; //EXTI 模式
EXTITrigger_TypeDef EXTI_Trigger; //EXTI 触发方式
FunctionalState EXTI_LineCmd; //中断线使能或失能
}EXTI_InitTypeDef;

下面就来介绍下结构体内成员的意义:
EXTI_Line:EXTI 中断/事件线选择,可配置参数为EXTI0-EXTI20,可参考上表。
EXTI_Mode:EXTI 模式选择,可以配置为中断模式EXTI_Mode_Interrupt 和事件模式EXTI_Mode_Event。
EXTI_Trigger : 触发方式选择, 可以配置为上升沿触发EXTI_Trigger_Rising、下降沿触发EXTI_Trigger_Falling、上升沿和下降沿触发EXTI_Trigger_Rising_Falling。
EXTI_LineCmd:中断线使能或者失能,配置ENABLE 为使能,DISABLE 为失能,我们这里要使用外部中断,所以需使能。
(5)编写EXTI 中断服务函数
所有中断函数都在STM32F1 启动文件中,不知道中断函数名的可以打开启动文件查找。这里我们使用到的是外部中断,其函数名如下:
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
EXTI9_5_IRQHandler
EXTI15_10_IRQHandler
从函数名可以看到,前面0-4 个中断线都是独立的函数,中断线5-9 共用一个函数EXTI9_5_IRQHandler , 中断线10-15 也共用一个函数EXTI15_10_IRQHandler,所以要在编写对应中断服务函数时要注意。

硬件设计

硬件电路依然使用开发板上的4 个按键,其电路如图所示:


当按键按下时,对应的IO 口电平会发生变化,这时只要配置好对应端口的外部中断触发方式就可以触发中断。

软件设计

要实现外部中断方式控制LED,程序框架如下:
(1)初始化对应端口的EXTI
(2)编写EXTI 中断函数
(3)编写主函数
在前面介绍EXTI 配置步骤时,就已经讲解如何初始化EXTI。

EXTI 初始化函数
要使用外部中断,我们必须先对它进行配置。EXTI 初始化代码如下:

/****************************************************************
***************
* 函数名: My_EXTI_Init
* 函数功能: 外部中断初始化
* 输入: 无
* 输出: 无
*****************************************************************
**************/
void My_EXTI_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource2);//选择GPIO 管脚用作外部中断线路
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource3);//选择GPIO 管脚用作外部中断线路
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource4);//选择GPIO 管脚用作外部中断线路
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);//选择GPIO 管脚用作外部中断线路//EXTI0 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//EXTI0 中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;// 抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC 寄存器//EXTI2 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;//EXTI2 中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;// 抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority =2; //子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC 寄存器//EXTI3 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;//EXTI3 中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;// 抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority =1; //子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC 寄存器//EXTI4 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;//EXTI4 中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;// 抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; //子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC 寄存器EXTI_InitStructure.EXTI_Line=EXTI_Line0;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_Init(&EXTI_InitStructure);EXTI_InitStructure.EXTI_Line=EXTI_Line2|EXTI_Line3|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);
}

在My_EXTI_Init()函数中,首先使能AFIO 时钟,并将4 个按键端口映射到对应中断线上,4 个按键连接端口是PA0、PE2、PE3、PE4。然后配置相应的NVIC并使能对应中断通道,由于4 个按键的IO 口占用了4 个中断线,属于不同的中断通道,需要分别对其配置,从NVIC 配置代码中可以看到4 个中断通道的响应优先级为0-3,所以NVIC 被分成了2 组,分组代码放在了主函数,只有一条语句:

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组分2 组。

最后就是对EXTI 初始化,通过配置EXTI_InitStructure 结构体成员值实现EXTI 的配置,从代码中可以看到,中断线0(EXTI_Line0)被配置为上升沿触发,中断线2-4 被配置为下降沿触发,这是因为我们的按键K_UP 是高电平有效,而其他3 个按键是低电平有效,这个在按键实验中已经介绍过。其实如果你会配置一个中断线的EXTI,那么其他中断线都是类似的。

EXTI 中断函数

初始化EXTI 后,中断就已经开启了,当任意按键按下后会触发一次中断,这时程序就会进入中断服务函数执行,所以我们还需要编写对应的EXTI 中断函数,这里我们以PA0 管脚的K_UP 按键进行讲解,其他的按键的中断函数类似,具体代码如下:

/****************************************************************
***************
* 函数名: EXTI0_IRQHandler
* 函数功能: 外部中断0 函数
* 输入: 无
* 输出: 无
*****************************************************************
**************/
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0)==1)
{
delay_ms(10);
if(K_UP==1)
{
led2=0;
}
}
EXTI_ClearITPendingBit(EXTI_Line0);
}

因为PA0 管脚对应的中断线是EXTI0,所以其中断函数为EXTI0_IRQHandler,这个从名字来看就很好理解。进入中断函数后,为了确保中断是否真的发生,我们还会对其中断标志位状态进行判断,获取EXTI 中断标志位状态函数如下:

EXTI_GetITStatus(EXTI_Line0);

函数参数EXTI_Line0 是所要判断的中断线, 可以为EXTI_Line0-EXTI_Line20。如果EXTI 中断线有中断发生,函数返回SET,否则返回RESET。SET 也可以用1 表示,RESET 可以用0 表示。在结束中断服务函数前,我们还会清除中断标志位,函数如下:

EXTI_ClearITPendingBit(EXTI_Line0);

在库函数内,还提供了两个函数用来判断外部中断状态以及清除外部状态标志位的函数EXTI_GetFlagStatus 和EXTI_ClearFlag,他们的作用和前面两个函数的作用类似。只是在EXTI_GetITStatus 函数中会先判断这种中断是否使能,使能了才去判断中断标志位,而EXTI_GetFlagStatus 直接用来判断状态标志位。在中断函数内,还调用了delay_ms 函数,用于软件消抖,如果K_UP 确实按下了,就点亮D2 指示灯。

主函数
编写好EXTI 初始化和中断服务函数后,接下来就可以编写主函数了,代码如下:

/****************************************************************
***************
* 函数名: main
* 函数功能: 主函数
* 输入: 无
* 输出: 无
*****************************************************************
**************/
int main()
{
u8 i;
SysTick_Init(72);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组分2 组
LED_Init();
KEY_Init();
My_EXTI_Init(); //外部中断初始化
while(1)
{
i++;
if(i%20==0)
{
led1=!led1;
}
delay_ms(10);
}
}

主函数实现的功能很简单, 首先对NVIC 进行分组, 这里我们调用NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2)函数,将NVIC 分为2 组即抢占优先级和响应优先级都占2 位,本套教程所有中断分组都采用这种设置,后面就不做重复。再对使用到的硬件端口时钟和IO 口初始化,然后调用我们前面编写的EXTI 的初始化函数,最后进入while 循环语句,不断让D1 指示间隔200ms
闪烁。有的朋友就会问,在主函数中怎么没有看到按键对LED 的控制呢?因为我们在My_EXTI_Init()函数内就已经把按键管脚映射到中断线上,并配置了相应的触发方式,当有按键按下,即会进入对应中断服务函数执行相应的功能程序,LED的控制就在中断函数内完成的。

13 . 外部中断实验相关推荐

  1. 一起学mini2440裸机开发(十)--mini2440外部中断实验

    我今天一整天都在试着将TQ2440的那种处理中断的方法(即安装中断向量表)移植到MDK中的mini2440,但是一直没成功,这种方法一直没成功,后来又想,还是先从最简单的开始吧,就是不利用中断向量表, ...

  2. [Keil][Verilog][微机原理] 流水灯、存储器、外部中断实验_北京邮电大学计算机原理与应用课程实验报告

    计算机原理与应用实验-流水灯.存储器.外部中断实验 1 实验一 流水灯实验 1.1 实验目的 掌握ARM开发工具的使用. 掌握基本IO的使用. 1.2 实验原理及内容 电路结构图 实现流水灯的电路结构 ...

  3. gd32f303 设计中断优先级_ALIENTEK 阿波罗 STM32F767 开发板资料连载第九章 外部中断实验...

    1)实验平台:alientek 阿波罗 STM32F767 开发板2)摘自<STM32F7 开发指南(HAL 库版)>关注官方微信号公众号,获取更多资料:正点原子 第九章 外部中断实验 这 ...

  4. hal库开启中断关中断_「正点原子NANO STM32开发板资料连载」第十章 外部中断实验...

    1)实验平台:ALIENTEK NANO STM32F411 V1开发板 2)摘自<正点原子STM32F4 开发指南(HAL 库版>关注官方微信号公众号,获取更多资料:正点原子 第十章 外 ...

  5. zigbee CC2530 系列教程 5 外部中断实验

    所有课程见此链接: zigbee CC2530 系列教程 0 课程介绍 4.4外部中断实验 4.4.1 实验目的 了解使用外部中断的方法,在中断处理函数中切换LED的状态. 4.4.2 实验讲解 首先 ...

  6. 基于Atmega16的外部中断实验

    一.实验目的 1. 理解单片机中断的概念. 2. 掌握外部中断的编程方法. 二.实验内容 1. 验证课堂例题 编译下载运行课堂例题--"按键次数显示"(INT_EX1)和" ...

  7. EXIT外部中断实验——EXTI

    外部中断概述: STM32的每个IO都可以作为外部中断输入. STM32的中断控制器支持19个外部中断/事件请求: 线0~15:对应外部IO口的输入中断. 线16:连接到PVD输出. 线17:连接到R ...

  8. 基于STM32F103ZET6库函数外部中断实验

    基于STM32F103ZET6库函数外部中断实验 外部中断简介 IO 口外部中断的一般步骤 软件设计 外部中断简介 通过板载的 3 个按键,控制板载的两个 LED 的亮灭以及蜂鸣器的发声. 代码主要分 ...

  9. 单片机原理及其应用——单片机外部中断实验(八段数码管通过按键依次显示0~9数字)

    目录 一.实验要求 二.知识要点 (一)数码管 (二)八段数码管的字形编码 (三)C51变量定义的四要素 (四)中断源 (五)相关的特殊功能寄存器 1.定时器/计数器控制寄存器TCON 2.中断允许控 ...

  10. 单片机外部中断实验C语言程序,STC89C52单片机外部中断0实验

    原标题:STC89C52单片机外部中断0实验 / 实现功能: 设置,然后通过点亮与P1口第一个引脚相连的D1来 显示系统进入了外部中断0 实验板型号:BS-XYD-C52 实验名称: 外部中断0测试 ...

最新文章

  1. Spark: sortBy和sortByKey函数详解
  2. Android为TV端助力 浅谈Aidl 通讯机制
  3. 系统学习深度学习(二十)--ResNet,DenseNet,以及残差家族
  4. java并发面试题整理
  5. JAVA虚拟机创建对象
  6. scanf()接受不同类型的参数的一个例子
  7. JDK源码分析(2)之 Array 相关
  8. mysql group by 用法解析(详细)
  9. python打印网页成pdf_如何使用Python将网页转换为PDF
  10. 推荐给大家一个网络工程标书模版(仅供参考)
  11. ie浏览器总跳转到 http://hao.360.cn
  12. java todo注释_Java自定义注解
  13. 2百度元老结论:web2.0创业时代将终结
  14. 算法语句高中数学计算机,高中数学《基本算法语句》文字素材3 新人教A版必修3...
  15. 【MDX】一文带你搞懂SQL Server Analysis Services 的安装和使用
  16. 新西兰正式提高购房首付比例
  17. 直播app源代码 直播软件开发Android UI动画 仿直播点赞飘心动画效果
  18. 【Ray Tracing The Rest of Your Life】第3章 光线散射理论
  19. TFTP服务器的下载与上传
  20. 明解C语言入门篇_第7章_基本数据类型

热门文章

  1. html tooltips效果,html5tooltips.js – 一款轻量级的3D工具提示插件
  2. 在北京租房 舒舍的租客素质怎么样?
  3. 协作:一份来自RChain的倡议书(上篇)
  4. oracle 11g 重置,oracle数据库重置
  5. 多服务台排队系统仿真基于c语言,带优先级的多服务台排队系统Monte Carlo模拟
  6. Virustotal使用
  7. linux看门狗定时器,看门狗定时器的作用
  8. 74ls390设计任意进制计数器_《设计任意进制计数器》的实验报告
  9. 字节码层面理解枚举类Enum在switch中的使用
  10. java http 传输二进制流_字符流、字节流、二进制及其在HTTP协议传输