嵌入式C语言高级编程之复杂按键扫描状态机
2019-07-13 08:29 发布
生成海报
通常普通的按键扫描程序,网上一大堆,基于扫描延时防抖等简单的操作,这里要讲的的遇到复杂的按键处理程序,
普通按键扫描:基于 一个按键的短按长按释放
复杂的按键扫描:有组合按键,且按键也有长短按,以及释放
现在如何实现一个按键扫描模块去处理这种按键扫描程序呢?这里用到按键状态机为基础框架。对按键编码能较好的实现复杂按键处理。
一、对按键进行编码具体实现参考如下
//代表按键按下的电平 用来切换不同的电路 一般都如下
#define PRESS 0X00 //低电平表示按下
#define RELEASE 0X01 //搞电平表示未按下
//这里有六个按键,借用六位
#define USER_KEY_ALL_MSK 0x003F
#define USER_KEY1_PORT P1
#define USER_KEY1_PIN BIT0
#define USER_KEY1 P10
#define USER_KEY1_MSK 0x0001
#define USER_KEY1_POS 0
#define USER_KEY2_PORT P1
#define USER_KEY2_PIN BIT1
#define USER_KEY2 P11
#define USER_KEY2_MSK 0x0002
#define USER_KEY2_POS 1
#define USER_KEY3_PORT P1
#define USER_KEY3_PIN BIT2
#define USER_KEY3 P12
#define USER_KEY3_MSK 0x0004
#define USER_KEY3_POS 2
#define USER_KEY4_PORT P1
#define USER_KEY4_PIN BIT3
#define USER_KEY4 P13
#define USER_KEY4_MSK 0x0008
#define USER_KEY4_POS 3
#define USER_KEY5_PORT P1
#define USER_KEY5_PIN BIT4
#define USER_KEY5 P14
#define USER_KEY5_MSK 0x0010
#define USER_KEY5_POS 4
#define USER_KEY6_PORT P4
#define USER_KEY6_PIN BIT2
#define USER_KEY6 P42
#define USER_KEY6_MSK 0x0020
#define USER_KEY6_POS 5
//状态机,一个简单的状态,你可以设计更复杂,短按释放,长按释放,长按不释放、、等各个状态
typedef enum
{
KEY_NULL = 0,
KEY_PRESS,
KEY_LONG_PRESS,
KEY_RELEASE,
}Type_Key_Status;
二、定义实现上部分就可以对按键检测编码了,按键检测,得到按键键值编码。
由于没有找到合适的办法循环处理,让代码更简洁,所以只能每一个按键都检测一次。
uint16_t read_key(void)
{
uint16_t key_value =0;
if(USER_KEY1 == PRESS)
{
key_value |=(0x01<
三、最后也是最重要的一步就是按键状态扫描的实现。
// 定义一个全局的按键状态
Type_Key_Status key_status = KEY_NULL;
void key_scan(void)
{
uint16_t old_key_value = 0,new_key_value =0;
switch(key_status)
{
case KEY_NULL:
old_key_value = read_key();
if(old_key_value == 0) //没按键按下
{
return;
}
delay_ms(50);
new_key_value = read_key();
if(old_key_value == new_key_value)
{
old_key_value = new_key_value; //有键按下,状态跳转
key_short_press_callback(new_key_value) //回调按下处理函数
key_status = KEY_PRESS;
}else
{
key_status = KEY_NULL;
}
break;
case KEY_PRESS:
delay_ms(50);
new_key_value = read_key();
if(old_key_value == new_key_value)
{
old_key_value = new_key_value;
key_long_press_callback(new_key_value); //回调长按下处理
key_status = KEY_LONG_PRESS;
}else
{
key_short_release_callback(new_key_value); //回调短按释放处理
key_status = KEY_RELEASE;
}
break;
case KEY_LONG_PRESS:
delay_ms(50);
new_key_value = read_key();
if(old_key_value == new_key_value)
{
old_key_value = new_key_value;
key_long_long_press_callback(new_key_value); //回调超长按下处理
key_status = KEY_RELEASE; //更具自定义功能状态去跳转
}else
{
key_long_release_callback(new_key_value); //回调长按释放处理
key_status = KEY_RELEASE;
}
break;
case KEY_RELEASE:
release_key_handle();
key_status = KEY_NULL; //释放回到正常检测状态
break;
}
};
四、最后就是在各个按键状态的基础上实现处理函数,这里就可以对编码的那就值进行解析,分别处理,对于按键释放有组合也很好处理。
void key_short_press_handle(uint16_t key_value)
{
switch(key_value & USER_KEY_ALL_MSK)
{
//没有组合键
case USER_KEY1_MSK:
break;
case USER_KEY2_MSK:
break;
case USER_KEY3_MSK:
break;
case USER_KEY4_MSK:
break;
case USER_KEY5_MSK:
break;
case USER_KEY6_MSK:
break;
//组合按键
case USER_KEY1_MSK|USER_KEY2_MSK : break;
...
}
}
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮