多按键的状态机扫描

基于stm32的hal库实现

要增加按键只需要在GetKEY()中添加相应按键返回,头文件中增加相应宏定义

源文件

#include "key.h"




uint8_t GetKEY(void)
{
    if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_2) == RESET)//读取相应IO口电平
    {
        return KEY1_DOWN;//按键0被按下
    }
    if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_3) == RESET)
    {
        return KEY2_DOWN;//按键1被按下
    }
    if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13) == RESET)
    {
        return KEY3_DOWN;//按键2被按下
    }
    if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_2) == RESET)//读取相应IO口电平
    {
        return KEY1_DOWN;//按键0被按下
    }
    if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_3) == RESET)
    {
        return KEY2_DOWN;//按键1被按下
    }
    if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13) == RESET)
    {
        return KEY3_DOWN;//按键2被按下
    }
    return NO_KEY;
}
/****************************************************************************
* 名    称:uint8_t ReadKeyStatus(void)
* 功    能:按键状态函数
* 入口参数:无
* 出口参数:返回某个按键的状态
* 说    明:移植时候,这个函数不需要做任何修改
* 调用方法:无
****************************************************************************/
uint8_t ReadKeyStatus(void)
{
    static uint8_t KeyState = KEY_UP;//按键状态
    static uint8_t KeyPrev = NO_KEY; //上一次按键值
    static int TimeCount = 0;		 //按键按下计时
    uint8_t KeyPress = NO_KEY;		 //按键值
    uint8_t KeyReturn = KEY_UP;		 //返回按键状态

    KeyPress = GetKEY();//得到被按下的按键

    switch(KeyState)
    {
        //状态0:没有按键按下
    case KEY_UP:
        if(KeyPress != NO_KEY)//有按键按下
        {
            KeyState = KEY_SURE;//转入状态1
            KeyPrev = KeyPress;//记录按键值
        }
        break;
        //状态1:按键按下确认
    case KEY_SURE:
        if(KeyPress == KeyPrev)//确认和上次相同
        {
            KeyState = KEY_DOWN;//转入状态2
            TimeCount = 0;//计数器清零
        }
        else
        {
            KeyState = KEY_UP;//转入状态0
        }
        break;
        //状态2:按键按下
    case KEY_DOWN:
        if(KeyPress != KeyPrev)//按键释放,端口高电平
        {
            KeyState = KEY_UP;//转入状态0
            KeyReturn = KEY_DOWN | KeyPrev;//返回单次按下(或运算可以得到是哪个按键处于什么状态)
        }
        else if((KeyPress == KeyPrev) && (++TimeCount >= 50)) //超过50*10ms没有释放
        {
            KeyState = KEY_LONG;//转入状态3
            TimeCount = 0;//计数器清零
            KeyReturn = KEY_LONG | KeyPrev;//返回连续按下
        }
        break;
        //状态3:按键连续按下
    case KEY_LONG:
        if(KeyPress != KeyPrev)//按键释放,端口高电平
        {
            KeyState = KEY_UP;//转入状态0
            KeyReturn = KEY_UP;
        }
        else if((KeyPress == KeyPrev) && (++TimeCount >= 50)) //超过50*10ms没有释放
        {
            KeyReturn = KEY_LONG | KeyPrev;//返回连续按下
            TimeCount = 0;//计数器清零
        }
        else//在50*10ms内释放
        {
            KeyReturn = KEY_UP;
        }
        break;
    }

    return KeyReturn;
}

头文件

#ifndef _KEY_H
#define _KEY_H

#include "main.h"

#define NO_KEY			0x00
#define KEY1_DOWN		0x01
#define KEY2_DOWN		0x02
#define KEY3_DOWN		0x03
#define KEY4_DOWN		0x04
#define KEY5_DOWN		0x05
#define KEY6_DOWN		0x05

#define KEY_UP			0xA0
#define KEY_SURE		0xB0
#define KEY_DOWN		0xC0
#define KEY_LONG		0xD0

#define KEY1_ONE_DOWN	0xC1
#define KEY2_ONE_DOWN	0xC2
#define KEY3_ONE_DOWN	0xC3
#define KEY4_ONE_DOWN	0xC4
#define KEY5_ONE_DOWN	0xC5
#define KEY6_ONE_DOWN	0xC6

#define KEY1_LONG_DOWN	0xD1
#define KEY2_LONG_DOWN	0xD2
#define KEY3_LONG_DOWN	0xD3
#define KEY4_LONG_DOWN	0xD4
#define KEY5_LONG_DOWN	0xD5
#define KEY6_LONG_DOWN	0xD6


uint8_t GetKEY(void);
uint8_t ReadKeyStatus(void);



#endif

调用实例

if(ReadKeyStatus() == KEY1_ONE_DOWN)
{	
	//do something	
}
  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
好的,下面是一个简单的状态机代码,用于扫描多个独立按键的状态: ``` // 定义按键状态常量 #define KEY_IDLE 0 #define KEY_DOWN 1 #define KEY_UP 2 #define KEY_PRESS 3 // 定义按键结构体 typedef struct { GPIO_TypeDef *port; uint16_t pin; uint8_t state; uint16_t cnt; } KeyTypeDef; // 定义按键数组 KeyTypeDef keys[] = { {GPIOA, GPIO_PIN_0, KEY_IDLE, 0}, {GPIOA, GPIO_PIN_1, KEY_IDLE, 0}, {GPIOA, GPIO_PIN_2, KEY_IDLE, 0}, {GPIOA, GPIO_PIN_3, KEY_IDLE, 0}, }; // 定义按键数量 #define KEY_COUNT (sizeof(keys) / sizeof(keys[0])) // 按键扫描函数 void KeyScan(void) { uint8_t i; for (i = 0; i < KEY_COUNT; i++) { switch (keys[i].state) { case KEY_IDLE: if (HAL_GPIO_ReadPin(keys[i].port, keys[i].pin) == GPIO_PIN_RESET) { keys[i].state = KEY_DOWN; } break; case KEY_DOWN: if (HAL_GPIO_ReadPin(keys[i].port, keys[i].pin) == GPIO_PIN_SET) { keys[i].state = KEY_UP; } else { keys[i].cnt++; if (keys[i].cnt >= 50) { keys[i].state = KEY_PRESS; keys[i].cnt = 0; } } break; case KEY_UP: keys[i].cnt++; if (keys[i].cnt >= 50) { keys[i].state = KEY_IDLE; keys[i].cnt = 0; } break; case KEY_PRESS: break; } } } ``` 以上代码中,按键状态被定义为常量,分别表示按键的空闲状态、按下状态、松开状态和长按状态。按键结构体包含了按键所在的 GPIO 端口、引脚、状态和计数器。按键数组包含了所有的按键信息,按键数量则通过 `KEY_COUNT` 宏定义。 在按键扫描函数中,每个按键都被遍历一遍,根据不同的状态进行不同的操作。例如,当按键处于空闲状态时,如果检测到按键按下,则将状态转换为按下状态;当按键处于按下状态时,如果检测到按键松开,则将状态转换为松开状态,否则计数器 `cnt` 自增,如果计数器超过了一定阈值,则将状态转换为长按状态;当按键处于松开状态时,计数器 `cnt` 自增,如果计数器超过了一定阈值,则将状态转换为空闲状态;当按键处于长按状态时,不进行任何操作。 以上是一个简单的状态机代码,可以用于扫描多个独立按键的状态。需要注意的是,在实际应用中,可能需要根据具体的需求进行一些修改和优化。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值