按键扫描,支持单击、长按、组合序列

在嵌入式开发中经常会用到各种各样形式的按键,矩阵的,独立的,在定时器扫描完成消抖后对按键动作的多样化检测是有必要的,于是自己写了一份分享给大家,直接贴代码。(扫描消抖部分根据自己实际使用添加,推荐使用定时器扫描,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));//添加组合按键序列

    //初始化定时器扫面按键

}

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值