STM32F103ZET6【标准库函数开发】------按键扫描和外部中断的优先级对比

1、打开正点原子的库函数源码可以看到关于按键的程序有两个,一个是按键输入实验,一个是外部中断实验。从最后体现的效果来看,这两个似乎是一样的,那么如果按键输入和外部中断冲突了,那么哪个优先级比较高呢,今天就来试试
在这里插入图片描述
2、首先还是简单介绍,硬件用的是野火的STM32F103ZET6开发板,软件框架用的是正点原子的。首先单独实现按键输入和外部中断来切换控制LED的亮灭状态。
首先打开原理图,可以看到按键SW2接到PA0,接了下拉电阻到GND,所以这个IO应该配置为下拉输入。
在这里插入图片描述
然后三个led分别接到了PB0、PB1、PB5,低电平点亮,高电平熄灭。
在这里插入图片描述

3、用按键扫描的方式点亮led
先初始化led

#include "led.h"
//初始化PB5和PE5为输出口.并使能这两个口的时钟		    
//LED IO初始化
void LED_Init(void)
{
		GPIO_InitTypeDef  GPIO_InitStructure;
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);	 //使能PB,PE端口时钟

		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_5;				 //LED0-->PB.5 端口配置
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
		GPIO_Init(GPIOB, &GPIO_InitStructure);					 //根据设定参数初始化GPIOB.5
		GPIO_SetBits(GPIOB,GPIO_Pin_0);						 //PB.5 输出高	
		GPIO_SetBits(GPIOB,GPIO_Pin_1);						 //PB.5 输出高	
		GPIO_SetBits(GPIOB,GPIO_Pin_5);						 //PB.5 输出高
}

再初始化按键和编写按键扫描函数

#include "stm32f10x.h"
#include "key.h"
#include "sys.h" 
#include "delay.h"
								    
//按键初始化函数
void KEY_Init(void) //IO初始化
{ 
 	GPIO_InitTypeDef GPIO_InitStructure;
 
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能PORTA,PORTE时钟
	
	//初始化 WK_UP-->GPIOA.0	  下拉输入
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0设置成输入,默认下拉	  
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.0

}
//按键处理函数
//返回按键值
//mode:0,不支持连续按;1,支持连续按;
//0,没有任何按键按下
//1,KEY3按下 WK_UP
//注意此函数有响应优先级,KEY0>KEY1>KEY2>KEY3!!
u8 KEY_Scan(u8 mode)
{	 
	static u8 key_up=1;//按键按松开标志
	if(mode)key_up=1;  //支持连按		  
	if(key_up&&(WK_UP==1))
	{
		delay_ms(10);//去抖动 
		key_up=0;
		if(WK_UP==1)return WKUP_PRES;
	}else if(WK_UP==0)key_up=1; 	    
 	return 0;// 无按键按下
}

编写主函数,效果很简单,开机三个led不亮,按下SW2,三个led均点亮。

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "exti.h"
 int main(void)
 {
 	vu8 key=0;	
	delay_init();	    	 //延时函数初始化	  
 	LED_Init();			     //LED端口初始化
	KEY_Init();          //初始化与按键连接的硬件接口
	LED0=1;
	LED1=1;	 
	LED2=1;	 
	while(1)
	{
		key=KEY_Scan(0);	//得到键值
		if(key==1)
		{
			LED0=0;
			LED1=0;	 
			LED2=0;
		}
	}	 
}

在这里插入图片描述
/**********************************************************/
4、用外部中断的方式点亮led
先初始化led,同上

#include "led.h"
//初始化PB5和PE5为输出口.并使能这两个口的时钟		    
//LED IO初始化
void LED_Init(void)
{
		GPIO_InitTypeDef  GPIO_InitStructure;
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);	 //使能PB,PE端口时钟

		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_5;				 //LED0-->PB.5 端口配置
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
		GPIO_Init(GPIOB, &GPIO_InitStructure);					 //根据设定参数初始化GPIOB.5
		GPIO_SetBits(GPIOB,GPIO_Pin_0);						 //PB.5 输出高	
		GPIO_SetBits(GPIOB,GPIO_Pin_1);						 //PB.5 输出高	
		GPIO_SetBits(GPIOB,GPIO_Pin_5);						 //PB.5 输出高
}

中断配置和中断服务函数

#include "exti.h"
#include "led.h"
#include "key.h"
#include "delay.h"
#include "usart.h"
#include "beep.h"
void EXTIX_Init(void)
{ 
		EXTI_InitTypeDef EXTI_InitStructure;
		NVIC_InitTypeDef NVIC_InitStructure;

    KEY_Init();	 //	按键端口初始化
  	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);	//使能复用功能时钟
	
   //GPIOA.0	  中断线以及中断初始化配置 上升沿触发 PA0  WK_UP
 	  GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); 
  	EXTI_InitStructure.EXTI_Line=EXTI_Line0;
		EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
  	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
		EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  	EXTI_Init(&EXTI_InitStructure);		//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器

  	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;			//使能按键WK_UP所在的外部中断通道
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2, 
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;					//子优先级3
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//使能外部中断通道
  	NVIC_Init(&NVIC_InitStructure);  
}

//外部中断0服务程序 
void EXTI0_IRQHandler(void)
{
	delay_ms(10);//消抖
	if(WK_UP==1)	 	 //WK_UP按键
	{	
		LED0=0;
		LED1=0;	 
		LED2=0;	
	}
	EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE0上的中断标志位  
}

编写主函数,可以看到,除了函数的初始化,while()循环里面什么都没有,因为只要有中断触发,就会执行中断服务函数里面的指令。实现的效果和上面一样,开机三个led都熄灭,按下SW2,三个led都点亮。

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "exti.h"
 int main(void)
 {	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	delay_init();	    	 //延时函数初始化	  
 	LED_Init();			     //LED端口初始化
	EXTIX_Init();	 
	LED0=1;
	LED1=1;	 
	LED2=1;	 
	while(1)
	{
		
	}	 
}

/**********************************************************/
5、在上面的基础上,我用按键扫描的方式点亮led,然后用外部中断来熄灭led,那么会出现什么情况呢?首先肯定还是先初始化led,代码就不再重复。所有代码都和外部中断点亮led的一样,除了main函数有区别,代码如下

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "exti.h"
extern int a;
 int main(void)
 {
 	vu8 key=0;	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	delay_init();	    	 //延时函数初始化	  
 	LED_Init();			     //LED端口初始化
	KEY_Init();          //初始化与按键连接的硬件接口
	EXTIX_Init();	 
	LED0=1;
	LED1=1;	 
	LED2=1;	 
	while(1)
	{
		key=KEY_Scan(0);	//得到键值
		if(key==1)
		{
		LED0=1;
		LED1=1;
		LED2=1;
		}
	}	 
}

可以看到,外部中断服务函数里面是将三个led都点亮。在主函数的while()里面是SW2按下,三个led都熄灭。实际效果是开机三个led都熄灭,按下SW2,三个led会闪一下,然后保持熄灭状态。分析原因在按下的一瞬间,触发了外部中断,所以led会熄灭,但是后续就进入了按键扫描函数,于是三个led保持熄灭状态。
回到标题的问题,按键扫描和外部中断的优先级哪个高。单纯从我这个代码而言,外部中断的优先级比按键扫描高,但是从实际效果而言,中断是一瞬间,一闪而过,而按键扫描是持续且长久的。通过这个也可以方便理解为什么说按键扫描比较耗费单片机资源,从此可见一斑。
百度云代码链接:
链接:https://pan.baidu.com/s/1IqjNq29yYTuU1TQjY9hV1g
提取码:2iwu

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
好的,针对您的问题,以下是一种基于STM32的独立按键扫描的实现方法: 1. 首先,将需要扫描的按键引脚连接到STM32的GPIO端口上。 2. 在初始化时,将相应的GPIO端口配置为输入模式,并设置上拉或下拉电阻。 3. 在程序中,通过读取GPIO端口的状态来检测按键是否被按下。可以使用HAL库提供的函数来读取GPIO端口的状态,如HAL_GPIO_ReadPin()。 4. 为了避免按键的抖动,需要进行软件消抖处理。一种简单的方法是在检测到按键状态改变时,延时一段时间再进行状态读取,如果状态仍然改变,则认为按键确实被按下。可以使用HAL库提供的延时函数来实现延时。 5. 可以在主循环中不断进行按键扫描,如果检测到按键被按下,则执行相应的操作。 下面是一个简单的代码示例,仅供参考: ```c #include "stm32f4xx_hal.h" #define KEY1_GPIO_PIN GPIO_PIN_0 #define KEY1_GPIO_PORT GPIOA int main(void) { HAL_Init(); // 配置KEY1引脚为输入模式,上拉电阻 GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = KEY1_GPIO_PIN; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStruct); while (1) { // 延时消抖 HAL_Delay(10); if (HAL_GPIO_ReadPin(KEY1_GPIO_PORT, KEY1_GPIO_PIN) == GPIO_PIN_RESET) { // KEY1被按下 // 执行相应操作 } } } ``` 希望上述内容能够对您有所帮助!如果您还有其他问题,欢迎随时提出。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值