STM32笔记归纳7:EXTI

EXTI

目录

EXTI

一、工作原理

1.1.EXTI模块简介

1.2.EXTI应用举例

1.3.线的概念

1.4.线的内部结构

二、按钮实验

2.1.搭建电路

2.2.分配EXTI线

2.3.配置EXTI线的参数

2.4.配置NVIC模块

2.5.编写中断响应函数

2.5.1.确定中断响应函数的名称

2.5.2.判断哪条线触发了中断

2.5.3.清除标志位

2.6.总代码


一、工作原理

1.1.EXTI模块简介

**EXTI(External Interrupt and Event ControllerI):**外部中断和事件控制器

EXTI检测引脚电平的高低变化

GPIO接收引脚输入的高低电平

类似于一个铃铛挂在每组GPIO上的IO引脚上,检测到电平变化时就触发中断

在中断响应函数中编写处理代码,当电平发生变化时就可以自动执行相应程序

1.2.EXTI应用举例

通过创建previous、current两个变量捕捉按钮按下和松开的瞬间

通过EXTI检测电平的上升沿和下降沿产生中断,在中断函数中切换LED亮灭状态

1.3.线的概念

EXTI中一共有20条线,可以产生20路不同的中断

一组GPIO引脚最多16个

EXIT中断数量也为16个

用复用器将这条EXTI线分配给GPIO的某一个组对应编号的引脚

同一时刻只能有一组GPIO对应编号的引脚使能这条EXTI的功能

1.4.线的内部结构

复用器将线分配给GPIO的某一个组对应编号的引脚

边沿检测电路从输入信号中检测上升沿和下降沿

上升沿和下降沿经过或门可产生双边沿信号

将上升沿、下降沿、双边信号输入到复用器

软件触发:只需向软件写0或写1就可以触发

二、按钮实验

2.1.搭建电路

cpp 复制代码
#include "stm32f10x.h"

//声明板载LED初始化函数
void App_OnBoardLED_Init(void);
//声明按钮初始化函数
void App_Button_Init(void);

int main(void)
{
	App_OnBoardLED_Init();
	App_Button_Init();
	
	while(1)
	{
	}
}

//创建板载LED初始化函数
void App_OnBoardLED_Init(void)
{
	/*启动GPIOC时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	/*声明GPIO结构变量*/
	GPIO_InitTypeDef GPIO_InitStruct;
	/*选择PC13引脚*/
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
	/*通用输出开漏模式*/
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
	/*最大输出速率为2MHz*/
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
	/*初始化PC13引脚*/
	GPIO_Init(GPIOC,&GPIO_InitStruct);
	/*熄灭板载LED*/
	GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);
}


//创建按钮初始化函数
void App_Button_Init(void)
{
	/*启动GPIOA时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	/*声明GPIO结构变量*/
	GPIO_InitTypeDef GPIO_InitStruct;
	/*选择PA5引脚*/
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
	/*输入上拉模式*/
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	/*初始化PA5引脚*/
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	/*选择PA6引脚*/
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
	/*输入上拉模式*/
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	/*初始化PA6引脚*/
	GPIO_Init(GPIOA,&GPIO_InitStruct);
}

2.2.分配EXTI线

cpp 复制代码
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource,uint8_t GPIO_PinSource);

解析:

**参数1:**端口号

  • GPIO_PortSourceGPIOA
  • GPIO_PortSourceGPIOB
  • GPIO_PortSourceGPIOC
  • GPIO_PortSourceGPIOD

**参数2:**线编号

  • GPIO_PinSource0 ~ GPIO_PinSource15

**作用:**使用AFIO模块为EXTI的线选择IO引脚

cpp 复制代码
//创建按钮初始化函数
void App_Button_Init(void)
{
	//#1:初始化PA5和PA6
	
	/*启动GPIOA时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	/*声明GPIO结构变量*/
	GPIO_InitTypeDef GPIO_InitStruct;
	/*选择PA5引脚*/
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
	/*输入上拉模式*/
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	/*初始化PA5引脚*/
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	/*选择PA6引脚*/
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
	/*输入上拉模式*/
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	/*初始化PA6引脚*/
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	//#2:为EXTI5和EXTI6分配引脚
	
	/*开启AFIO的时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	/*线5选择端口A*/
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource5);
	/*线6选择端口A*/
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource6);
}

2.3.配置EXTI线的参数

cpp 复制代码
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);

解析:

**参数:**初始化的参数结构体地址

**作用:**用来初始化EXTI的一条线

**补充:**EXTI_InitTypeDef结构

cpp 复制代码
struct EXTI_InitTypeDef
{
    uint32_t EXTI_Line;
    EXTIMode_TypeDef EXTI_Mode;
    EXTITrigger_TypeDef EXTI_Teigger;
    FunctionalState EXTI_LineCmd;
};

分析:

**1.EXTI_Line:**线编号

  • EXTI_Line0 ~ EXTI_Line19

**2.EXTI_Mode:**选择模式

  • EXTI_Mode_Interrupt:中断
  • EXTI_Mode_Event:事件

**3.EXTI_Teigger:**边沿

  • EXTI_Teigger_Rising:上升沿
  • EXTI_Teigger_Falling:下降沿
  • EXTI_Teigger_Rising_Falling:双边沿

**4.EXTI_LineCmd:**开关

  • ENABLE:闭合
  • DISABLE:断开
cpp 复制代码
//创建按钮初始化函数
void App_Button_Init(void)
{
	//#1:初始化PA5和PA6
	
	/*启动GPIOA时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	/*声明GPIO结构变量*/
	GPIO_InitTypeDef GPIO_InitStruct;
	/*选择PA5引脚*/
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
	/*输入上拉模式*/
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	/*初始化PA5引脚*/
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	/*选择PA6引脚*/
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
	/*输入上拉模式*/
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	/*初始化PA6引脚*/
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	//#2:为EXTI5和EXTI6分配引脚
	
	/*开启AFIO的时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	/*线5选择端口A*/
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource5);
	/*线6选择端口A*/
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource6);
	
	//#3:初始化EXTI的线
	
	/*声明EXTI结构变量*/
	EXTI_InitTypeDef EXTI_InitStruct;
	/*选择EXTI_Line5*/
	EXTI_InitStruct.EXTI_Line = EXTI_Line5;
	/*中断模式*/
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	/*上升沿采集*/
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
	/*闭合开关*/
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	/*初始化Line5*/
	EXTI_Init(&EXTI_InitStruct);
	/*选择EXTI_Line6*/
	EXTI_InitStruct.EXTI_Line = EXTI_Line6;
	/*中断模式*/
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	/*上升沿采集*/
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
	/*闭合开关*/
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	/*初始化Line6*/
	EXTI_Init(&EXTI_InitStruct);
}

**注:**EXTI模块比较特殊,无需使能EXTI模块的时钟

2.4.配置NVIC模块

cpp 复制代码
int main(void)
{
	/*设置中断优先级分组*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	App_OnBoardLED_Init();
	App_Button_Init();
	while(1)
	{
	}
}

//创建按钮初始化函数
void App_Button_Init(void)
{
	//#1:初始化PA5和PA6
	
	/*启动GPIOA时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	/*声明GPIO结构变量*/
	GPIO_InitTypeDef GPIO_InitStruct;
	/*选择PA5引脚*/
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
	/*输入上拉模式*/
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	/*初始化PA5引脚*/
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	/*选择PA6引脚*/
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
	/*输入上拉模式*/
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	/*初始化PA6引脚*/
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	//#2:为EXTI5和EXTI6分配引脚
	
	/*开启AFIO的时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	/*线5选择端口A*/
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource5);
	/*线6选择端口A*/
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource6);
	
	//#3:初始化EXTI的线
	
	/*声明EXTI结构变量*/
	EXTI_InitTypeDef EXTI_InitStruct;
	/*选择EXTI_Line5*/
	EXTI_InitStruct.EXTI_Line = EXTI_Line5;
	/*中断模式*/
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	/*上升沿采集*/
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
	/*闭合开关*/
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	/*初始化Line5*/
	EXTI_Init(&EXTI_InitStruct);
	/*选择EXTI_Line6*/
	EXTI_InitStruct.EXTI_Line = EXTI_Line6;
	/*中断模式*/
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	/*上升沿采集*/
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
	/*闭合开关*/
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	/*初始化Line6*/
	EXTI_Init(&EXTI_InitStruct);
	
	//#4:配置中断
	
	/*声明NVIC结构变量*/
	NVIC_InitTypeDef NVIC_InitStruct;
	/*设置EXTI9_5中断名称*/
	NVIC_InitStruct.NVIC_IRQChannel = EXTI9_5_IRQn;
	/*设置抢占优先级*/
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	/*子优先级*/
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
	/*闭合中断开关*/
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	/*初始化NVIC*/
	NVIC_Init(&NVIC_InitStruct);
}

**注:**在stm32f10x.h中搜索枚举IRQn,寻找中断的名称

2.5.编写中断响应函数

2.5.1.确定中断响应函数的名称

打开startup文件,在中断向量表中找中断响应函数

cpp 复制代码
void EXTI9_5_IRQHandler(void);
2.5.2.判断哪条线触发了中断
cpp 复制代码
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);

解析:

**参数:**线编号

返回值:

  • 标志位为0,返回RESET
  • 标志位为1,返回SET
cpp 复制代码
//创建EXTI9_5中断服务函数
void EXTI9_5_IRQHandler(void)
{
	/*如果是线5触发的中断*/
	if(EXTI_GetFlagStatus(EXTI_Line5) == SET)
	{
		/*亮灯*/
		GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);
	}
	/*如果是线6触发的中断*/
	if(EXTI_GetFlagStatus(EXTI_Line6) == SET)
	{
		/*灭灯*/
		GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);
	}
}
2.5.3.清除标志位
cpp 复制代码
void EXTI_ClearFlag(uint32_t EXTI_Line);
cpp 复制代码
//创建EXTI9_5中断服务函数
void EXTI9_5_IRQHandler(void)
{
	/*如果是线5触发的中断*/
	if(EXTI_GetFlagStatus(EXTI_Line5) == SET)
	{
		/*清除中断标志位*/
		EXTI_ClearFlag(EXTI_Line5);
		/*亮灯*/
		GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);
	}
	/*如果是线6触发的中断*/
	if(EXTI_GetFlagStatus(EXTI_Line6) == SET)
	{
		/*清除中断标志位*/
		EXTI_ClearFlag(EXTI_Line6);
		/*灭灯*/
		GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);
	}
}

2.6.总代码

cpp 复制代码
#include "stm32f10x.h"

//声明板载LED初始化函数
void App_OnBoardLED_Init(void);
//声明按钮初始化函数
void App_Button_Init(void);
//声明EXTI9_5中断服务函数
void EXTI9_5_IRQHandler(void);
	
int main(void)
{
	/*设置中断优先级分组*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	App_OnBoardLED_Init();
	App_Button_Init();
	while(1)
	{
	}
}

//创建EXTI9_5中断服务函数
void EXTI9_5_IRQHandler(void)
{
	/*如果是线5触发的中断*/
	if(EXTI_GetFlagStatus(EXTI_Line5) == SET)
	{
		/*清除中断标志位*/
		EXTI_ClearFlag(EXTI_Line5);
		/*亮灯*/
		GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);
	}
	/*如果是线6触发的中断*/
	if(EXTI_GetFlagStatus(EXTI_Line6) == SET)
	{
		/*清除中断标志位*/
		EXTI_ClearFlag(EXTI_Line6);
		/*灭灯*/
		GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);
	}
}

//创建板载LED初始化函数
void App_OnBoardLED_Init(void)
{
	/*启动GPIOC时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	/*声明GPIO结构变量*/
	GPIO_InitTypeDef GPIO_InitStruct;
	/*选择PC13引脚*/
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
	/*通用输出开漏模式*/
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
	/*最大输出速率为2MHz*/
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
	/*初始化PC13引脚*/
	GPIO_Init(GPIOC,&GPIO_InitStruct);
	/*熄灭板载LED*/
	GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);
}


//创建按钮初始化函数
void App_Button_Init(void)
{
	//#1:初始化PA5和PA6
	
	/*启动GPIOA时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	/*声明GPIO结构变量*/
	GPIO_InitTypeDef GPIO_InitStruct;
	/*选择PA5引脚*/
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
	/*输入上拉模式*/
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	/*初始化PA5引脚*/
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	/*选择PA6引脚*/
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
	/*输入上拉模式*/
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	/*初始化PA6引脚*/
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	//#2:为EXTI5和EXTI6分配引脚
	
	/*开启AFIO的时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	/*线5选择端口A*/
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource5);
	/*线6选择端口A*/
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource6);
	
	//#3:初始化EXTI的线
	
	/*声明EXTI结构变量*/
	EXTI_InitTypeDef EXTI_InitStruct;
	/*选择EXTI_Line5*/
	EXTI_InitStruct.EXTI_Line = EXTI_Line5;
	/*中断模式*/
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	/*上升沿采集*/
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
	/*闭合开关*/
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	/*初始化Line5*/
	EXTI_Init(&EXTI_InitStruct);
	/*选择EXTI_Line6*/
	EXTI_InitStruct.EXTI_Line = EXTI_Line6;
	/*中断模式*/
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	/*上升沿采集*/
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
	/*闭合开关*/
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	/*初始化Line6*/
	EXTI_Init(&EXTI_InitStruct);
	
	//#4:配置中断
	
	/*声明NVIC结构变量*/
	NVIC_InitTypeDef NVIC_InitStruct;
	/*设置EXTI9_5中断名称*/
	NVIC_InitStruct.NVIC_IRQChannel = EXTI9_5_IRQn;
	/*设置抢占优先级*/
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	/*子优先级*/
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
	/*闭合中断开关*/
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	/*初始化NVIC*/
	NVIC_Init(&NVIC_InitStruct);
}
相关推荐
MAR-Sky2 小时前
ws2812幻彩灯珠使用stc/AI8G1K08控制
单片机·嵌入式硬件
星夜泊客2 小时前
C# 基础:为什么类可以在静态方法中创建自己的实例?
开发语言·经验分享·笔记·unity·c#·游戏引擎
古译汉书2 小时前
部分.exe文件打开但是一直显示界面,点击任务栏持续无反应
开发语言·单片机·嵌入式硬件
im_AMBER3 小时前
Leetcode 111 两数相加
javascript·笔记·学习·算法·leetcode
驭渊的小故事3 小时前
类和对象的笔记3
笔记
恒锐丰小吕3 小时前
屹晶微 EG27517 高速低侧单通道驱动芯片技术解析
嵌入式硬件·硬件工程
四谎真好看3 小时前
JavaWeb学习笔记(Day12)
笔记·学习·学习笔记·javaweb
三佛科技-134163842124 小时前
FT61E13x家族解析(FT61E131/3F/32/33/35)8位AD型MCU之间的区别
单片机·嵌入式硬件·物联网·智能家居·pcb工艺
恒锐丰小吕4 小时前
屹晶微 EG1416 低压高速低侧单通道驱动芯片技术解析
嵌入式硬件·硬件工程