STM32独立按键实现单击双击长按功能

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

在使用STM32或其他单片机开发项目时,经常需要用到独立按键进行控制。

通常一个独立按键需要使用一个IO口,如果项目需要按键实现多个功能,往往需要使用到多个按键,需要使用到多个IO口。在IO口资源紧张或不希望使用太多按键时。可以使用以下方法实现一个按键单击,双击,长按返回不同键值的功能,从而减少独立按键的使用。


提示:以下是本篇文章正文内容,下面案例可供参考

一、按键功能定义

这里我将按键按住3秒视为长按操作,两次按下间隔0.5s视为双击,否则为单击

二、使用步骤

1.按键初始化

初始化部分和正常的独立按键使用一样,可以参考正点原子的代码

代码如下(示例):

这里使用的是上拉模式

//按键初始化
void CtrlKey_Init(void) 
{ 
 	GPIO_InitTypeDef GPIO_InitStructure;
 
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能时钟

	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_12;//KEY0
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置为上拉
 	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化IO口

}

2.按键扫描函数(重点)

在key.h中对键值进行宏定义

代码如下(示例):

#define KEY0  GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12)//读取按键

#define KEY0_PRES 	1	//单击
#define LONG_PRES	2	//长按
#define DOUBLE_PRES	3	//双击

在key.c中编写扫描函数,进行按键扫描并返回相应键值

代码如下(示例):

//为了代码不那么乱,这里我定义了一个结构体,不想使用结构体的可以直接定义全局变量
typedef struct {
  u32 u32time1;            //第一次按下后开始计时,主要用于判断长按,放在定时器中自加
  u32 u32time2;            //第一次松手后开始计时,用于判断双击或单击,放在定时器中自加
  u8 u8key_flag;           //第一次按下标志
  u8 u8key_double_flag;    //第二次标志
}Key_Tag;

Key_Tag skey;


u8 KEY_Scan()
{
    static u8 press = 0;
        
    if(KEY0==0)//按键按下
    {
        delay_ms(10);//消抖
        if(KEY0==0)
        { 
            if(skey.u8key_flag==0)
            {
                skey.u8key_flag=1;        //第一次按下,标志位置1。同时计数值归零
                skey.u32time1=0;
            }
            else if(skey.u8key_flag==1)
            {
                if(!press && skey.u32time1 > 3000)//如果第一次按下且时间超过3S,视为长按
                {
                    press = 1;
                    return LONG_PRES;//返回长按键值
                }
            }
        }
    }
    
    else if(KEY0==1)//按键松开
    {
        if(skey.u8key_flag==1)    //第一次按键松开
        {
            skey.u8key_flag=0;
            if(skey.u32time1>3000)//按下后超过3秒才松开,已经返回了键值,松手后把标志位都归零
            {
                press = 0;
                skey.u32time1 = 0;
                skey.u32time2 = 0;
                skey.u8key_flag=0;
                skey.u8key_double_flag=0;
            }
            else if(skey.u8key_double_flag==0)
            {
                skey.u8key_double_flag=1;    //第一次松开之后标志位置1开始等待第二次按键松开
                skey.u32time2=0;            
            }
            else if(skey.u8key_double_flag==1)
            {
                if(skey.u32time2<500)            //如果第二次松开时间间隔小于0.5S,视为双击
                {
                    skey.u8key_double_flag=0;

                    return DOUBLE_PRES;
                }
            }
        }
        else if(skey.u8key_double_flag==1)
        {
            if(skey.u32time2>=500)            
            {
                skey.u8key_double_flag=0;

                return KEY0_PRES;//如果第一次松开之后0.5s没有第二次按键操作,视为短按
            }
        }
    }
    return 0;//没有按键按下返回0
}

3.注意事项

time1和time2两个计时变量要放在定时器中自加,这里就不放出详细代码了。

在main函数中轮询调用按键扫描函数,获得键值之后再根据键值执行相应操作。和平时的按键扫描函数一样用法


总结

这个实现按键单击双击长按的方法比较简单,主要是在按键按下之后记录第一次按下持续时间,若达到我们要的长按标准则视为长按,建议长按时间不小于1秒。第一次按键松手之后记录第二个时间,若在规定间隔时间内有第二次按下并松手则视为双击,若达到规定时间还没第二次按下并松手,则为单击。

小白入行没多久,第一次写博客,可能写得很一般,希望各位大神勿喷。如果有什么错误欢迎指正。

上一篇:JAVA提高十一:LinkedList深入分析


下一篇:剑指offer--正则表达式匹配问题Java解法