[STM32 - 野火] - - - 固件库学习笔记 - - -三.EXTI外部中断寄存器

1 EXTI介绍

EXTI(External interrupt/event controller):外部 中断/事件 控制器,通常用于微控制器或微处理器上,以便在外部事件发生时触发中断。EXTI的主要目的是允许处理器在需要时执行中断服务程序,以响应外部事件,如按键的按下、松开、传感器状态变化等。

外部事件发生(如GPIO口的电平发生变化) -> EXTI产生中断 -> 内核NVIC。

2 EXIT功能框图讲解

在这里插入图片描述

EXTI可以产生中断,也可以产生事件;上图中红色虚线指示的电路流程为产生中断的线路,绿色虚线指示的电路流程为产生事件的线路。

2.1 中断

我们先来看产生中断的线路。

  • 1.输入线。
    • 输入线总共有20根,如下图所示:

在这里插入图片描述
- 通过配置外部中断寄存器x(x=1、2、3、4)来选择外部中断的输入源。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 2.边沿检测电路。
    • 它会根据上升沿触发选择寄存器 (EXTI_RTSR) 和下降沿触发选择寄存器 (EXTI_FTSR) 对应位的设置来控制信号触发。边沿检测电路以输入线作为信号输入端,如果检测到有边沿跳变就输出有效信号 1 给与门,否则输出无效信号 0。
    • 上升沿触发与下降沿触发的区别(以按键来举例):上升沿触发捕捉按键按下的这个脉冲;而下降沿触发捕捉按键松开的这个脉冲。
    • 触发类型:可以是只有上升沿触发、只有下降沿触发或者上升沿和下降沿都触发。

在这里插入图片描述
在这里插入图片描述

  • 3.或门。
    • 它的输入信号有两个:一个来自于前面 2.边沿检测电路 ,另一个来自于软件中断事件寄存器 (EXTI_SWIER)。 EXTI_SWIER 允许我们通过程序控制就可以启动中断/事件线。

在这里插入图片描述

  • 4.与门。

    • 它的输入信号有两个:一个来自于 3.或门 ,另一个来自于中断屏蔽寄存器(EXTI_IMR)。通过这个与门,我们可以采用控制 EXTI_IMR 的方式来实现是否产生中断的目的。与门输出的信号会被保存到挂起寄存器(EXTI_PR)内,如果确定与门输出为1,就会把 EXTI_PR 对应位置 1。

在这里插入图片描述

  • 5.将 EXTI_PR 寄存器内容输出到 NVIC 内,从而实现系统中断事件控制。

2.2 事件

最终输出一个脉冲信号。

  • 1.输入线。

  • 2.边沿检测电路。

  • 3.或门。

  • 6.与门。

    • 它的输入信号有两个:一个来自于 3.或门 ,另一个来自于事件屏蔽寄存器 (EXTI_EMR)。通过这个与门,我们可以采用控制 EXTI_EMR 的方式来实现是否产生中断的目的。

在这里插入图片描述

  • 7.脉冲发生器。

    • 4.与门 的输出信号是一个有效信号1时就会产生一个脉冲,否则就不会产生脉冲。
  • 8.一个脉冲信号。

    • 这个脉冲信号可以给其他外设电路使用,如触发ADC开始转换、让定时器开始计时等。

2.3 产生中断与产生事件的区别

产生中断线路目的是把输入信号输入到 NVIC,进一步会运行中断服务函数,实现功能,这样是软件级的。

产生事件线路目的就是传输一个脉冲信号给其他外设使用,并且是电路级别的信号传输,属于硬件级的。

另外,EXTI 是在 APB2 总线上的。

3 EXIT初始化结构体讲解

typedef struct {
	uint32_t EXTI_Line; // 中断/事件线
	EXTIMode_TypeDef EXTI_Mode; // EXTI 模式
	EXTITrigger_TypeDef EXTI_Trigger; // 触发类型
	FunctionalState EXTI_LineCmd; // EXTI 使能
}
  • 1.EXTI_Line: EXTI 中断/事件线选择,可选 EXTI0 至 EXTI19。

EXTI_Line设置的是EXTI_IMR寄存器,跟真正的输入线是没有关系的(输入线由EXTI_AFIOx设置)。

  • 2.EXTI_Mode: EXTI 模式选择,可选为产生中断 (EXTI_Mode_Interrupt) 或者产生事件(EXTI_Mode_Event)。

  • 3.EXTI_Trigger: EXTI 边沿触发事件,可选上升沿触发 (EXTI_Trigger_Rising)、下降沿触发 (EXTI_Trigger_Falling) 或者上升沿和下降沿都触发 ( EXTI_Trigger_Rising_Falling)。

  • 4.EXTI_LineCmd:控制是否使能 EXTI 线,可选使能 EXTI 线 (ENABLE) 或禁用 (DISABLE)。

EXTI_LineCmd设置的是EXTI_IMR与EXTI_EMR着两个寄存器。

4 GPIO外部中断代码讲解

4.1 实验设计

  • 1.PA0、PC13连接到EXTI用于产生中断,PA0、PC13的电平变化通过按键来控制。
  • 2.产生一次中断,LED反转一次。

在这里插入图片描述

4.2 软件编程

为了使工程更加有条理,我们把EXTI相关的代码独立分开存储,方便以后移植。新建“bsp_exti.c”文件与"bsp_exti.h"文件。

步骤:

  • 1.初始化要连接到EXTI的GPIO
  • 2.初始化EXTI用于产生中断/事件
  • 3.初始化NVIC,用于处理中断
  • 4.编写中断服务函数
  • 5.main函数
// bsp_exti.h 文件
#ifndef __BSP_EXTI_H
#define __BSP_EXTI_H

#include "stm32f10x.h"

#define KEY1_INT_GPIO_Pin									GPIO_Pin_0
#define KEY1_INT_GPIO_PROT									GPIOA
#define KEY1_INT_GPIO_CLK									RCC_APB2Periph_GPIOA

#define EXTI_KEY1_CLK										RCC_APB2Periph_AFIO
#define EXTI_KEY1_GPIO_PortSourceGPIO						GPIO_PortSourceGPIOA
#define EXTI_KEY1_GPIO_PinSource							GPIO_PinSource0
#define EXTI_Line_KEY1										EXTI_Line0
#define EXTI_KEY1_IRQn										EXTI0_IRQn

#define KEY2_INT_GPIO_Pin									GPIO_Pin_13
#define KEY2_INT_GPIO_PROT									GPIOC
#define KEY2_INT_GPIO_CLK									RCC_APB2Periph_GPIOC

#define EXTI_KEY2_CLK										RCC_APB2Periph_AFIO
#define EXTI_KEY2_GPIO_PortSourceGPIO						GPIO_PortSourceGPIOC
#define EXTI_KEY2_GPIO_PinSource							GPIO_PinSource13
#define EXTI_Line_KEY2										EXTI_Line13
#define EXTI_KEY2_IRQn										EXTI15_10_IRQn 

void EXTI_KEY1_Config(void);
void EXTI_KEY2_Config(void);

#endif /* __BSP_EXTI_H */
// bsp_exti.c 文件
#include "bsp_exti.h"

static void EXTI_KEY1_NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStruct;
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	
	NVIC_InitStruct.NVIC_IRQChannel = EXTI_KEY1_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStruct);
}

static void EXTI_KEY2_NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStruct;
	
//	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	
	NVIC_InitStruct.NVIC_IRQChannel = EXTI_KEY2_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStruct);
}

void EXTI_KEY1_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	EXTI_InitTypeDef EXTI_InitStruct;
	
	// 配置 NVIC 
	EXTI_KEY1_NVIC_Config();
	
	// 初始化GPIO
	RCC_APB2PeriphClockCmd(KEY1_INT_GPIO_CLK, ENABLE);
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStruct.GPIO_Pin = KEY1_INT_GPIO_Pin;
	GPIO_Init(KEY1_INT_GPIO_PROT, &GPIO_InitStruct);
	
	// 初始化EXTI
	RCC_APB2PeriphClockCmd(EXTI_KEY1_CLK, ENABLE);
	GPIO_EXTILineConfig(EXTI_KEY1_GPIO_PortSourceGPIO, EXTI_KEY1_GPIO_PinSource);
	
	EXTI_InitStruct.EXTI_Line = EXTI_Line_KEY1;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStruct);
}

void EXTI_KEY2_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	EXTI_InitTypeDef EXTI_InitStruct;
	
	// 配置 NVIC 
	EXTI_KEY2_NVIC_Config();
	
	// 初始化GPIO
	RCC_APB2PeriphClockCmd(KEY2_INT_GPIO_CLK, ENABLE);
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStruct.GPIO_Pin = KEY2_INT_GPIO_Pin;
	GPIO_Init(KEY2_INT_GPIO_PROT, &GPIO_InitStruct);
	
	// 初始化EXTI
	RCC_APB2PeriphClockCmd(EXTI_KEY2_CLK, ENABLE);
	GPIO_EXTILineConfig(EXTI_KEY2_GPIO_PortSourceGPIO, EXTI_KEY2_GPIO_PinSource);
	
	EXTI_InitStruct.EXTI_Line = EXTI_Line_KEY2;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStruct);
}
// stm32f10x_it.c 文件

#include "stm32f10x_it.h"
#include "bsp_led.h"
#include "bsp_exti.h"

/* 在 stm32f10x_it.c 文件 中新添加两个头文件 : bsp_led.h 与 bsp_exti.h */
/* 在 stm32f10x_it.c 文件 中新添加以下两个中断服务函数 : EXTI0_IRQHandler 与 EXTI15_10_IRQHandler */
void EXTI0_IRQHandler(void)
{
	if(EXTI_GetFlagStatus(EXTI_Line_KEY1) != RESET)
	{
		LED_G_TOGGLE();
	}
	EXTI_ClearFlag(EXTI_Line_KEY1);
}

// 这里的中断名称不要写成 EXTI4_IRQHandler 
void EXTI15_10_IRQHandler(void)
{
	if(EXTI_GetFlagStatus(EXTI_Line_KEY2) != RESET)
	{
		LED_B_TOGGLE();
	}
	EXTI_ClearFlag(EXTI_Line_KEY2);
}
  • 在 stm32f10x_it.c 文件 中,如果将 EXTI15_10_IRQHandler 函数写为 EXTI4_IRQHandler 或其他名称,当你按下按键KEY2的时候程序会在 startup.stm32f10x_hd.s 文件中的默认中断服务函数里原地跳转。
// main.c 文件

#include "stm32f10x.h"
#include "bsp_exti.h"

int main(void)
{
	
	LED_G_GPIO_Config();
	LED_B_GPIO_Config();
	
	EXTI_KEY1_Config();
	EXTI_KEY2_Config();
	
	GPIO_SetBits(LED_PROT, GPIO_Pin_All);

	while(1)
	{

	}

另:

如果PA0、PB0、PC0都连接到 EXTI0 的时候该怎么判断是哪个触发了外部中断?

  • 在中断服务函数中判断 GPIOA->IDR、GPIOB->IDR、GPIOC->IDR 的最低位哪个发生了变化,然后进行相应的操作。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值