STM32F103ZET6【标准库函数开发】------02.2 按键实现短按、长按、双击的效果(非中断方式)

一、硬件介绍

正点原子战舰开发板
在这里插入图片描述
在这里插入图片描述

LED0-----PB5
LED1-----PE5
KEY0-----PA4

二、实现目的

开机LED0、LED1均熄灭
单击KEY0,LED0点亮、LED1熄灭
双击KEY0,LED0熄灭、LED1点亮
长按,LED0,LED1均熄灭

三、设计思路

1、两个LED对应的IO设置为推挽输出,高电平,保证开机时灯处于熄灭状态
2、按键KEY0设置为上拉输入,按下后为低电平,松手为高电平
3、单击、双击、长按的区别示意图如下
在这里插入图片描述
首先需要区分单击和长按,可以看到长按就是按下的时间比较长的单击。如下图可以看到,如果检测到低电平的时间超过S3那么则是长按,否则就是单击。
在这里插入图片描述
单击和双击的区别,松开后,在一定的时间内是否再次检测到低电平。如下图,在松开手后如果在D2内检测到低电平,那么便是双击。否则便是单击。
在这里插入图片描述

单击表现出来的效果为高、低、高。即按下后低电平持续时间小于1s为单击
双击表现形式为高、低、高、低、高,即两次单击,且两次单击之间间隔要小于200ms
长按表现形式为高、低、高。即按下后低电平持续时间长于1s为长按

四、代码简介

主要是五个文件

LED源文件和头文件
led.c

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_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_5);						 //PB.5 输出高
	
	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;	    		 //LED1-->PE.5 端口配置, 推挽输出
	 GPIO_Init(GPIOE, &GPIO_InitStructure);	  				 //推挽输出 ,IO口速度为50MHz
	 GPIO_SetBits(GPIOE,GPIO_Pin_5); 						 //PE.5 输出高 
}

led.h

#define LED0 PBout(5)// PB5
#define LED1 PEout(5)// PE5	
void LED_Init(void);//初始化

KEY源文件和头文件
key.c

//按键初始化函数
void KEY_Init(void) //IO初始化
{ 
 	GPIO_InitTypeDef GPIO_InitStructure; 
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);//使能PORTA,PORTE时钟

	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_4;//KEY0-KEY2
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
 	GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE2,3,4
}

key.h

#define KEY0  GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)//读取按键0
void KEY_Init(void);//IO初始化	

主函数main.c
main.c

 int main(void)
 {
	int a=0,b=0,c=0;
	delay_init();	    	 //延时函数初始化	  
 	LED_Init();			     //LED端口初始化
	KEY_Init();          //初始化与按键连接的硬件接口
	LED0=1;//保证LED0熄灭状态
	LED1=1;//保证LED1熄灭状态
	while(1)
	{		  
		if(KEY0==0) //按键按下
		{
			delay_ms(10);//消抖
			if(KEY0==0) //按键按下
			{
				while((KEY0==0)&&c<100)//10*100=1000ms,即超过1s即为长按
				{
					c++;
					delay_ms(10);
				}
				if(c>=100)//执行长按操作
				{
					LED0=1;//LED0点亮
					LED1=1;//LED1熄灭
					while(KEY0==0);//按键松开
				}
			
				else//执行单击操作
				{
					for(b=0;b<10;b++)//循环检测10*20ms=200ms内是否按键再次按下、即检测双击
					{
						delay_ms(20);
						if(KEY0==0)//如果检测到按键按下,即执行双击命令
						{
							a=1;
							LED0=0;//LED0点亮
							LED1=0;//LED1熄灭	
							while(KEY0==0);//按键松开
						}
					}
					if(a==0)//执行单击操作
					{
							LED0=0;//LED0点亮
							LED1=1;//LED1熄灭						
					}
				}
					a=0;
					c=0;
			}
		}						
	}
}	 

这个是通过扫描和循环的方式进行按键判断,代码参考的洋桃电子,没有用到定时器和中断,代码验证过,可以参考。
通过c的值,来判断操作是单击还是长按;通过a的值,来判断是单击还是双击。
通过改变两个自加次数,来改变双击之间时间间隔以及长按判定等的时间参数。

猜你喜欢

转载自blog.csdn.net/m0_67391870/article/details/124777478