Stm32学习笔记(三) 按键外部中断

目录

一、原理部分

1.1 按键原理

1.2 外部中断

二、工程部分

2.1 按键初始化

2.2 配置KEY引脚为外部中断

2.2.1开启时钟

2.2.2 GPIO_Init和AFIO中断引脚选择

2.2.3  外部中断EXTI初始化(EXTI_Init)

2.2.4 配置NVIC(中断分组NVIC_PriorityGroupConfig以及初始化NVIC_Init)

1.中断分组函数NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)

2.初始化NVIC

2.3 中断函数


通过按键来触发外部中断,然后控制LED灯的亮灭。

一、原理部分

1.1 按键原理

        在STM32F103 上的按键 KEY0 连接在 PE4 上、KEY1 连接在 PE3 上、KEY_UP 连接在 PA0 上,而且可以看到KEY0 和 KEY1 是低电平有效的,而 KEY_UP 是高电平有效的。

        要注意的是这三个按键外部都没有上下拉电阻,这会导致按键在悬空的时候,对应引脚的电压不确定。例如,在KEY0被按下时,引脚被接地,为低电平;但是在KEY0没被按下的时候,引脚悬空会导致电压的值不确定,所以这种情况下,必须设置为上拉输入模式,否则按键的判定会不准确。相反,KEY__UP这种接法就要求设置为下拉输入模式。

1.2 外部中断

下图为EXTI的基本结构

        外部中断EXTI是由中断控制器NVIC控制的,从上图我们可以看到,要想让GPIO连通到NVIC,还需要先经过AFIO和EXTI这两个部分。其中AFIO寄存器的主要功能是选择中断引脚(GPIOA,GPIOB...等等);EXTI用来配置中断的触发方式(上升沿、下降沿、双边沿以及软件触发)和相应中断的方式(中断响应和事件相应);NVIC用来配置中断的优先级(抢占优先级和中断优先级)。

所以开启外部中断的要依次配置好GPIO、AFIO、EXTI和NVIC,这样才能使用外部中断。

对应的程序框图:

二、工程部分

2.1 按键初始化

这里我们使用KEY0和KEY1来分别控制两个LED的亮灭。

配置它们的GPIO和之前LED的GPIO配置类似,先RCC开启对应GPIO时钟,然后GPIO_Init(),不过要记得配置GPIO为输入模式,并且是上拉输入模式。

void KEY_GPIO_Init(void)
{
  //使能KEY引脚对应IO端口时钟
  KEY0_RCC_CLOCKCMD(KEY0_RCC_CLOCKGPIO, ENABLE);
  KEY1_RCC_CLOCKCMD(KEY1_RCC_CLOCKGPIO, ENABLE);

  //定义IO硬件初始化结构体变量
  GPIO_InitTypeDef GPIO_InitStructure;
  
  GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_PIN;  
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  //设置为上拉输入模式
	
  //初始化KEY1对应引脚IO
  GPIO_Init(KEY0_GPIO, &GPIO_InitStructure);
	
  GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_PIN;  
  //初始化KEY1对应引脚IO
  GPIO_Init(KEY1_GPIO, &GPIO_InitStructure);
}

2.2 配置KEY引脚为外部中断

我们上面的代码只是简单地配置了两个按键KEY0和KEY1的GPIO,而我们需要实现通过按键来触发外部中断,因此还要对中断选择器AFIO、EXTI和中断处理器NVIC进行相应的配置。

新建两个"KEY0_EXIT_Config"和"KEY1_EXIT_Config"函数,来为两个按键配置外部中断。

2.2.1开启时钟

第一步还是先开启时钟,不过这次除了开启GPIO的时钟,还要多开启一个中断选择器AFIO,并且因为EXTI和NVIC的时钟是一直打开的,所以我们不用开启它们的时钟。

//启动KEY按键对应的GPIO和AFIO时钟
  KEY0_RCC_CLOCKCMD(KEY0_RCC_CLOCKGPIO | KEY0_RCC_CLOCKAFIO,ENABLE);

其中KEY0_RCC_CLOCKCMD =RCC_APB2PeriphClockCmd,GPIO和AFIO都在总线APB2上。

2.2.2 GPIO_Init和AFIO中断引脚选择

GPIO配置还是使用结构体来配置,而AFIO需要用到GPIO_EXTILineConfig函数:

GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)

其中,GPIO_PortSource是选择的GPIO中断源(GPIOA~GPIOG);

GPIO_PinSource是要配置的外部中断线,可以是GPIO_Pin_0到GPIO _Pin_15 。

两个按键分别对应PE4和PE3,所以GPIO_PortSource为GPIOE,GPIO_PinSource分别为4和3。

  //启动KEY按键对应的GPIO和AFIO时钟
  KEY0_RCC_CLOCKCMD(KEY0_RCC_CLOCKGPIO | KEY0_RCC_CLOCKAFIO,ENABLE);
	
  GPIO_InitTypeDef GPIO_InitStructure;//IO硬件初始化结构体变量
  
  
  NVIC_InitTypeDef NVIC_InitStructure;//嵌套向量中断控制器初始化结构体变量
  
  //启动KEY按键对应的GPIO和AFIO时钟
  KEY0_RCC_CLOCKCMD(KEY0_RCC_CLOCKGPIO | KEY0_RCC_CLOCKAFIO,ENABLE);
  
  GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_PIN;  
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  //上拉输入模式

  GPIO_Init(KEY1_GPIO, &GPIO_InitStructure);//GPIO初始化

  //AFIO配置
  GPIO_EXTILineConfig(KEY0_GPIO_PORTSOURCE,KEY0_GPIO_PINSOURCE);

2.2.3  外部中断EXTI初始化(EXTI_Init)

也是用结构体来初始化EXTI。

对应的结构体EXTI_InitTypeDef:

typedef struct
{
  uint32_t EXTI_Line;               
                                        
  EXTIMode_TypeDef EXTI_Mode;       

  EXTITrigger_TypeDef EXTI_Trigger; 

  FunctionalState EXTI_LineCmd;     
                                         
}EXTI_InitTypeDef;

EXTI_Line,要配置的中断线,KEY0的EXITLINE为EXTI_Line4。

EXTI_Mode,指定外部中断线的模式,选用中断模式EXTI_Mode_Interrupt。

EXTI_Trigger,中断触发方式,选择下降沿触发方式EXTI_Trigger_Falling,因为开关的按下会导致对应的I/O口接地,从而导致电压下降。

EXTI_LineCmd,指定中断线的状态,选为ENABLE。

2.2.4 配置NVIC(中断分组NVIC_PriorityGroupConfig以及初始化NVIC_Init)

1.中断分组函数NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)

NVIC_PriorityGroup中断优先级分组,对应两个中断优先级:

 抢占优先级:是指打断其它中断,会出现嵌套中断;

 子优先级(响应优先级):先处理响应优先级高的中断;

中断不多的情况下,两个优先级的设定比较随意,这里选择NVIC_PriorityGroup_2。

2.初始化NVIC
ypedef struct
{
  uint8_t NVIC_IRQChannel;  
                  
  uint8_t NVIC_IRQChannelPreemptionPriority; 

  uint8_t NVIC_IRQChannelSubPriority;         

  FunctionalState NVIC_IRQChannelCmd;   
     
} NVIC_InitTypeDef;

NVIC_IRQChannel,指定的中断通道,所以除了103系列公用的中断通道可以使用,STM32F103ZET6还有更多的一些中断通道可以使用,可以在"stm32f10x.h"中找到它们。

这里KEY0选择了公有的中断通道EXTI4_IRQn,KEY1选择了公有的中断通道的EXTI3_IRQn。

NVIC_IRQChannelCmd,指定中断通道使能或使能,选使能(ENABLE)。

NVIC_IRQChannelPreemptionPriority,抢占优先级;

NVIC_IRQChannelSubPriority,响应优先级(子优先级)。

我们之前设定的优先级分组为2,可以参照下表来取值。这里选择了设置抢占优先级为2(0x02), 
响应优先级为3(0x03)。

通过以上步骤,我们就完成通过按键触发外部中断的配置了,接下来需要写处理中断的函数。

2.3 中断函数

在之前选择中断通道的时候,KEY0选择的是公有通道EXTI4_IRQn,KEY1选择的是EXTI3_IRQn,它们对应的中断函数分别为 void EXTI4_IRQHandler(void)以及

void EXTI3_IRQHandler(void)。

进入中断函数第一步要先判断是不是我们选择的EXTI_Line4(对应KEY0)进来的。

用EXTI_GetITStatus(EXTI_Line4)来检查,返回值是SET或RESET,如果确实是KEY0触发的外部中断,那么函数就会返回SET,之后我们再翻转LED灯的状态便可实现按键控制LED灯了,最后要记得中断标志位复位。

//外部中断4对应Key0
void EXTI4_IRQHandler(void)
{
	Delay();//消抖
	if(KEY0==0)	 //按键KEY0
	{
		LED1_TOGGLE;
	}		 
	EXTI_ClearITPendingBit(EXTI_Line4);  //清除LINE4上的中断标志位  
}
 

Key1同理。

将代码烧录进去,查看效果。

  • 14
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值