蓝桥杯单片机按键进阶-基于柳离风模板

蓝桥杯单片机按键进阶-基于柳离风模板

——基于柳离风老师模板及按键进阶教程

说明

在使用特殊操作按键(如松手、长按)的过程中可能会触发普通按键,解决方法:1、在按键处理函数中严格控制生效条件,避免误触发,即题目中说的在某个界面下生效,其余界面无效;2、按键处理函数case中不考虑没用的按键返回值;3、改变普通按键检测返回键值代码的位置,把普通按键的触发改到特殊按键的互斥条件中,一般在松手检测处。推荐方法1、2,因为不需要改代码。
在这里插入图片描述

矩阵键盘在进行某些特殊按键操作时要判断具体的键值,因为有多个可能的值,处理操作可以放在得到具体的键值后,也可放在行列扫描的最后一步,本代码使用第二种。
在这里插入图片描述

1、按键测试-按下生效

key.c

#include "key.h"


/**
 * @brief 独立按键扫描函数
 * 
 * @return uchar 键值对应的元件位号
 */
uchar key_scan1(void)
{
    uchar key = 0;                      //按键值
    static bit key_up = 1;              //按键松开标志,1松开0按下
    if((key_up == 1) && (P30 == 0 || P31 == 0 || P32 == 0 || P33 == 0))
    {
        key_up = 0;
        if(P30 == 0)          key = 7;
        else if(P31 == 0)     key = 6;
        else if(P32 == 0)     key = 5;
        else if(P33 == 0)     key = 4;
        return key;
    }
    else if(P30 == 1 && P31 == 1 && P32 == 1 && P33 == 1)
        key_up = 1;
    return 0;
}


/**
 * @brief 矩阵键盘扫描函数
 * 
 * @return uchar 键值对应的元件位号
 */
uchar key_scan2(void)
{
    uchar key = 0;                      //按键值
    static bit key_up = 1;              //按键松开标志,1松开0按下
    P44 = P42 = 1;                      //列扫描
    P32 = P33 = 0;
    if((key_up == 1)&&(P44 == 0 || P42 == 0))
    {
        
        if(P44 == 0)        key = 7;
        else if(P42 == 0)   key = 11;
        else                return 0;
        key_up = 0;                     //标志按下
        P44 = P42 = 0;
        P32 = P33 = 1;                  //行扫描
        if(P32 == 0)   key = key - 2;
        else if(P33 == 0)   key = key - 3;
        return key;
    }
    else if(P44 == 1 && P42 == 1)
        key_up = 1;                     //松开
    return 0;
}


main.c

//按键处理任务
void key_task(void)
{
    uchar key_num;
    if(key_dly<10)return;
    key_dly = 0;
//    key_num = key_scan1();
    key_num = key_scan2();
    switch (key_num)
    {
        /* 独立按键 */
//        case 4:  num++;
//            break;
//        case 5:  num--;
//            break;
//        case 6:  flag_L1 ^= 1;
//            break;
//        case 7:  state_display = (state_display+1)%2;
//            break;
        
        /* 矩阵键盘 */
        case 4:  num++;
            break;
        case 5:  num--;
            break;
        case 8:  flag_L1 ^= 1;
            break;
        case 9:  state_display = (state_display+1)%2;
            break;
    }
}

2、按键进阶-不同界面不同效果

key.c
这里不用改。
main.c

//按键处理任务
void key_task(void)
{
    uchar key_num;
    if(key_dly<10)return;
    key_dly = 0;
//    key_num = key_scan1();
    key_num = key_scan2();
    switch (key_num)
    {
        /* 独立按键 */
//        case 4:  num++;
//            break;
//        case 5:  num--;
//            break;
//        case 6:  flag_L1 ^= 1;
//            break;
//        case 7:  state_display = (state_display+1)%2;
//            break;
        
        /* 矩阵键盘 */
        case 4:  //不同界面不同效果
            if(state_display == 0)
            {
                num++;
            }
            else if(state_display == 1)
            {
                flag_L1 ^= 1;
            }
            //界面很多时用switch
            break;
        case 5:  num--;
            break;
        case 8:  
            break;
        case 9:  state_display = (state_display+1)%2;
            break;
    }
}

3、按键进阶-某模式按键禁用/任意按键生效

key.c
这里不用改。
main.c

//按键处理任务
void key_task(void)
{
    uchar key_num;
    if(key_dly<10)return;
    key_dly = 0;
    
//    if(state_display == 0) return;              //某模式按键禁用
    
//    key_num = key_scan1();
    key_num = key_scan2();
    
    if((key_num > 0) && (state_display == 0))   //某模式任意按键生效
    {
        flag_L1 ^= 1;
        return;
    }
    switch (key_num)
    {
        /* 独立按键 */
//        case 4:  num++;
//            break;
//        case 5:  num--;
//            break;
//        case 6:  flag_L1 ^= 1;
//            break;
//        case 7:  state_display = (state_display+1)%2;
//            break;
        
        /* 矩阵键盘 */
        case 4:  num++;
            break;
        case 5:  num--;
            break;
        case 8:  flag_L1 ^= 1;
            break;
        case 9:  state_display = (state_display+1)%2;
            break;
    }
}

4、按键进阶-松手生效

key.c

#include "key.h"


/**
 * @brief 独立按键扫描函数
 * 
 * @return uchar 键值对应的元件位号
 */
uchar key_scan1(void)
{
    uchar key = 0;                      //按键值
    static bit key_up = 1;              //按键松开标志,1松开0按下
    static bit flag_s4 = 0;             //按键4按下标志
    if((key_up == 1) && (P30 == 0 || P31 == 0 || P32 == 0 || P33 == 0))
    {
        key_up = 0;
        if(P30 == 0)          key = 7;
        else if(P31 == 0)     key = 6;
        else if(P32 == 0)     key = 5;
        else if(P33 == 0)
        {
            flag_s4 = 1;                //标记按下
            key = 4;
        }
        return key;
    }
    else if(P30 == 1 && P31 == 1 && P32 == 1 && P33 == 1)
    {
        key_up = 1;
        if(flag_s4 == 1)
        {
            flag_s4 = 0;
            return 40;                  //松手生效
        }
    }
    return 0;
}


/**
 * @brief 矩阵键盘扫描函数
 * 
 * @return uchar 键值对应的元件位号
 */
uchar key_scan2(void)
{
    uchar key = 0;                      //按键值
    static bit key_up = 1;              //按键松开标志,1松开0按下
    static bit flag_s4 = 0;             //按键4按下标志
    P44 = P42 = 1;                      //列扫描
    P32 = P33 = 0;
    if((key_up == 1)&&(P44 == 0 || P42 == 0))
    {
        
        if(P44 == 0)        key = 7;
        else if(P42 == 0)   key = 11;
        else                return 0;
        key_up = 0;                     //标志按下
        P44 = P42 = 0;
        P32 = P33 = 1;                  //行扫描
        if(P32 == 0)   key = key - 2;
        else if(P33 == 0)
        {
            key = key - 3;
            if(key == 4) flag_s4 = 1;   //标记按下,这里判断键值是因为有两种可能s8,s4
        }
        return key;
    }
    else if(P44 == 1 && P42 == 1)
    {
        key_up = 1;                     //松开
        if(flag_s4 == 1)
        {
            flag_s4 = 0;
            return 40;                  //松手生效
        }
    }
    return 0;
}


main.c

//按键处理任务
void key_task(void)
{
    uchar key_num;
    if(key_dly<10)return;
    key_dly = 0;
//    key_num = key_scan1();
    key_num = key_scan2();
    switch (key_num)
    {
        /* 独立按键 */
//        case 4://按下生效
//            break;
//        case 5:  num--;
//            break;
//        case 6:
//            break;
//        case 7:  flag_L1 ^= 1;
//            break;
//        case 40:num++;    //松手生效
//            break;
        
        /* 矩阵键盘 */
        case 4://按下生效
            break;
        case 5:  num--;
            break;
        case 8:
            break;
        case 9:  flag_L1 ^= 1;
            break;
        case 40:  num++;    //松手生效
            break;
    }
}

5、按键进阶-长按

5-1、长按生效

按下后记录时间,然后判断已按下的时间是否到了。
key.c

#include "key.h"
#include "timer.h"

/**
 * @brief 独立按键扫描函数
 * 
 * @return uchar 键值对应的元件位号
 */
uchar key_scan1(void)
{
    uchar key = 0;                      //按键值
    static bit key_up = 1;              //按键松开标志,1松开0按下
    static bit flag_s4 = 0;             //按键4按下标志
    static unsigned long key_time_s4 = 0;//按键4长按计时
    
    if((key_up == 1) && (P30 == 0 || P31 == 0 || P32 == 0 || P33 == 0))
    {
        key_up = 0;
        if(P30 == 0)          key = 7;
        else if(P31 == 0)     key = 6;
        else if(P32 == 0)     key = 5;
        else if(P33 == 0)               //记录按下
        {
            flag_s4 = 1;
            key_time_s4 = systick_ms;
            key = 4;
        }
        return key;
    }
    else if(P30 == 1 && P31 == 1 && P32 == 1 && P33 == 1)
    {
    	key_up = 1;
        flag_s4 = 0;                    //松手
    }
    
    if((flag_s4 == 1) && ((systick_ms - key_time_s4) > 1000))   //长按1s
    {
        flag_s4 = 0;
        return 40;
    }
    return 0;
}


/**
 * @brief 矩阵键盘扫描函数
 * 
 * @return uchar 键值对应的元件位号
 */
uchar key_scan2(void)
{
    uchar key = 0;                      //按键值
    static bit key_up = 1;              //按键松开标志,1松开0按下
    static bit flag_s4 = 0;             //按键4按下标志
    static unsigned long key_time_s4 = 0;//按键4长按计时
    
    P44 = P42 = 1;                      //列扫描
    P32 = P33 = 0;
    if((key_up == 1)&&(P44 == 0 || P42 == 0))
    {
        
        if(P44 == 0)        key = 7;
        else if(P42 == 0)   key = 11;
        else                return 0;
        key_up = 0;                     //标志按下
        P44 = P42 = 0;
        P32 = P33 = 1;                  //行扫描
        if(P32 == 0)   key = key - 2;
        else if(P33 == 0)
        {
            key = key - 3;
            if(key == 4)                //记录按下
            {
                flag_s4 = 1;
                key_time_s4 = systick_ms;
            }
        }
        return key;
    }
    else if(P44 == 1 && P42 == 1)
    {
    	key_up = 1;                     //松开
        flag_s4 = 0;
    }
    if((flag_s4 == 1) && ((systick_ms - key_time_s4) > 1000))   //长按1s
    {
        flag_s4 = 0;
        return 40;
    }
    return 0;
}


main.c

//按键处理任务
void key_task(void)
{
    uchar key_num;
    if(key_dly<10)return;
    key_dly = 0;
//    key_num = key_scan1();
    key_num = key_scan2();
    switch (key_num)
    {
        /* 独立按键 */
//        case 4:  //num++;
//            break;
//        case 5:  num--;
//            break;
//        case 6:  
//            break;
//        case 7:  state_display = (state_display+1)%2;
//            break;
//        case 40: flag_L1 ^= 1;        //长按生效
//            break;
        /* 矩阵键盘 */
        case 4:  //num++;
            break;
        case 5:  num--;
            break;
        case 8:  
            break;
        case 9:  state_display = (state_display+1)%2;
            break;
        case 40: flag_L1 ^= 1;        //长按生效
            break;
    }
}

5-2、长按一直生效

在生效后不把标志位置0就会一直生效。
key.c

#include "key.h"
#include "timer.h"

/**
 * @brief 独立按键扫描函数
 * 
 * @return uchar 键值对应的元件位号
 */
uchar key_scan1(void)
{
    uchar key = 0;                      //按键值
    static bit key_up = 1;              //按键松开标志,1松开0按下
    static bit flag_s4 = 0;             //按键4按下标志
    static unsigned long key_time_s4 = 0;//按键4长按计时
    
    if((key_up == 1) && (P30 == 0 || P31 == 0 || P32 == 0 || P33 == 0))
    {
        key_up = 0;
        if(P30 == 0)          key = 7;
        else if(P31 == 0)     key = 6;
        else if(P32 == 0)     key = 5;
        else if(P33 == 0)               //记录按下
        {
            flag_s4 = 1;
            key_time_s4 = systick_ms;
            key = 4;
        }
        return key;
    }
    else if(P30 == 1 && P31 == 1 && P32 == 1 && P33 == 1)
    {
    	key_up = 1;
        flag_s4 = 0;                    //松手
    }
    
    if((flag_s4 == 1) && ((systick_ms - key_time_s4) > 1000))   //长按1s
    {
//        flag_s4 = 0;		//这里不置0就一直生效
        return 40;
    }
    return 0;
}


/**
 * @brief 矩阵键盘扫描函数
 * 
 * @return uchar 键值对应的元件位号
 */
uchar key_scan2(void)
{
    uchar key = 0;                      //按键值
    static bit key_up = 1;              //按键松开标志,1松开0按下
    static bit flag_s4 = 0;             //按键4按下标志
    static unsigned long key_time_s4 = 0;//按键4长按计时
    
    P44 = P42 = 1;                      //列扫描
    P32 = P33 = 0;
    if((key_up == 1)&&(P44 == 0 || P42 == 0))
    {
        
        if(P44 == 0)        key = 7;
        else if(P42 == 0)   key = 11;
        else                return 0;
        key_up = 0;                     //标志按下
        P44 = P42 = 0;
        P32 = P33 = 1;                  //行扫描
        if(P32 == 0)   key = key - 2;
        else if(P33 == 0)
        {
            key = key - 3;
            if(key == 4)                //记录按下
            {
                flag_s4 = 1;
                key_time_s4 = systick_ms;
            }
        }
        return key;
    }
    else if(P44 == 1 && P42 == 1)
    {
    	key_up = 1;                     //松开
        flag_s4 = 0;
    }
    if((flag_s4 == 1) && ((systick_ms - key_time_s4) > 1000))   //长按1s
    {
//        flag_s4 = 0;                  //这里不置0就可以一直生效
        return 40;
    }
    return 0;
}


main.c

//按键处理任务
void key_task(void)
{
    uchar key_num;
    if(key_dly<10)return;
    key_dly = 0;
//    key_num = key_scan1();
    key_num = key_scan2();
    switch (key_num)
    {
        /* 独立按键 */
//        case 4:  //num++;
//            break;
//        case 5:  num--;
//            break;
//        case 6:  
//            break;
//        case 7:  state_display = (state_display+1)%2;
//            break;
//        case 40: num = (num+1)%255;        //长按一直生效
//            break;
        /* 矩阵键盘 */
        case 4:  //num++;
            break;
        case 5:  num--;
            break;
        case 8:  
            break;
        case 9:  state_display = (state_display+1)%2;
            break;
        case 40: num = (num+1)%255;        //长按一直生效,如果对速度有要求需要配合定时器
            break;
    }
}

5-3、长按松手生效

把长按检测放在松手检测里。
key.c

#include "key.h"
#include "timer.h"

/**
 * @brief 独立按键扫描函数
 * 
 * @return uchar 键值对应的元件位号
 */
uchar key_scan1(void)
{
    uchar key = 0;                      //按键值
    static bit key_up = 1;              //按键松开标志,1松开0按下
    static bit flag_s4 = 0;             //按键4按下标志
    static unsigned long key_time_s4 = 0;//按键4长按计时
    
    if((key_up == 1) && (P30 == 0 || P31 == 0 || P32 == 0 || P33 == 0))
    {
        key_up = 0;
        if(P30 == 0)          key = 7;
        else if(P31 == 0)     key = 6;
        else if(P32 == 0)     key = 5;
        else if(P33 == 0)               //记录按下
        {
            flag_s4 = 1;
            key_time_s4 = systick_ms;
            key = 4;
        }
        return key;
    }
    else if(P30 == 1 && P31 == 1 && P32 == 1 && P33 == 1)
    {
    	 key_up = 1;
        //把长按放在松手检测里
        if((flag_s4 == 1) && ((systick_ms - key_time_s4) > 1000))   //长按1s以上松手
        {
            flag_s4 = 0;
            return 40;
        }
        else
            flag_s4 = 0;                    //短按松手
    }
    return 0;
}


/**
 * @brief 矩阵键盘扫描函数
 * 
 * @return uchar 键值对应的元件位号
 */
uchar key_scan2(void)
{
    uchar key = 0;                      //按键值
    static bit key_up = 1;              //按键松开标志,1松开0按下
    static bit flag_s4 = 0;             //按键4按下标志
    static unsigned long key_time_s4 = 0;//按键4长按计时
    
    P44 = P42 = 1;                      //列扫描
    P32 = P33 = 0;
    if((key_up == 1)&&(P44 == 0 || P42 == 0))
    {
        
        if(P44 == 0)        key = 7;
        else if(P42 == 0)   key = 11;
        else                return 0;
        key_up = 0;                     //标志按下
        P44 = P42 = 0;
        P32 = P33 = 1;                  //行扫描
        if(P32 == 0)   key = key - 2;
        else if(P33 == 0)
        {
            key = key - 3;
            if(key == 4)                //记录按下
            {
                flag_s4 = 1;
                key_time_s4 = systick_ms;
            }
        }
        return key;
    }
    else if(P44 == 1 && P42 == 1)
    {
    	key_up = 1;                      //松开
        //把长按放在松手检测里
        if((flag_s4 == 1) && ((systick_ms - key_time_s4) > 1000))   //长按1s
        {
            flag_s4 = 0;                  //这里不置0就可以一直生效
            return 40;
        }
        else
            flag_s4 = 0;                 //短按松手
    }
    
    return 0;
}


main.c

//按键处理任务
void key_task(void)
{
    uchar key_num;
    if(key_dly<10)return;
    key_dly = 0;
//    key_num = key_scan1();
    key_num = key_scan2();
    switch (key_num)
    {
        /* 独立按键 */
//        case 4:  //num++;
//            break;
//        case 5:  num--;
//            break;
//        case 6:  
//            break;
//        case 7:  state_display = (state_display+1)%2;
//            break;
//        case 40: flag_L1 ^= 1;        //长按松手生效
//            break;
        /* 矩阵键盘 */
        case 4:  //num++;
            break;
        case 5:  num--;
            break;
        case 8:  
            break;
        case 9:  state_display = (state_display+1)%2;
            break;
        case 40: flag_L1 ^= 1;        //长按松手生效
            break;
    }
}

5-4、长按短按分别松手生效

原来的短按为按下生效,在长按松手检测里加一项时间判断,小于为短按松手生效。
key.c

#include "key.h"
#include "timer.h"

/**
 * @brief 独立按键扫描函数
 * 
 * @return uchar 键值对应的元件位号
 */
uchar key_scan1(void)
{
    uchar key = 0;                      //按键值
    static bit key_up = 1;              //按键松开标志,1松开0按下
    static bit flag_s4 = 0;             //按键4按下标志
    static unsigned long key_time_s4 = 0;//按键4长按计时
    
    if((key_up == 1) && (P30 == 0 || P31 == 0 || P32 == 0 || P33 == 0))
    {
        key_up = 0;
        if(P30 == 0)          key = 7;
        else if(P31 == 0)     key = 6;
        else if(P32 == 0)     key = 5;
        else if(P33 == 0)               //记录按下
        {
            flag_s4 = 1;
            key_time_s4 = systick_ms;
            key = 4;
        }
        return key;
    }
    else if(P30 == 1 && P31 == 1 && P32 == 1 && P33 == 1)
    {
    	key_up = 1;
        //把长按放在松手检测里
        if((flag_s4 == 1) && ((systick_ms - key_time_s4) > 1000))   //长按1s以上松手
        {
            flag_s4 = 0;
            return 40;
        }
        else if((flag_s4 == 1) && ((systick_ms - key_time_s4) < 1000)) //短按松手生效
        {
            flag_s4 = 0;
            return 41;
        }
    }
    return 0;
}


/**
 * @brief 矩阵键盘扫描函数
 * 
 * @return uchar 键值对应的元件位号
 */
uchar key_scan2(void)
{
    uchar key = 0;                      //按键值
    static bit key_up = 1;              //按键松开标志,1松开0按下
    static bit flag_s4 = 0;             //按键4按下标志
    static unsigned long key_time_s4 = 0;//按键4长按计时
    
    P44 = P42 = 1;                      //列扫描
    P32 = P33 = 0;
    if((key_up == 1)&&(P44 == 0 || P42 == 0))
    {
        
        if(P44 == 0)        key = 7;
        else if(P42 == 0)   key = 11;
        else                return 0;
        key_up = 0;                     //标志按下
        P44 = P42 = 0;
        P32 = P33 = 1;                  //行扫描
        if(P32 == 0)   key = key - 2;
        else if(P33 == 0)
        {
            key = key - 3;
            if(key == 4)                //记录按下
            {
                flag_s4 = 1;
                key_time_s4 = systick_ms;
            }
        }
        return key;
    }
    else if(P44 == 1 && P42 == 1)
    {
    	key_up = 1;                      //松开
        //把长按放在松手检测里
        if((flag_s4 == 1) && ((systick_ms - key_time_s4) > 1000))   //长按1s
        {
            flag_s4 = 0;                  //这里不置0就可以一直生效
            return 40;
        }
        else if((flag_s4 == 1) && ((systick_ms - key_time_s4) < 1000))//短按松手生效
        {
            flag_s4 = 0;
            return 41;
        }
    }
    
    return 0;
}


main.c

//按键处理任务
void key_task(void)
{
    uchar key_num;
    if(key_dly<10)return;
    key_dly = 0;
//    key_num = key_scan1();
    key_num = key_scan2();
    switch (key_num)
    {
        /* 独立按键 */
//        case 4:  //num++;//短按按下生效
//            break;
//        case 5:  num--;
//            break;
//        case 6:  
//            break;
//        case 7:  state_display = (state_display+1)%2;
//            break;
//        case 40: flag_L1 ^= 1;        //长按松手生效
//            break;
//        case 41:  num++;              //短按松手生效
//            break;
        /* 矩阵键盘 */
        case 4:  //num++;//短按按下生效
            break;
        case 5:  num--;
            break;
        case 8:  
            break;
        case 9:  state_display = (state_display+1)%2;
            break;
        case 40: flag_L1 ^= 1;        //长按松手生效
            break;
        case 41:  num++;              //短按松手生效
            break;
    }
}

6、按键进阶-按键双击

检测到按键按下后计数加1,并判断两次时间差,小于某个值即为双击。为避免双击单击同时触发,把单击改到松手检测中。
key.c

#include "key.h"
#include "timer.h"

/**
 * @brief 独立按键扫描函数
 * 
 * @return uchar 键值对应的元件位号
 */
uchar key_scan1(void)
{
    uchar key = 0;                      //按键值
    static bit key_up = 1;              //按键松开标志,1松开0按下
    static uchar s4_pres_count = 0;     //按键4按下次数,用于双击
    static unsigned long key_time = 0;  //按键4按下计时
    
    if((key_up == 1) && (P30 == 0 || P31 == 0 || P32 == 0 || P33 == 0))
    {
        key_up = 0;
        if(P30 == 0)          key = 7;
        else if(P31 == 0)     key = 6;
        else if(P32 == 0)     key = 5;
        else if(P33 == 0)
        {
            s4_pres_count++;
            if((s4_pres_count == 2) && ((systick_ms - key_time) <= 500))    //双击s4
            {
                s4_pres_count = 0;
                return 40;
            }
            key_time = systick_ms;      //先判断完双击再计时
//            key = 4;                //如果用这里作为单击,会导致双击过程中触发单击
        }
        return key;
    }
    else if(P30 == 1 && P31 == 1 && P32 == 1 && P33 == 1)
    {
    	key_up = 1;
        if((s4_pres_count == 1) && ((systick_ms - key_time) > 500))    //单击s4松手
        {
            s4_pres_count = 0;
            return 41;
        }
    }
    return 0;
}


/**
 * @brief 矩阵键盘扫描函数
 * 
 * @return uchar 键值对应的元件位号
 */
uchar key_scan2(void)
{
    uchar key = 0;                      //按键值
    static bit key_up = 1;              //按键松开标志,1松开0按下
    static uchar s4_pres_count = 0;     //按键4按下次数,用于双击
    static unsigned long key_time = 0;  //按键4按下计时
    
    P44 = P42 = 1;                      //列扫描
    P32 = P33 = 0;
    if((key_up == 1)&&(P44 == 0 || P42 == 0))
    {
        
        if(P44 == 0)        key = 7;
        else if(P42 == 0)   key = 11;
        else                return 0;
        key_up = 0;                     //标志按下
        P44 = P42 = 0;
        P32 = P33 = 1;                  //行扫描
        if(P32 == 0)   key = key - 2;
        else if(P33 == 0)   key = key - 3;
        
        if(key == 4)                    //s4按下
        {
            s4_pres_count++;
            if((s4_pres_count == 2) && ((systick_ms - key_time) <= 500))    //双击s4
            {
                s4_pres_count = 0;
                return 40;
            }
            key_time = systick_ms;      //先判断完双击再计时
        }
        return key;
    }
    else if(P44 == 1 && P42 == 1)
    {
    	key_up = 1;                     //松开
        if((s4_pres_count == 1) && ((systick_ms - key_time) > 500))    //单击s4松手
        {
            s4_pres_count = 0;
            return 41;
        }
    }
    return 0;
}


main.c

//按键处理任务
void key_task(void)
{
    uchar key_num;
    if(key_dly<10)return;
    key_dly = 0;
//    key_num = key_scan1();
    key_num = key_scan2();
    switch (key_num)
    {
        /* 独立按键 */
//        case 4:  //num++;//单击生效
//            break;
//        case 5:  
//            break;
//        case 6:  
//            break;
//        case 7:  state_display = (state_display+1)%2;
//            break;
//        case 40:  flag_L1 ^= 1;   //双击生效
//            break;
//        case 41:  num++;          //单击松手生效
//            break;
        /* 矩阵键盘 */
        case 4:  //num++;//单击生效
            break;
        case 5:  
            break;
        case 8:  
            break;
        case 9:  state_display = (state_display+1)%2;
            break;
        case 40:  flag_L1 ^= 1;   //双击生效
            break;
        case 41:  num++;          //单击松手生效
            break;
    }
}

7、按键进阶-双按键

双按键要在第一个按键检测到后将key_up置1,才能进行第二次检测,同时注意行列扫描法检测矩阵键盘的弊端,行列扫描的if-else结构会有优先级问题,满足当前if后,后面的都不会再判断了,类似短路,因此当一个按键持续按下时,会阻止检测其他按键,导致双按键需要两个按键按固定的顺序按下才会触发,这不是我们想要的。为避免这种现象,我们需要调整行扫描的优先级,大体思路是:当原先处于优先级靠前的行扫描的那一行如果是第一次按下,则保持原来的优先级不变,如果不是第一次按下(即第一个按键按下没松手,等待第二个按键按下),则把它的优先级放到原先优先级靠后的行扫描后面,优先扫描第二个按键。具体代码如下:

 if(P32 == 0 && flag_s5 == 0)   key = key - 2;   //s5第一次按下
 else if(P33 == 0)   key = key - 3;              //s4按下,这一句一定要放在重复扫描前面,
                                                 //这是因为矩阵键盘行列扫描的局限性,依赖于代码执行顺序,否则s5一直按着后面的没法扫描
 else if(P32 == 0 && flag_s5 == 1) key_up = 1;   //如果s5一直按着就重复扫描,这句一定放在s4扫描之后,优先级最低
                                                 //注意这几句是else if,如果前面的条件满足,后面的就不执行了

或者:

if(P33 == 0 && flag_s8 == 0)        key = key - 3;//第一次按下优先
else if(P32 == 0)   key = key - 2;//比另一个按键第二次按下优先级要高
else if(P33 == 0)   key = key - 3;//非第一次按下优先级靠后

如果两个按键有相同的行或列,可以对双按键检测进行简化,在行扫描前,先检测一下在同一列的两行是否同时按下了,再单独对每行检测,这样可以避免优先级问题,并且简化代码逻辑。

if(P32 == 0 && P33 == 0) //如果双按键有共同的行或列可简化扫描,注意后面跟的是else if
{
    key_up = 0;     //停止扫描
    return 45;      //双按键生效
}

else if(P32 == 0)   key = key - 2;
else if(P33 == 0)   key = key - 3;

if(key == 5)
{
    key_up = 1;         //这里置1才能使第二个按键进入检测
    flag_s5 = 1;        //记录按下
}
if(key == 4)
{
    key_up = 1;         //这里置1才能使第二个按键进入检测
    flag_s4 = 1;        //记录按下
}

key.c

#include "key.h"


/**
 * @brief 独立按键扫描函数
 * 
 * @return uchar 键值对应的元件位号
 */
uchar key_scan1(void)
{
    uchar key = 0;                      //按键值
    static bit key_up = 1;              //按键松开标志,1松开0按下
    static bit flag_s4 = 0;             //按键4按下标志位
    static bit flag_s5 = 0;             //按键4按下标志位
    
    if((key_up == 1) && (P30 == 0 || P31 == 0 || P32 == 0 || P33 == 0))
    {
        key_up = 0;
        if(P30 == 0)          key = 7;
        else if(P31 == 0)     key = 6;
        if(P32 == 0)  //注意这里是if,因为else分支只要满足一个就不再检查其他的了,这样会导致双按键有按下顺序要求
        {
            key_up = 1;         //这里置1才能使第二个按键进入检测
            flag_s5 = 1;        //记录按下
            if(flag_s4 == 1)    //如果另一个按键也按下了
            {
                key_up = 0;     //停止扫描
                flag_s5 = 0;    //
                flag_s4 = 0;
                return 45;      //双按键生效
            }
//            key = 5;          //这里为避免双按键过程中触发单按键,将单按键改为松手触发
        }
        if(P33 == 0)  //注意这里是if,因为else分支只要满足一个就不再检查其他的了,这样会导致双按键有按下顺序要求
        {
            key_up = 1;         //这里置1才能使第二个按键进入检测
            flag_s4 = 1;        //记录按下
            if(flag_s5 == 1)    //如果另一个按键也按下了
            {
                key_up = 0;     //停止扫描
                flag_s5 = 0;    //
                flag_s4 = 0;
                return 45;      //双按键生效
            }
//            key = 4;          //这里为避免双按键过程中触发单按键,将单按键改为松手触发
        }
        return key;
    }
    else if(P30 == 1 && P31 == 1 && P32 == 1 && P33 == 1)
    {
    	key_up = 1;
        if(flag_s4 == 1)    //单按键松手生效
        {
            flag_s4 = 0;
            return 40;
        }
        if(flag_s5 == 1)
        {
            flag_s5 = 0;
            return 50;
        }
    }
    return 0;
}


/**
 * @brief 矩阵键盘扫描函数
 * 
 * @return uchar 键值对应的元件位号
 */
uchar key_scan2(void)
{
    uchar key = 0;                      //按键值
    static bit key_up = 1;              //按键松开标志,1松开0按下
    static bit flag_s4 = 0;             //按键4按下标志位
    static bit flag_s5 = 0;             //按键4按下标志位
    
    P44 = P42 = 1;                      //列扫描
    P32 = P33 = 0;
    if((key_up == 1)&&(P44 == 0 || P42 == 0))
    {
        
        if(P44 == 0)        key = 7;
        else if(P42 == 0)   key = 11;
        else                return 0;
        key_up = 0;                     //标志按下
        P44 = P42 = 0;
        P32 = P33 = 1;                  //行扫描
        
        if(P32 == 0 && flag_s5 == 0)   key = key - 2;   //s5第一次按下
        else if(P33 == 0)   key = key - 3;              //s4按下,这一句一定要放在重复扫描重复扫描前面,
                                                        //这是因为矩阵键盘行列扫描的局限性,依赖于代码执行顺序,否则s5一直按着后面的没法扫描
        else if(P32 == 0 && flag_s5 == 1) key_up = 1;   //如果s5一直按着就重复扫描,这句一定放在s4扫描之后,优先级最低
                                                        //注意这几句是else if,如果前面的条件满足,后面的就不执行了
        
        if(key == 5)
        {
            key_up = 1;         //这里置1才能使第二个按键进入检测
            flag_s5 = 1;        //记录按下
            if(flag_s4 == 1)    //如果另一个按键也按下了
            {
                key_up = 0;     //停止扫描
                flag_s5 = 0;    //
                flag_s4 = 0;
                return 45;      //双按键生效
            }
        }
        if(key == 4)
        {
            key_up = 1;         //这里置1才能使第二个按键进入检测
            flag_s4 = 1;        //记录按下
            if(flag_s5 == 1)    //如果另一个按键也按下了
            {
                key_up = 0;     //停止扫描
                flag_s5 = 0;    //
                flag_s4 = 0;
                return 45;      //双按键生效
            }
        }
        return key;
    }
    else if(P44 == 1 && P42 == 1)
    {
    	key_up = 1;                     //松开
        if(flag_s4 == 1)    //单按键松手生效
        {
            flag_s4 = 0;
            return 40;
        }
        if(flag_s5 == 1)
        {
            flag_s5 = 0;
            return 50;
        }
    }
    return 0;
}


//uchar key_scan2(void)
//{
//    uchar key = 0;                      //按键值
//    static bit key_up = 1;              //按键松开标志,1松开0按下
//    static bit flag_s4 = 0;             //按键4按下标志位
//    static bit flag_s5 = 0;             //按键4按下标志位
//    
//    P44 = P42 = 1;                      //列扫描
//    P32 = P33 = 0;
//    if((key_up == 1)&&(P44 == 0 || P42 == 0))
//    {
//        
//        if(P44 == 0)        key = 7;
//        else if(P42 == 0)   key = 11;
//        else                return 0;
//        key_up = 0;                     //标志按下
//        P44 = P42 = 0;
//        P32 = P33 = 1;                  //行扫描
//        
//        if(P32 == 0 && P33 == 0) //如果双按键有共同的行或列可简化扫描,注意后面跟的是else if
//        {
//            key_up = 0;     //停止扫描
//            return 45;      //双按键生效
//        }
//        
//        else if(P32 == 0)   key = key - 2;
//        else if(P33 == 0)   key = key - 3;
//        
//        if(key == 5)
//        {
//            key_up = 1;         //这里置1才能使第二个按键进入检测
//            flag_s5 = 1;        //记录按下
////            if(flag_s4 == 1)    //如果另一个按键也按下了
////            {
////                key_up = 0;     //停止扫描
////                flag_s5 = 0;    //
////                flag_s4 = 0;
////                return 45;      //双按键生效
////            }
//        }
//        if(key == 4)
//        {
//            key_up = 1;         //这里置1才能使第二个按键进入检测
//            flag_s4 = 1;        //记录按下
////            if(flag_s5 == 1)    //如果另一个按键也按下了
////            {
////                key_up = 0;     //停止扫描
////                flag_s5 = 0;    //
////                flag_s4 = 0;
////                return 45;      //双按键生效
////            }
//        }
//        return key;
//    }
//    else if(P44 == 1 && P42 == 1)
//    {
//		  key_up = 1;                     //松开
//        if(flag_s4 == 1)    //单按键松手生效
//        {
//            flag_s4 = 0;
//            return 40;
//        }
//        if(flag_s5 == 1)
//        {
//            flag_s5 = 0;
//            return 50;
//        }
//        
//    }
//    return 0;
//}


main.c

//按键处理任务
void key_task(void)
{
    uchar key_num;
    if(key_dly<10)return;
    key_dly = 0;
//    key_num = key_scan1();
    key_num = key_scan2();
    switch (key_num)
    {
        /* 独立按键 */
//        case 4:  
//            break;
//        case 5:  
//            break;
//        case 6:  
//            break;
//        case 7:  state_display = (state_display+1)%2;
//            break;
//        case 40:  num++;        //单按s4松手生效
//            break;
//        case 50:  num--;        //单按s5松手生效
//            break;
//        case 45:  flag_L1 ^= 1; //双按键生效
//            break;
        /* 矩阵键盘 */
        case 4:  //单击生效
            break;
        case 5:  //单击生效
            break;
        case 8:  
            break;
        case 9:  state_display = (state_display+1)%2;
            break;
        case 40:  num++;        //单按s4松手生效
            break;
        case 50:  num--;        //单按s5松手生效
            break;
        case 45:  flag_L1 ^= 1; //双按键生效
            break;
    }
}

8、按键进阶-双按键长按生效

key.c

#include "key.h"
#include "timer.h"

/**
 * @brief 独立按键扫描函数
 * 
 * @return uchar 键值对应的元件位号
 */
uchar key_scan1(void)
{
    uchar key = 0;                      //按键值
    static bit key_up = 1;              //按键松开标志,1松开0按下
    static bit flag_s4 = 0;             //按键4按下标志位
    static bit flag_s5 = 0;             //按键4按下标志位
    static unsigned long key_time = 0;  //双按键按下计时
    
    if((key_up == 1) && (P30 == 0 || P31 == 0 || P32 == 0 || P33 == 0))
    {
        key_up = 0;
        if(P30 == 0)          key = 7;
        else if(P31 == 0)     key = 6;
        if(P32 == 0)  //注意这里是if,因为else分支只要满足一个就不再检查其他的了,这样会导致双按键有按下顺序要求
        {
            key_up = 1;         //这里置1才能使第二个按键进入检测
            flag_s5 = 1;        //记录按下
            if(flag_s4 == 1)    //如果另一个按键也按下了
            {
                key_up = 0;     //停止扫描
                key_time = systick_ms;
//                return 45;      //双按键生效
            }
//            key = 5;          //这里为避免双按键过程中触发单按键,将单按键改为松手触发
        }
        if(P33 == 0)  //注意这里是if,因为else分支只要满足一个就不再检查其他的了,这样会导致双按键有按下顺序要求
        {
            key_up = 1;         //这里置1才能使第二个按键进入检测
            flag_s4 = 1;        //记录按下
            if(flag_s5 == 1)    //如果另一个按键也按下了
            {
                key_up = 0;     //停止扫描
                key_time = systick_ms;
//                return 45;      //双按键生效
            }
//            key = 4;          //这里为避免双按键过程中触发单按键,将单按键改为松手触发
        }
        return key;
    }
    else if(P30 == 1 && P31 == 1 && P32 == 1 && P33 == 1)
    {
    	key_up = 1;
        if(flag_s4 == 1)    //单按键松手生效
        {
            flag_s4 = 0;
            return 40;
        }
        if(flag_s5 == 1)
        {
            flag_s5 = 0;
            return 50;
        }
    }
    else if(((systick_ms - key_time) > 2000) && (P33 == 0) && (P32 == 0) && (flag_s4 == 1) && (flag_s5 == 1))//双按键长按生效
    {
        flag_s4 = 0;
        flag_s5 = 0;
        return 45;
    }
    return 0;
}


/**
 * @brief 矩阵键盘扫描函数
 * 
 * @return uchar 键值对应的元件位号
 */
uchar key_scan2(void)
{
    uchar key = 0;                      //按键值
    static bit key_up = 1;              //按键松开标志,1松开0按下
    static bit flag_s4 = 0;             //按键4按下标志位
    static bit flag_s5 = 0;             //按键4按下标志位
    static unsigned long key_time = 0;  //双按键按下计时
    
    P44 = P42 = 1;                      //列扫描
    P32 = P33 = 0;
    if((key_up == 1)&&(P44 == 0 || P42 == 0))
    {
        
        if(P44 == 0)        key = 7;
        else if(P42 == 0)   key = 11;
        else                return 0;
        key_up = 0;                     //标志按下
        P44 = P42 = 0;
        P32 = P33 = 1;                  //行扫描
        
        if(P32 == 0 && flag_s5 == 0)   key = key - 2;   //s5第一次按下
        else if(P33 == 0)   key = key - 3;              //s4按下,这一句一定要放在重复扫描重复扫描前面,
                                                        //这是因为矩阵键盘行列扫描的局限性,依赖于代码执行顺序,否则s5一直按着后面的没法扫描
        else if(P32 == 0 && flag_s5 == 1) key_up = 1;   //如果s5一直按着就重复扫描,这句一定放在s4扫描之后,优先级最低
                                                        //注意这几句是else if,如果前面的条件满足,后面的就不执行了
        
        if(key == 5)
        {
            key_up = 1;         //这里置1才能使第二个按键进入检测
            flag_s5 = 1;        //记录按下
            if(flag_s4 == 1)    //如果另一个按键也按下了
            {
                key_up = 0;     //停止扫描
                key_time = systick_ms;
//                return 45;      //双按键生效
            }
        }
        if(key == 4)
        {
            key_up = 1;         //这里置1才能使第二个按键进入检测
            flag_s4 = 1;        //记录按下
            if(flag_s5 == 1)    //如果另一个按键也按下了
            {
                key_up = 0;     //停止扫描
                key_time = systick_ms;
//                return 45;      //双按键生效
            }
        }
        return key;
    }
    else if(P44 == 1 && P42 == 1)
    {
    	key_up = 1;                     //松开
        if(flag_s4 == 1)    //单按键松手生效
        {
            flag_s4 = 0;
            return 40;
        }
        if(flag_s5 == 1)
        {
            flag_s5 = 0;
            return 50;
        }
    }
    else if(((systick_ms - key_time) > 2000) && (flag_s4 == 1) && (flag_s5 == 1))//双按键长按生效
    {
        flag_s4 = 0;
        flag_s5 = 0;
        return 45;
    }
    return 0;
}


//uchar key_scan2(void)
//{
//    uchar key = 0;                      //按键值
//    static bit key_up = 1;              //按键松开标志,1松开0按下
//    static bit flag_s4 = 0;             //按键4按下标志位
//    static bit flag_s5 = 0;             //按键4按下标志位
//    static unsigned long key_time = 0;  //双按键按下计时
//    
//    P44 = P42 = 1;                      //列扫描
//    P32 = P33 = 0;
//    if((key_up == 1)&&(P44 == 0 || P42 == 0))
//    {
//        
//        if(P44 == 0)        key = 7;
//        else if(P42 == 0)   key = 11;
//        else                return 0;
//        key_up = 0;                     //标志按下
//        P44 = P42 = 0;
//        P32 = P33 = 1;                  //行扫描
//        
//        if(P32 == 0 && P33 == 0) //如果双按键有共同的行或列可简化扫描,注意后面跟的是else if
//        {
//            key_up = 0;     //停止扫描
//            flag_s5 = 1;    //
//            flag_s4 = 1;
//            key_time = systick_ms;
////            return 45;      //双按键生效
//        }
//        
//        else if(P32 == 0)   key = key - 2;
//        else if(P33 == 0)   key = key - 3;
//        
//        if(key == 5)
//        {
//            key_up = 1;         //这里置1才能使第二个按键进入检测
//            flag_s5 = 1;        //记录按下
////            if(flag_s4 == 1)    //如果另一个按键也按下了
////            {
////                key_up = 0;     //停止扫描
////                flag_s5 = 0;    //
////                flag_s4 = 0;
////                return 45;      //双按键生效
////            }
//        }
//        if(key == 4)
//        {
//            key_up = 1;         //这里置1才能使第二个按键进入检测
//            flag_s4 = 1;        //记录按下
////            if(flag_s5 == 1)    //如果另一个按键也按下了
////            {
////                key_up = 0;     //停止扫描
////                flag_s5 = 0;    //
////                flag_s4 = 0;
////                return 45;      //双按键生效
////            }
//        }
//        return key;
//    }
//    else if(P44 == 1 && P42 == 1)
//    {
//        key_up = 1;                     //松开
//        if(flag_s4 == 1)    //单按键松手生效
//        {
//            flag_s4 = 0;
//            return 40;
//        }
//        if(flag_s5 == 1)
//        {
//            flag_s5 = 0;
//            return 50;
//        }
//        
//    }
//    else if(((systick_ms - key_time) > 2000) && (flag_s4 == 1) && (flag_s5 == 1))//双按键长按生效
//    {
//        flag_s4 = 0;
//        flag_s5 = 0;
//        return 45;
//    }
//    return 0;
//}


main.c

//按键处理任务
void key_task(void)
{
    uchar key_num;
    if(key_dly<10)return;
    key_dly = 0;
//    key_num = key_scan1();
    key_num = key_scan2();
    switch (key_num)
    {
        /* 独立按键 */
//        case 4:  
//            break;
//        case 5:  
//            break;
//        case 6:  
//            break;
//        case 7:  state_display = (state_display+1)%2;
//            break;
//        case 40:  num++;        //单按s4松手生效
//            break;
//        case 50:  num--;        //单按s5松手生效
//            break;
//        case 45:  flag_L1 ^= 1; //双按键长按生效
//            break;
        /* 矩阵键盘 */
        case 4:  //单击生效
            break;
        case 5:  //单击生效
            break;
        case 8:  
            break;
        case 9:  state_display = (state_display+1)%2;
            break;
        case 40:  num++;        //单按s4松手生效
            break;
        case 50:  num--;        //单按s5松手生效
            break;
        case 45:  flag_L1 ^= 1; //双按键长按生效
            break;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值