嵌入式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; ... } }