在嵌入式开发中经常会用到各种各样形式的按键,矩阵的,独立的,在定时器扫描完成消抖后对按键动作的多样化检测是有必要的,于是自己写了一份分享给大家,直接贴代码。(扫描消抖部分根据自己实际使用添加,推荐使用定时器扫描,PS:只要不是初学者应该都不会使用延时消抖吧)
//h文件
#define KEY_X_T 4 //键阵行
#define KEY_Y_T 5 //键阵列
#define SUM_CON_KEY(x,y) ((KEY_Y_T*(x)+(y))+1)
#define LONG_TIM_NUM 500 //长按检测时间
#define LONG_DLY 50 //长按多次触发间隔时间
#define LONG_ONE_IR 0 //0长按多次触发 1长按单次触发
#define KEY_OLD_NUM 16 //历史序列长度
#define KEY_CON_NUM 8 //需要的组合个数
typedef struct {
uint8_t *key_con;//组合序列
uint8_t key_con_num;//组合序列长度
uint8_t com_num;//当前检查长度
}_devConKey_t;
typedef struct {
uint8_t *key_p_in;
uint8_t key_x_in,key_y_in;
uint8_t key_old[KEY_OLD_NUM];//历史序列,最多记录KEY_OLD_NUM个单击(键值+1)
uint8_t *key_last;//上一次的状态
uint16_t *key_long_tim;
uint8_t *key_long_flag;
uint16_t *key_long_dly;
_devConKey_t key_con[KEY_CON_NUM];//支持KEY_CON_NUM种序列
uint8_t key_con_num;
}_devParaKey_t;
//c文件
_devParaKey_t devParaKey_t={0};
void init_key( void *key_p,uint8_t key_x,uint8_t key_y)
{
if(key_p==NULL){
return;
}
memset(&devParaKey_t,0,sizeof(_devParaKey_t));
devParaKey_t.key_p_in = (uint8_t *)key_p;
devParaKey_t.key_x_in = key_x;
devParaKey_t.key_y_in = key_y;
devParaKey_t.key_last = malloc(key_x*key_y);
devParaKey_t.key_long_tim = malloc(key_x*key_y*2);
devParaKey_t.key_long_flag = malloc(key_x*key_y);
devParaKey_t.key_long_dly = malloc(key_x*key_y*2);
memset(devParaKey_t.key_last,0,key_x*key_y);
memset(devParaKey_t.key_long_tim,0,key_x*key_y*2);
memset(devParaKey_t.key_long_flag,0,key_x*key_y);
memset(devParaKey_t.key_long_dly,LONG_DLY,key_x*key_y*2);
}
void check_key_con( void )
{
uint8_t con_num = 0;
uint8_t i = 0;
for(i=0;i<devParaKey_t.key_con_num;i++){
devParaKey_t.key_con[i].com_num = 0;
}
for(con_num=0;con_num<KEY_OLD_NUM;con_num++){
for(i=0;i<devParaKey_t.key_con_num;i++){
if(con_num<devParaKey_t.key_con[i].key_con_num){
if( devParaKey_t.key_con[i].key_con[devParaKey_t.key_con[i].key_con_num-con_num-1]==devParaKey_t.key_old[KEY_OLD_NUM-1-con_num] ){
devParaKey_t.key_con[i].com_num++;
if(devParaKey_t.key_con[i].com_num==devParaKey_t.key_con[i].key_con_num \
&& devParaKey_t.key_con[i].com_num==(con_num+1) ){
//触发组合按键动作
printf("key_con:%d\r\n",i);
memset(devParaKey_t.key_old,0,KEY_OLD_NUM);
return;
}
}
}
}
}
}
void add_key_con( uint8_t *key_con_add,uint8_t key_con_num )
{
if(devParaKey_t.key_con_num<KEY_CON_NUM){
devParaKey_t.key_con[devParaKey_t.key_con_num].key_con = key_con_add;
devParaKey_t.key_con[devParaKey_t.key_con_num].key_con_num = key_con_num;
devParaKey_t.key_con_num++;
}else{
printf("key_con_num full\r\n");
}
}
//按键扫描完成一次调用一次(我自己使用2ms定时扫描按键后调用)
void check_key( void )
{
uint8_t i,j,key_num = 0;
key_num = devParaKey_t.key_x_in*devParaKey_t.key_y_in;
for(i=0;i<key_num;i++){
//检测长按
if( devParaKey_t.key_p_in[i]==1 ){
if(devParaKey_t.key_long_tim[i]<LONG_TIM_NUM){
devParaKey_t.key_long_tim[i]++;
}
if(devParaKey_t.key_long_tim[i]==LONG_TIM_NUM){
#if(LONG_ONE_IR==1)
devParaKey_t.key_long_tim[i]++;
#endif
if( devParaKey_t.key_long_dly[i]<LONG_DLY ){
devParaKey_t.key_long_dly[i]++;
}else{
devParaKey_t.key_long_dly[i]=0;
devParaKey_t.key_long_flag[i] = 1;
//长按动作(x=i/devParaKey_t.key_y_in,y=i%devParaKey_t.key_y_in,xy从0开始)
printf("long:%d,%d\r\n",i/devParaKey_t.key_y_in,i%devParaKey_t.key_y_in);
}
}
}else{
devParaKey_t.key_long_tim[i]=0;
}
//检测单击
if(devParaKey_t.key_p_in[i]!=devParaKey_t.key_last[i]){
if(devParaKey_t.key_p_in[i]==0){
if(devParaKey_t.key_long_flag[i]==0){
//添加到历史按键序列
for(j=0;j<(KEY_OLD_NUM-1);j++){
devParaKey_t.key_old[j]=devParaKey_t.key_old[j+1];
}
devParaKey_t.key_old[KEY_OLD_NUM-1] = i+1;
//单击动作
//当前单击(x=i/devParaKey_t.key_y_in,y=i%devParaKey_t.key_y_in,xy从0开始)
printf("one:%d,%d\r\n",i/devParaKey_t.key_y_in,i%devParaKey_t.key_y_in);
//检查组合序列
check_key_con();
}else{
devParaKey_t.key_long_flag[i] = 0;
}
}
devParaKey_t.key_last[i] = devParaKey_t.key_p_in[i];
}
}
}
//**************************************************************
//4行5列
//这个状态需要自己添加按键扫描消抖后更新!!!!!
uint8_t ket_t[KEY_X_T][KEY_Y_T]={0};//消抖过后的状态0为弹起,1为按下
uint8_t user_key_con1[4]={SUM_CON_KEY(0,1),SUM_CON_KEY(0,2),SUM_CON_KEY(0,3),SUM_CON_KEY(0,4)};
uint8_t user_key_con2[4]={SUM_CON_KEY(0,4),SUM_CON_KEY(1,2),SUM_CON_KEY(2,3),SUM_CON_KEY(3,4)};
int main()
{
init_key(ket_t,KEY_X_T,KEY_Y_T);//初始化键阵
add_key_con(user_key_con1,sizeof(user_key_con1));//添加组合按键序列
add_key_con(user_key_con2,sizeof(user_key_con2));//添加组合按键序列
//初始化定时器扫面按键
}