欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STM32笔记(六)---GPIO中断EXTI

程序员文章站 2022-04-01 21:59:06
...

GPIO中断EXTI


STM32笔记(六)---GPIO中断EXTI

一、 基础概念

EXTI框图

STM32笔记(六)---GPIO中断EXTI

​ 外部中断通用I/O映像

STM32笔记(六)---GPIO中断EXTI

​ EXTI 中断/事件线

STM32笔记(六)---GPIO中断EXTI

STM32笔记(六)---GPIO中断EXTI

1.输入线总共有20条,EXTI0~EXTI19

2.通过配置AFIO_EXTICRx寄存器相应位段进行设置:

STM32笔记(六)---GPIO中断EXTI

STM32笔记(六)---GPIO中断EXTI

以框图为配置步骤参考,上升沿与下降沿触发选择寄存器(EXTI_RTSR 、EXTI_FTSR )配置后GPIO触发则边沿检测电路输出1与软件中断事件寄存器(EXTI_SWIER )相或;

上端(中断):输出至请求挂起寄存器(EXTI_PR)置1并同中断屏蔽寄存器(EXTI-IMR)相与输出至NVIC中断控制器(中断服务函数)

下端(事件):输出至与门跟事件屏蔽寄存器(EXTI_EMR )相与输出至脉冲发生器(常常与ADC关联)

STM32笔记(六)---GPIO中断EXTI

  • 上升沿与下降沿触发选择寄存器(EXTI_RTSR 、EXTI_FTSR )

    以GPIO上升沿触发选择寄存器(EXTI_RTSR)为例,配置上升沿触发选择寄存器相应位为1

    STM32笔记(六)---GPIO中断EXTI

  • 软件中断事件寄存器(EXTI_SWIER )

    STM32笔记(六)---GPIO中断EXTI

  • 挂起寄存器(EXTI-PR)

    STM32笔记(六)---GPIO中断EXTI

  • 中断屏蔽寄存器(EXTI-IMR)

    STM32笔记(六)---GPIO中断EXTI

  • 事件屏蔽寄存器(EXTI_EMR)

    STM32笔记(六)---GPIO中断EXTI

二、中断步骤:

  • GPIO触发

  • EXTI配置

  • NVIC配置

  • NVIC中断服务

三、 中断编程:

  • STM32笔记(六)---GPIO中断EXTI

两个文件: bsp_exti.c 和 bsp_exti.h 文件用来存放 EXTI 驱动程序及相关宏定义,中断服务函数放在 stm32f10x_it.h 文件中。

思路:

  1. 初始化用来产生中断的 GPIO;
  2. 初始化 EXTI;
  3. 配置 NVIC;
  4. 编写中断服务函数;

EXTI_InitTypeDef结构体

typedef struct {
	uint32_t EXTI_Line; // 中断/事件线
	EXTIMode_TypeDef EXTI_Mode; // EXTI 模式
	EXTITrigger_TypeDef EXTI_Trigger; // 触发类型
	FunctionalState EXTI_LineCmd; // EXTI 使能
} EXTI_InitTypeDef
  • EXTI_Line: EXTI 中断/事件线选择,可选 EXTI0 至 EXTI19。
  • EXTI_Mode: EXTI 模式选择,可选为产生中断(EXTI_Mode_Interrupt)或者产生事件(EXTI_Mode_Event)。
  • EXTI_Trigger: EXTI 边沿触发事件,可选上升沿触发(EXTI_Trigger_Rising)、下降沿触发 (EXTI_Trigger_Falling) 或 者 上 升 沿 和 下 降 沿 都 触 发(EXTI_Trigger_Rising_Falling)。
  • EXTI_LineCmd:控制是否使能 EXTI 线,可选使能 EXTI 线(ENABLE)或禁用(DISABLE)。

bsp-exti.c

#include "bsp-exti.h"

//配置EXTI中断优先级
//初始化连接EXTI的按键GPIO
//初始化EXTI用于产生中断/事件
	//开启AFIO外设时钟
	//选择输入线(EXTIConfig)
//初始化NVIC-EXTI中断配置,用于处理中断
//编写中断服务函数
//main函数声明内容

//配置EXTI中断优先级函数(static---只被当前文件调用)
static void EXTI_NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStruct;
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);			//设置中断优先级组:1组(整个系统为同一组)
	
	NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;			//Channel这里EXTI5~9都是用一个中断源、EXTI10~15也是一个
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;	//抢占优先级0
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;			//子优先级0(响应优先级)
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStruct);							//初始化
	//EXTI13为中断源
	NVIC_InitStruct.NVIC_IRQChannel = EXTI15_10_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;	//抢占优先级1
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;			//子优先级0(响应优先级)
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;			//使能
	NVIC_Init(&NVIC_InitStruct);							//初始化
}

void EXTI_Key_Config(void)
{
	//定义GPIO/NVIC结构体
	GPIO_InitTypeDef GPIO_InitStructure;
	EXTI_InitTypeDef EXTI_InitStruct;
	
//配置中断优先级
	EXTI_NVIC_Config();
	
//初始化连接EXTI的按键GPIO

	RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK|KEY2_GPIO_CLK, ENABLE);//RCC时钟开启
	
	//GPIO结构体配置(KEY1--A0)
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;		//浮空输入模式
	GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	
	GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStructure);				//GPIO初始化
	
	//GPIO结构体配置(KEY2--C13)
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;		//浮空输入模式
	GPIO_InitStructure.GPIO_Pin = KEY2_GPIO_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	
	GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStructure);				//GPIO初始化
	
//初始化EXTI用于产生中断/事件

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);		//开启AFIO外设时钟
	
	//选择输入线(EXTIConfig)
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource13);
	
//初始化NVIC结构体

	//“stm32f10x_exti.h”---EXTI_InitTypeDef
	EXTI_InitStruct.EXTI_Line = EXTI_Line0;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;			//A0上升沿触发
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStruct);								//EXTI初始化
	
	EXTI_InitStruct.EXTI_Line = EXTI_Line13;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;		//C13下降沿触发
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStruct);								//EXTI初始化
}

IRQHandler—'stm32f10x_it.c’

//在startup_stm32f10x.h中找中断服务函数名称

//EXTI0中断服务函数
void EXTI0_IRQHandler(void)
{
	//当中断标志位**时
	if(EXTI_GetFlagStatus(EXTI_Line0) != RESET)
	{
		LED_Delay(0xFFFFFF);		//便于观察现象
		LED_TOGGLE;					//LED翻转
	}
	//完成翻转服务内容后清除中断标志位
	EXTI_ClearITPendingBit(EXTI_Line0);
}

//EXTI13中断服务函数
void EXTI15_10_IRQHandler(void)
{
	//当中断标志位**时
	if(EXTI_GetFlagStatus(EXTI_Line13) != RESET)
	{
		LED_Fire();					//LED流水灯函数
	}
	//完成翻转服务内容后清除中断标志位
	EXTI_ClearITPendingBit(EXTI_Line13);
}

main函数

int main(void)
{	
	LED_GPIO_Config();
	EXTI_Key_Config();
	while(1)
	{
		//中断表现为延时期间抢占优先级为1的C13无法打断抢占优先级为0的A0,只有当A0完成中断服务时,才进入C13归属的EXTI中断
		//同时C13可以被A0打断
	}
}
配置流程总结

配置EXTI中断优先级(NVIC_InitTypeDef结构体配置通道优先级、NVIC_PriorityGroupConfig()配置优先级分组)

初始化连接EXTI的按键GPIO(RCC使能、GPIO配置)

初始化EXTI用于产生中断/事件(开启AFIO外设时钟、选择输入线(EXTIConfig))

初始化NVIC-EXTI中断配置,用于处理中断(EXTI_InitTypeDef结构体中断属性配置)

编写中断服务函数(正确的中断服务函数名称、中断标志位(需要时加入中断线判断))

main函数声明内容(Config配置)

疑问解答
  • PA0/PB0/PC0都挂到EXTI0上,怎么处理中断?
    这时中断源设置中的最后设置中断GPIO口会覆盖同中断线上已设置的GPIO口。(AFIO_EXTICR1寄存器设置讲述很清楚)
    即同时设置PA0,PD0情况下,PA0若为后设置中断源,由于两者挂载同一中断线,则选择后者(A0)为中断源
    解决方法:同中断线通过IO口扫描。
  • 可以同时配置共用一个中断服务函数的两个中断源吗,怎么区分?
    明内容(Config配置)
相关标签: 嵌入式 stm32