(蓝桥杯)51单片机按键处理

  1. 当按键程序用固定延时的时候,会显的很呆板,并且还很长很长,这样显的程序也臃肿,所以我在网上查了很多按键程序,见到了各种各样的形式,最后只有一种在定时器里扫描按键的这个最合我心意,但代码都杂乱,下面是我自己修改的代码
  2. 这里写图片描述

#define S7 0x0E //按下s7拉低P30,下面同理
#define S6 0x0D
#define S5 0x0B
#define S4 0x07
unsigned char key_one=0;//按一次的标志位
unsigned char key_long=0;//长按的标志位
unsigned char key_scan()//独立按键,扫描函数
{
    static unsigned char key_buf = 0x00;
    static unsigned int  key_time = 0;
    static unsigned char key_one_temp = 0;
    static unsigned char key_temp = 0;
    P3=0x0F;
    if(P3 != 0x0f)
    {
        key_temp = P3;
        if(P3 != key_buf) //用来实现长按功能,如果不需要可以不加else
        {
            key_buf = P3;
            key_one_temp = 1;
        }
        else
        {
            key_time++; //按键时间 = key_time *扫描时间
            if(key_time == 100) //自己设定的时间,规定按键时长为多少
                                //就是长按
                key_long = 1;   //其实长按程序你可以自己发挥,是依具
                                //体情况来实现的   
        }
    }
    else
    {
        if(key_long !=0) //如果添加了长按,这是防止长按和按一次功能重叠
            if(key_one_temp)//这是为了实现按下释放才算按一次,如果想
                //按下就实现功能,可以不需要这功能,直接用key_one替换
                        //上面的key_one_temp
        {
            key_one = 1;
        }
        key_one_temp = 0;
        key_long = 0; 
        key_buf = 0x00;
    }
    return key_temp;
}
//上面的程序我在2ms的扫描里面使用很稳定,但是只是相当于消抖2ms,可能会觉得
//不稳定,这是改进版,同样放在2ms扫描中,最高消抖时间为8ms
unsigned char key_scan()//改进版扫描函数
{
    static unsigned char key_buf = 0x0E;
    static unsigned int  key_time = 0;
    static unsigned char key_one_temp = 0;
    static unsigned char key_temp = 0;
    P3=0x0F;
    if(P3 != 0x0f)
    {
        if(P3 == key_buf) //用来实现长按功能,如果不需要可以不加else
        {
            key_temp = P3;
            key_one_temp = 1;
            key_time++;
            if(key_time > 100) //延时时间=key_time*扫描时间*4 800ms
            {
                key_one_temp=0;//同样是为了防止按一次和长按功能同时出现
                              //这里换成大于是有原因的,是因为长时间按
                              //会一直进来,然后key_one_temp会一直
                              //置1.
                key_long=1;
            }
        }
    }
    else
    {
        if(key_one_temp)
        {
            key_one_temp = 0;
            key_one = 1;
        }
        key_long = 0; 
    }
    key_buf = _crol_(key_buf |0xF0,1);//循环左移 intrins.h里面
    key_buf &= 0x0F;
    if(key_buf == 0x0F)
        key_buf= 0x0E;
    return key_temp;
}
void key_handle(unsigned char val)//按键处理函数
{
    if(key_one)
    {
        key_one=0;
        switch(val)
        {
        case S7://你要处理是事件
            break;
        case S6://你要处理是事件
            break;
        case S5://你要处理是事件
            break;
        case S4://你要处理是事件
            break;
        }
    }
    if(key_long)
    {
        switch(val)
        {
        case S7://你要处理是事件
            break;
        case S6://你要处理是事件
            break;
        case S5://你要处理是事件
            break;
        case S4://你要处理是事件
            break;
        }
    }
}

下面是矩阵的,和上面的大致差不多,只是蓝桥杯上用的stc15转接板,p36是p42,p37是p44,我先以正常的写一遍,然后在写一遍关于蓝桥杯的例程。

#define S7  0x7E  //这是行扫描出来的结果,就是以行一行的拉低,
#define S6  0x7D  //就比如先是让P3=0xFE,然后按下S7 
#define S5  0x7B  //P30 P37都被拉低,就是0x7E
#define S4  0x77
#define S11 0xBE
#define S10 0xBD
#define S9  0xBB
#define S8  0xB7
#define S15 0xDE
#define S14 0xDD
#define S13 0xDB
#define S12 0xD7
#define S19 0xEE
#define S18 0xED
#define S17 0xEB
#define S16 0xE7
unsigned char key_scan()
{
    static unsigned char key_buf = 0;
    static unsigned char key_sca = 0x01;
    static unsigned int  key_time = 0;
    static unsigned char key_one_temp = 0;
    static unsigned char key_temp = 0;
    P3 = (~key_sca);
    if(P3 != (~key_sca))
    {
        key_temp = P3;
        if(P3 == key_buf) 
        {
            key_buf = P3;
            key_one_temp = 1;
        }
        else
        {
            key_time++;
            if(key_time == 100) //按键时间=key_time*扫描时间*4
            {
                key_one_temp=0;
                key_long=1;
            }
        }
    }
    else
    {
        if(key_one_temp)
        {
            key_one_temp = 0;
            key_one = 1;
        }
        key_long = 0; 
        key_buf = 0;
    }
    key_sca <<=1;
    if(key_sca == 0x10)
        key_sca =0x01;
    //也可以直接用 key_sca = _crol_(key_sca,1);

    return key_temp;
}
//然后处理和独立按键是一样的,只不过case语句多一点
//下面就是关于蓝桥杯的处理方法
unsigned cahr key_read()
{
    unsigned char temp = P3&0x3f;//清掉高两位,以便读取P42 P44
    if(P42 == 1)
    {
        temp |= 0x40;
    }
    if(P44 == 1)
    {
        temp |= 0x80;
    }
    return temp;
}

unsigned char key_scan()
{
    static unsigned char key_buf = 0;
    static unsigned char key_sca = 0x01;
    static unsigned int  key_time = 0;
    static unsigned char key_one_temp = 0;
    static unsigned char key_temp = 0;
    P3 = (~key_sca);
    P42 = (~key_sca)>>6;
    P44 = (~key_sca)>>7;
    if(key_read() != (~key_sca))
    {
        key_temp = P3;
        if(key_read() == key_buf) 
        {
            key_buf = P3;
            key_one_temp = 1;
        }
        else
        {
            key_time++;
            if(key_time == 100) //按键时间=key_time*扫描时间*4
            {
                key_one_temp=0;
                key_long=1;
            }
        }
    }
    else
    {
        if(key_one_temp)
        {
            key_one_temp = 0;
            key_one = 1;
        }
        key_long = 0; 
        key_buf = 0;
    }
    key_sca <<=1;
    if(key_sca == 0x10)
        key_sca =0x01;
    //也可以直接用 key_sca = _crol_(key_sca,1);

    return key_temp;
}

很忏愧,没有检验就把代码贴出来了,只是凭自己的思路写代码漏洞还是比较多的,下面是更改后的代码,因为按键扫描的扫描线在变化,就不能想独立按键那样处理了。废话不多说,下面是测验过的代码

unsigned char key_scan()
{
    static unsigned char scan = 0x01;
    static bit key_flag = 0;
    static bit key_one_flag = 0;
    static unsigned int key_time = 0;
    static unsigned char key_dat = 0;
    unsigned char temp;
    static unsigned char scan_time = 0;

    P3 = (~scan)&0x3F;
    P42 = 1;
    P44 = 1;
    temp = key_read();
    if(temp != (~scan))
    {
        key_flag = 1;
        key_one_flag = 1;
        key_dat = temp;

        key_time++; //2ms*4 加一次  1s代表长按键
        if(key_time >= 125)
        {
            key_long = 1;
            key_one_flag = 0;
        }
    }
    else
    {
        if(key_flag)
            scan_time++;
        else
        {
            scan_time=0;
            if(key_one_flag == 1)
            {
                key_one = 1;
                key_one_flag = 0;
            }
            key_time = 0;
            key_long = 0;
        }

        if(scan_time == 3)//如果按键还按着,那么会是key_flag在一次之1.反之就不会代表结束按键。
        {
            key_flag = 0;
            scan_time = 0;
        }
    }

    scan <<= 1;
    if(scan == 0x10)
        scan = 0x01;

    return key_dat;
}

希望对大家有所帮助,如果有什么问题,可以留言,让我们共同解决,如果能和你们交流,是我莫大的荣幸。

猜你喜欢

转载自blog.csdn.net/A_wangc/article/details/80151803