单片机按键功能:单击、双击、长按、三击

/*== ========================/*功能:单击 */ =================================*/

void key_det(void)
{
    if(key_1 == 0) //按下
    {
        if(++key_cnt>6)   //主循环10ms进来一次  作用:按下消抖  
        {
            if(key_flag == 0) //防止重复进入
            {
                key_flag = 1;
                led_1 = ~led_1;   //单击事件
            }
        }
    }
    else    //松开
    {

        if(key_cnt >= 6) key_cnt = 6;
        if(key_cnt != 0) --key_cnt;//防止松开抖动
    
        if(key_cnt == 0)    //防止重复进入
        {
            if(key_flag)
            {
                key_flag = 0;
            }
        }
    }
}

/*=============================/* 单击 双击 */================================*/

void key_det_2(void)
{
    
    if(click_flag)   //单击 
    {
        click_flag = 0;
        led_1 = ~led_1;
    }
    
    if(double_click_flag) //双击 
    {
        double_click_flag = 0;
        led_2 = ~led_2;
    }
    
    if(key_1 == 0)    //按下
    {
        if(++key_cnt_2 > 6)//主循环10ms进来一次 作用:按下消抖   
        {
            key_double_click_cnt = 0;
            if(key_flag_2 == 0)  //防止重复进入
            {
                key_flag_2 = 1;
            }
            else if(key_flag_2_1 == 1)
            {
                key_flag_2_1 = 0;
                double_click_flag = 1;   //300ms以内再次按下就判断为 双击事件
                key_double_flag = 1;    //该标志位置1 为了不触发单击
                key_flag_2 = 0;
            }
        }
    }
    else
    {
        if(key_flag_2)  //防止重复进入
        {
            key_flag_2_1 = 1;
            if(++key_double_click_cnt >= 30) //300ms  双击间隔时间改这里
            {
                key_double_click_cnt = 0;
                if(key_double_flag == 0) 
                {
                    click_flag = 1; //300ms以内没有再次按下按键就判断为 单击事件
                }
                key_flag_2_1 = 0;
                key_double_flag = 0;
                key_flag_2 = 0;
            }
        }    
    }
}

/*=============================/* 单击 长按*/================================*/

void key_det_3(void)
{
    if(key_flag_1)   //单击 亮灭led_1
    {
        key_flag_1 = 0;
        led_1 = ~led_1;
    }
    if(key_long) //长按 亮灭led_2
    {
        key_long = 0;
        led_2 = ~led_2;
    }
    
    if(key_1 == 0)   //按下
    {
        if(++key_cnt > 6) //主循环10ms进来一次 作用:按下消抖  
        {  
            if(key_flag == 0 && key_long_flag == 0) //防止重复进入
            {
                key_flag = 1;
            }
            
            if((++key_cnt_1 > 200) && key_long_flag == 0) //长按时间
            {
                key_cnt_1 = 0;
                key_flag = 0; //防止触发单击
                key_long = 1; //长按事件
                key_long_flag = 1;
            }
        }
    }
    else
    {
        if(key_cnt >= 6) key_cnt = 6;
        if(key_cnt !=0) --key_cnt;
        key_long_flag = 0;
        key_cnt_1 = 0;
        if(key_cnt == 0)
        {
            if(key_flag) //防止重复进入
            {
                key_flag = 0;
                key_flag_1 = 1;  //单击事件
            }
        }
    }
}

以下两种写法:适用于一个按键实现多种功能、简单易懂、移植性高修改性高、可以运用到实际的项目开发

/*===========================/* 单击 双击 长按 */=============================*/

void key_det_1(void)
{

    if(key_flag_1 == 1)  //单击 
    {
        key_flag_1 = 0;
        led_1 = ~led_1;
    }
    else if(key_flag_1 == 2) //双击
    {
        key_flag_1 = 0;
        led_2 = ~led_2;
    }
    else if(key_flag_1 == 3) //长按
    {
        key_flag_1 = 0;
        led_3 = ~led_3;
    }
    
    switch(key_state)
    {
        case 0:
            if(key_1 == 0)                 //按下
            {
                if(++key_cnt_1 > 6)         //主循环10ms进来一次  作用:按下消抖  
                {
                    key_cnt_1 = 0;
                    key_state = 1;
                }
            }
            else
            {
                key_cnt_1 = 0;
            }
        break;
        case 1:
            if(key_1 == 1)                 //松开
            {
                key_cnt_1 = 0;
                key_state = 2;
//                key_flag_1 = 1;             //单击判断不能放这里,不然会触发单击和双击
                return; 
            }
            if(++key_cnt_1 >= 200)         //主循环10ms进来一次 = 2S
            {
                key_cnt_1 = 0;
                key_state = 3;
                key_flag_1 = 2;            //长按事件
                return; 
            }
        break;
        case 2:
            if(key_1 == 0)                //按下
            {
                key_cnt_1 = 0;
                key_state = 3;
                key_flag_1 = 3;             //双击判断
                return; 
            }
            if(++key_cnt_1 >= 40)         // 计时超过400ms判断为单击事件
            {
                key_cnt = 0;
                key_flag_1 = 1;             //单击事件
                key_state = 3;
                return;  
            }
        break;
        case 3:
            if(key_1 == 1)                //松开
            {
                key_state = 0;
            }
        break;
        default:
            key_state = 0;            
    }
    
    key_flag_1 = 0;    
}

/*======================== /* 单击 双击 长按  三击*/   ===========================*/

void key_det_1_1(void)
{

    if(key_flag_1 == 1)  //单击 
    {
        key_flag_1 = 0;
        led_1 = ~led_1;
    }
    else if(key_flag_1 == 2) //双击
    {
        key_flag_1 = 0;
        led_2 = ~led_2;
    }
    else if(key_flag_1 == 3) //长按
    {
        key_flag_1 = 0;
        led_3 = ~led_3;
    }
    else if(key_flag_1 == 4) //三击
    {
        key_flag_1 = 0;
        led_4 = ~led_4;
    }
    
    switch(key_state)
    {
        case 0:
            if(key_1 == 0)               //按下
            {
                if(++key_cnt_1 > 6)     //主循环10ms进来一次  作用:按下消抖  
                {
                    key_cnt_1 = 0;
                    key_state = 1;
                }
            }
            else
            {
                key_cnt_1 = 0;
            }
        break;
        case 1:
            if(key_1 == 1)               //松开
            {
                key_cnt_1 = 0;
                key_state = 2;
//                key_flag_1 = 1;             //单击判断不能放这里,不然会触发单击和双击
                return; 
            }
            if(++key_cnt_1 >= 200)        //主循环10ms进来一次 = 2S
            {
                key_cnt_1 = 0;
                key_state = 5;
                key_flag_1 = 2;            //长按事件
                return; 
            }
        break;
        case 2:
            if(key_1 == 0)                //按下
            {
                key_cnt_1 = 0;
                key_state = 3;
                return;  
            }
            if(++key_cnt_1 >= 40)        // 计时超过400ms判断为单击事件
            {
                key_cnt = 0;
                key_state = 5;
                key_flag_1 = 1;            //单击事件     
                return;  
            }
        break;
        case 3:
            if(key_1 == 1)                 //松开
            {
                key_cnt_1 = 0;
                key_state = 4;
                return;
            }
            if(++key_cnt_1 >= 40)         // 计时超过400ms判断为双击事件
            {
                key_cnt = 0;
                key_state = 5;
                key_flag_1 = 3;            //双击事件    
                return;     
            }
        break;
        case 4:
            if(key_1 == 0)                 //按下
            {
                key_cnt_1 =0;
                key_state = 5;
                key_flag_1 = 4;            //三击事件
                return;
            }
            if(++key_cnt_1 >= 40)         // 计时超过400ms判断为双击事件
            {
                key_cnt = 0;
                key_state = 5;
                key_flag_1 = 3;             //双击事件    
                return;     
            }
        break;
        case 5:
            if(key_1 == 1)                //松开
            {
                key_state = 0;
            }
        break;
        default:
            key_state = 0;            
    }
    
    key_flag_1 = 0;

}

/*=======================================================================*/

以上几种按键的写法是利用上班摸鱼时间整理出来的所以函数和变量的命名比较随意。

希望这篇文章能帮助到各位,如有更好的写法可以互相学习交流一下。

                        

                                                                                                   从事单片机软件开发大半年的小白


版权声明:本文为weixin_48945522原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。