按键扫描(单击、双击、长按)

一、说明

通过按键来读取按下按键信息,可以实现单机、双击和长按的状态

二、硬件电路

1.开机电路设计

三、软件设计

1.按键初始化略过


/**按键通道数以及数据读取*/
#define PIOS_KEY_NUMBERS     2  //通道数量
#define PIOS_KEY_POWER       0	//电源键
#define PIOS_KEY_FUNCTION    1	//多功能按键

//按键更新时各个状态
typedef enum
{
    KEY_STATE_RELEASE = 0,              /**< enum 0 状态--释放按键. */
    KEY_STATE_PRESS,                    /**< enum 1 状态--按下按键. */
    KEY_STATE_PRESS_FILTER,             /**< enum 2 状态--消抖后仍按下. */
    KEY_STATE_HOLD,                     /**< enum 3 状态--长按按键. */
    KEY_STATE_DOUBLE,                   /**< enum 4 状态--双击按键. */
} KeyStateType;

//按键编码动作
typedef enum
{
    KEY_NONE = 0,               /**< enum 0 按键空. */
    KEY_TOGGLE,                 /**< enum 1 按键短按. */
    KEY_HOLD,                   /**< enum 2 按键长按. */
    KEY_DOUBLE,                 /**< enum 3 按键双击. */
} KeyCodeType;


2.读取具体引脚的高低电平数据

/**
  * @brief 读取按键状态
  * @param channal
  * @retval 相对应通道的按键状态
  */
uint8_t PIOS_KEY_GPIO_Read(uint8_t channal)
{
   switch(channal)
   {
       case PIOS_KEY_POWER:
            return (uint8_t)GPIO_ReadInputDataBit(KEY_POWER_GPIO,KEY_POWER_GPIO_PIN);							
       case PIOS_KEY_FUNCTION:
            return (uint8_t)GPIO_ReadInputDataBit(KEY_FUNCTION_GPIO,KEY_FUNCTION_GPIO_PIN);
       default:
            return 0;
   }
}

3.按键状态更新

/*按键值*/
static KeyCodeType key_code[PIOS_KEY_NUMBERS];
static KeyStateType state[PIOS_KEY_NUMBERS];
static uint32_t timeNowMs[PIOS_KEY_NUMBERS] ;

/**
  * @brief 获取当前的时间,返回Ms
  * @param None
  * @retval sys_tick / 10
  */
uint32_t Get_sysTime(void)
{ 
    return sys_tick / 10;
}


/**
  * @brief 按键更新函数
  * @param\[in] channal 传入所要更新的按键序号
  * @retval None
  */
void PIOS_KEY_Update_Key(uint8_t channal)
{
    if (channal >= PIOS_KEY_NUMBERS){
        return;
    }
    switch (state[channal] ){
        case KEY_STATE_RELEASE:
            if (!PIOS_KEY_GPIO_Read(channal)){		//检测按键是否按下
                state[channal] = KEY_STATE_PRESS;
            }
            break;
        case KEY_STATE_PRESS:
            if (!PIOS_KEY_GPIO_Read(channal)){		//再次检测按键是否按下  100ms去抖动
                timeNowMs[channal] = Get_sysTime();
                state[channal] = KEY_STATE_PRESS_FILTER;
            }
            break;
        case KEY_STATE_PRESS_FILTER:
            if (!PIOS_KEY_GPIO_Read(channal)){		//检测消抖后按键是否仍按下
                if (((Get_sysTime()) - timeNowMs[channal] ) > PIOS_KEY_HOLD_TIME){		//按键按下是否超过2秒
                    //长按按键
                    state[channal] = KEY_STATE_HOLD;
                    key_code[channal] = KEY_HOLD;
                }
            }else{
                timeNowMs[channal] = Get_sysTime();
                state[channal] = KEY_STATE_DOUBLE;
            }
            break;
        case KEY_STATE_DOUBLE:
            if (((Get_sysTime()) - timeNowMs[channal] ) > PIOS_KEY_DOUBLE_TIME){
                //释放按键 短按键
                key_code[channal] = KEY_TOGGLE;
                state[channal] = KEY_STATE_HOLD;
            }else{
                //400ms内又按下
                if (!PIOS_KEY_GPIO_Read(channal)){
                    key_code[channal] = KEY_DOUBLE;
                    state[channal] = KEY_STATE_HOLD;
                }
            }
            break;
        case KEY_STATE_HOLD:
            if (PIOS_KEY_GPIO_Read(channal)){		//检测按键释放
                state[channal] = KEY_STATE_RELEASE;
            }
            break;
        default:
            break;
    }
}

4.定时1ms去扫描各按键数据

/**
 * @brief 按键更新函数
 * @param\[in] num 按键个数
 * @retval None
 */
void PIOS_KEY_Update_Keys(void)
{
    uint8_t i = 0;
    for (; i < PIOS_KEY_NUMBERS; ++i){
        PIOS_KEY_Update_Key(i);
    }
}

5.在每次使用完一次之后对按键状态进行清除

/**
 * @brief 清除按键键值
 * @param None
 * @retval None
 */
void PIOS_KEY_Reset(void)
{
    uint8_t i = 0;
    for (; i < PIOS_KEY_NUMBERS; i++){
        key_code[i] = KEY_NONE;
    }
}

/**
 * @brief 获取单个按键键值
 * @param\[in]  channal 按键序号
 * @return 返回键值
 */
KeyCodeType PIOS_KEY_GetKey(uint8_t channal)
{
    return key_code[channal];
}

6.通过不断扫描按键可以达到去识别那个按键按下和按下的状态

/**
	* @brief 按键处理 (在定时器每1ms中断一次中运行)
  * @param None
  * @retval None
  */
void key_handle()
{
    // 长按电源按键进入
    if((PIOS_KEY_GetKey(PIOS_KEY_POWER) == KEY_HOLD)){
        //在此写需要执行的程序


        PIOS_KEY_Reset();//执行完恢复按键状态,防止一直扫描进入
    }
		
    //短按电源按键进入
    if((!PIOS_KEY_GPIO_Read(PIOS_KEY_POWER))  && Get_sysTime() < 2000){
		
        PIOS_KEY_Reset();
    }
    
    //多功能按键-短按进入
    if(PIOS_KEY_GetKey(PIOS_KEY_FUNCTION) == KEY_TOGGLE){ 

		PIOS_KEY_Reset();
    }
		
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32是一种嵌入式微控制器,具有灵活的输入输出引脚。使用STM32可以方便地实现按键的单击双击按功能。 实现按键单击功能的方法是,在程序中通过轮询检测按键引脚的电平状态。当检测到按键引脚的电平从高变低时,就可以认为发生了按键单击事件。在处理事件的代码中可以执行相应的操作,比如控制LED灯亮起或熄灭。 要实现按键的双击功能,可以利用计时器和中断。当按键引脚由高电平变为低电平时,启动计时器,并设置一个适当的时间阈值。在计时器中断中断中,检查按键引脚的电平状态,如果在规定的时间内再次检测到低电平,就可以认为发生了双击事件。在处理双击事件的代码中,可以执行相应的操作,如切换LED灯的状态。 要实现按键的按功能,也可以利用计时器和中断。当按键引脚由高电平变为低电平时,启动计时器,并设置一个较的时间阈值。在计时器中断中,检查按键引脚的电平状态,如果在规定的时间内仍然保持低电平,就可以认为发生了按事件。在处理按事件的代码中,可以执行相应的操作,如控制LED灯持续亮起或熄灭,或者是执行其他功能。 总结来说,通过对STM32的输入输出引脚进行轮询检测,并结合计时器和中断的使用,可以实现按键的单击双击按功能。这种灵活和可编程性是STM32在嵌入式系统中广泛应用的原因之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值