STM32学习笔记:GPIO外部中断实验

EXTI:GPIO外部中断实验

一、EXTI结构框图

这个框图有两条路,第一条路是外部中断控制器,另外一条是事件控制器。在这一节我们主要关注的是外部中断控制器,也就是上面那条路。

我们从输入线开始沿着这条路来讲一下相关寄存器的配置:

首先是输入线,选择输入线的寄存器是AFIO_EXTICR1(外部中断配置寄存器),通过控制这个寄存器我们就可以选择EXTIx外部中断输入源。

在这里插入图片描述
然后会进入边沿检测电路,通过对EXTI_RTSR(上升沿触发选择寄存器)或者是EXTI_FTSR(下降沿触发选择寄存器)中输入线相应的位置1,就可以允许该输入线上的上升沿或者下降沿触发中断检测电路的输出为1。

再然后就会进入一个“或门”此时我们需要在EXTI_SWIER(软件中断事件寄存器)相应位置1,这里需要注意,这一步主要是为了让EXTI_PR(请求挂起寄存器)相应位自动置1,而不是我们后边再对EXTI_PR(请求挂起寄存器)相应位写1,这个挂起寄存器比较特殊。

最后我们需要配置EXTI_IMR(中断屏蔽寄存器)相应位,开放中断线上的请求,因为最后是一个“与门”只有两条路均为1的时候它另外一端才会输出1,如果你不开放中断线上请求,也就是该位仍然为0,在“与门”输出端将会是0。

框图外的就是NVIC中断控制器的配置,在下一部分会进行详细描述。

二、NVIC(嵌套向量中断控制器)

NVIC两个相关的头文件

core_cm3.h

misc.h

NVIC特性

68个可屏蔽中断通道(不包含16个Cortex™-M3的中断线);
16个可编程的优先等级(使用了4位中断优先级);
低延迟的异常和中断处理;
电源管理控制;
系统控制寄存器的实现;

NVIC编程的参考手册

《 STM32F10xxx Cortex-M3编程手册》

1.NVIC寄存器

typedef struct
{
  __IO uint32_t ISER[8]; /* 中断使能寄存器 */                    
       uint32_t RESERVED0[24];                                   
  __IO uint32_t ICER[8]; /* 中断清除寄存器 */                   
       uint32_t RSERVED1[24];                                    
  __IO uint32_t ISPR[8]; /* 中断使能悬起寄存器 */                    
       uint32_t RESERVED2[24]; /* 中断清除悬起寄存器 */                                  
  __IO uint32_t ICPR[8]; /* 中断有效位寄存器 */                     
       uint32_t RESERVED3[24];                                   
  __IO uint32_t IABR[8]; /* 中断优先级寄存器 8Bit*/                    
       uint32_t RESERVED4[56];                                   
  __IO uint8_t  IP[240]; /* 中断触发寄存器 */                    
       uint32_t RESERVED5[644];                                  
  __O  uint32_t STIR;                         
}  NVIC_Type;

2.中断优先级分组

 ========================================================================================
    NVIC_PriorityGroup   | PreemptionPriority | SubPriority  | Description
  =======================================================================================
   NVIC_PriorityGroup_0  |     0     |     0-15    |   0 bits for pre-emption priority
                         |           |             |   4 bits for subpriority
  ---------------------------------------------------------------------------------------
   NVIC_PriorityGroup_1  |    0-1    |     0-7     |   1 bits for pre-emption priority
                         |           |             |   3 bits for subpriority
  -------------------------------------------------------------------------------------- 
   NVIC_PriorityGroup_2  |    0-3    |     0-3     |   2 bits for pre-emption priority
                         |           |             |   2 bits for subpriority
  --------------------------------------------------------------------------------------- 
   NVIC_PriorityGroup_3  |    0-7    |     0-1     |   3 bits for pre-emption priority
                         |           |             |   1 bits for subpriority
  -------------------------------------------------------------------------------------- 
   NVIC_PriorityGroup_4  |    0-15   |      0      |   4 bits for pre-emption priority
                         |           |             |   0 bits for subpriority             
  =======================================================================================

具体配置优先级在我们固件库编程里面是在NVIC的结构体里面

typedef struct
{
  uint8_t NVIC_IRQChannel; 
    /*!< Specifies the IRQ channel to be enabled or disabled. */
  uint8_t NVIC_IRQChannelPreemptionPriority; 
    /*!< Specifies the pre-emption priority for the IRQ channel*/
  uint8_t NVIC_IRQChannelSubPriority;         
    /*!< Specifies the subpriority level for the IRQ channel specifie*/
  FunctionalState NVIC_IRQChannelCmd;        
    /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannel*/
} NVIC_InitTypeDef;

在EXTI中我们用到NVIC的内容其实不多,一个是使能寄存器一个是优先级寄存器,我们配置NVIC的目的也是,使能中断,一个选择我们外部中断的优先级,我们固件库编程只需要两个函数就能配置完成

NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)//NVIC初始化
NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)//选择分组

三、所使用的函数

1.NVIC初始化函数
  NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)2.NVIC优先级组别选择函数
  NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)3.时钟使能函数
  RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE); //使能GPIOE的时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //使能AFIO的时钟,AFIO用来选择中断输入线
4.引脚初始化函数
  GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)5.EXTI输入线的配置函数
  GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)6.EXTI初始化函数
  EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct)

四、代码编写过程整理

1.中断编程顺序

使能中断请求:
    a.初始化所使用的GPIO
    b.初始化EXTI
配置中断优先级
编写中断服务函数

2.编写EXTI.h头文件

# ifndef __EXTI_H
# define __EXTI_H

void exti_config(void);

# endif

3.编写EXTI.c文件

void exti_config(void)
{
	GPIO_InitTypeDef GPIO_Initstructure;
	EXTI_InitTypeDef EXTI_Initstructure;
	NVIC_InitTypeDef NVIC_Initstructure;
		
	/* 配置中断优先级 */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	NVIC_Initstructure.NVIC_IRQChannel = EXTI3_IRQn;
	NVIC_Initstructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Initstructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_Initstructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_Initstructure);
	
	/* 初始化所使用的GPIO KEY */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE); //时钟使能
	GPIO_Initstructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
	GPIO_Initstructure.GPIO_Pin = GPIO_Pin_3;
	GPIO_Init(GPIOE,&GPIO_Initstructure); //PE3初始化
	
	/* 初始化EXTI */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);
	
	EXTI_Initstructure.EXTI_Line = EXTI_Line3;
	EXTI_Initstructure.EXTI_LineCmd = ENABLE;
	EXTI_Initstructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_Initstructure.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_Init(&EXTI_Initstructure);	
}

这里主要讲一下初始化EXTI部分:

	/* 初始化EXTI */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //使能AFIO的时钟
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3); //控制AFIO寄存器,选择输入线
	
    EXTI_Initstructure.EXTI_Line = EXTI_Line3; 
    /* 这里虽然看起来像是选择输入线,但其实它是确定在EXTI相关寄存器中具体操作的是哪一位
    ,输入线的选择是在AFIO中进行的 */
	EXTI_Initstructure.EXTI_LineCmd = ENABLE;
    /* 中断屏蔽寄存器相应位置1,中断使能 */
	EXTI_Initstructure.EXTI_Mode = EXTI_Mode_Interrupt;
    /* 模式选择 */
	EXTI_Initstructure.EXTI_Trigger = EXTI_Trigger_Falling;
    /* 触发模式选择 */
	EXTI_Init(&EXTI_Initstructure);	

4.中断服务函数

写在stm32f10x_it.h头文件中,也可以直接写在EXTI.h的头文件中:

void EXTI3_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line3) != RESET)
	{
		GPIOB->ODR ^= GPIO_Pin_5;	
	}
	EXTI_ClearITPendingBit(EXTI_Line3); //清除中断标志寄存器
}

这里实现的功能是按一下KEY1可以实现灯从灭到亮或者是从亮到灭,我用的是正点原子的精英版,大家如果使用其他板子只需要将IO口换一下即可。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
STM32F103ZET6是一款功能强大的微控制器,具有多种外围设备和接口。其中,GPIO外部中断是一种非常有用的功能,可以通过该功能实现对外部事件的快速响应。 在STM32F103ZET6中,GPIO外部中断的实现需要以下步骤: 1. 配置GPIO口为输入模式,并使能外部中断。 2. 配置中断触发方式,可以选择上升沿触发、下降沿触发、双边沿触发等方式。 3. 编写中断服务函数,在该函数中实现对外部事件的处理。 以下是一个简单的示例代码,演示如何在STM32F103ZET6上实现GPIO外部中断: //配置GPIO口为输入模式 GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //配置PA0引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //配置为输入模式,上拉 GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA //使能外部中断 NVIC_InitTypeDef NVIC_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //使能AFIO时钟 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); //选择中断线路 EXTI_InitStructure.EXTI_Line = EXTI_Line0; //选择中断线0 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //选择中断模式 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //选择上升沿触发 EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能中断线 EXTI_Init(&EXTI_InitStructure); //初始化中断 //编写中断服务函数 void EXTI0_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line0) != RESET) //判断中断是否发生 { //处理外部事件 //... EXTI_ClearITPendingBit(EXTI_Line0); //清除中断标志位 } } 以上代码演示了如何在PA0引脚上实现上升沿触发的GPIO外部中断,并在中断服务函数中处理外部事件。实际应用中,可以根据需要选择不同的GPIO口和中断触发方式,并编写相应的中断服务函数来实现更加复杂的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ninehuang333

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值