金沙滩51单片机按键

独立按键

在这里插入图片描述

独立按键的扫描

#include <reg52.h>

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit LED9 = P0^7;
sbit LED8 = P0^6;
sbit LED7 = P0^5;
sbit LED6 = P0^4;
sbit KEY1 = P2^4;
sbit KEY2 = P2^5;
sbit KEY3 = P2^6;
sbit KEY4 = P2^7;

void main()
{
    
    ENLED = 0;   //选择独立LED进行显示
    ADDR3 = 1;
    ADDR2 = 1;
    ADDR1 = 1;
    ADDR0 = 0;
    P2 = 0xF7;   //P2.3置0,即KeyOut1输出低电平

	while (1)
    {
        //将按键扫描引脚的值传递到LED上
        LED9 = KEY1;  //按下时为0,对应的LED点亮
        LED8 = KEY2;
        LED7 = KEY3;
        LED6 = KEY4;
    }
}

  • 计数值显示到数码管上
#include <reg52.h>

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit KEY1 = P2^4;
sbit KEY2 = P2^5;
sbit KEY3 = P2^6;
sbit KEY4 = P2^7;

unsigned char code LedChar[] = {  //数码管显示字符转换表
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};

void main()
{
    bit backup = 1;  //定义一个位变量,保存前一次扫描的按键值
    unsigned char cnt = 0;  //定义一个计数变量,记录按键按下的次数
    
    ENLED = 0;   //选择数码管DS1进行显示
    ADDR3 = 1;
    ADDR2 = 0;
    ADDR1 = 0;
    ADDR0 = 0;
    P2 = 0xF7;   //P2.3置0,即KeyOut1输出低电平
    P0 = LedChar[cnt];   //显示按键次数初值

	while (1)
    {
        if (KEY4 != backup)   //当前值与前次值不相等说明此时按键有动作
        {
            if (backup == 0)  //如果前次值为0,则说明当前是由0变1,即按键弹起
            {
                cnt++;        //按键次数+1
                if (cnt >= 10)
                {             //只用1个数码管显示,所以加到10就清零重新开始
                    cnt = 0;
                }
                P0 = LedChar[cnt];  //计数值显示到数码管上
            }
            backup = KEY4;   //更新备份为当前值,以备进行下次比较
        }
    }
}

按键消抖

在这里插入图片描述
在绝大多数情况下,我们是用软件即程序来实现消抖的。最简单的消抖原理,就是当检测到按键状态变化后,先等待一个 10ms 左右的延时时间,让抖动消失后再进行一次按键状态检测,如果与刚才检测到的状态相同,就可以确认按键已经稳定的动作了。

#include <reg52.h>

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit KEY1 = P2^4;
sbit KEY2 = P2^5;
sbit KEY3 = P2^6;
sbit KEY4 = P2^7;

unsigned char code LedChar[] = {  //数码管显示字符转换表
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};

void delay();

void main()
{
    bit keybuf = 1;  //按键值暂存,临时保存按键的扫描值
    bit backup = 1;  //按键值备份,保存前一次的扫描值
    unsigned char cnt = 0;  //按键计数,记录按键按下的次数
    
    ENLED = 0;   //选择数码管DS1进行显示
    ADDR3 = 1;
    ADDR2 = 0;
    ADDR1 = 0;
    ADDR0 = 0;
    P2 = 0xF7;   //P2.3置0,即KeyOut1输出低电平
    P0 = LedChar[cnt];   //显示按键次数初值
    
	while (1)
    {
        keybuf = KEY4;            //把当前扫描值暂存
        if (keybuf != backup)     //当前值与前次值不相等说明此时按键有动作
        {
            delay();              //延时大约10ms
            if (keybuf == KEY4)   //判断扫描值有没有发生改变,即按键抖动
            {
                if (backup == 0)  //如果前次值为0,则说明当前是弹起动作
                {
                    cnt++;        //按键次数+1
                    if (cnt >= 10)
                    {             //只用1个数码管显示,所以加到10就清零重新开始
                        cnt = 0;
                    }
                    P0 = LedChar[cnt];  //计数值显示到数码管上
                }
                backup = keybuf;  //更新备份为当前值,以备进行下次比较
            }
        }
    }
}
/* 软件延时函数,延时约10ms */
void delay()
{
    unsigned int i = 1000;
	
    while (i--);
}

优化消抖

在这里插入图片描述
假如左边时间是起始 0 时刻,每经过 2ms 左移一次,每移动一次,判断当前连续的 8 次按键状态是不是全 1 或者全 0,如果是全 1 则判定为弹起,如果是全 0 则判定为按下,如果0 和 1 交错,就认为是抖动,不做任何判定。

#include <reg52.h>

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit KEY1 = P2^4;
sbit KEY2 = P2^5;
sbit KEY3 = P2^6;
sbit KEY4 = P2^7;

unsigned char code LedChar[] = {  //数码管显示字符转换表
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
bit KeySta = 1;  //当前按键状态

void main()
{
    bit backup = 1;  //按键值备份,保存前一次的扫描值
    unsigned char cnt = 0;  //按键计数,记录按键按下的次数
    
    EA = 1;       //使能总中断
    ENLED = 0;    //选择数码管DS1进行显示
    ADDR3 = 1;
    ADDR2 = 0;
    ADDR1 = 0;
    ADDR0 = 0;
    TMOD = 0x01;  //设置T0为模式1
    TH0  = 0xF8;  //为T0赋初值0xF8CD,定时2ms
    TL0  = 0xCD;
    ET0  = 1;     //使能T0中断
    TR0  = 1;     //启动T0
    P2 = 0xF7;    //P2.3置0,即KeyOut1输出低电平
    P0 = LedChar[cnt];   //显示按键次数初值
	
    while (1)
    {
        if (KeySta != backup)  //当前值与前次值不相等说明此时按键有动作
        {
            if (backup == 0)   //如果前次值为0,则说明当前是弹起动作
            {
                cnt++;         //按键次数+1
                if (cnt >= 10)
                {              //只用1个数码管显示,所以加到10就清零重新开始
                    cnt = 0;
                }
                P0 = LedChar[cnt];  //计数值显示到数码管上
            }
            backup = KeySta;   //更新备份为当前值,以备进行下次比较
        }
    }
}
/* T0中断服务函数,用于按键状态的扫描并消抖 */
void InterruptTimer0() interrupt 1
{
    static unsigned char keybuf = 0xFF;  //扫描缓冲区,保存一段时间内的扫描值
    
    TH0 = 0xF8;  //重新加载初值
    TL0 = 0xCD;
    keybuf = (keybuf<<1) | KEY4;  //缓冲区左移一位,并将当前扫描值移入最低位
    if (keybuf == 0x00)
    {   //连续8次扫描值都为0,即16ms内都只检测到按下状态时,可认为按键已按下
        KeySta = 0;
    }
    else if (keybuf == 0xFF)
    {   //连续8次扫描值都为1,即16ms内都只检测到弹起状态时,可认为按键已弹起
        KeySta = 1;
    }
    else
    {}  //其它情况则说明按键状态尚未稳定,则不对KeySta变量值进行更新
}

矩阵按键

在这里插入图片描述
矩阵按键的扫描

#include <reg52.h>

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit KEY_IN_1  = P2^4;
sbit KEY_IN_2  = P2^5;
sbit KEY_IN_3  = P2^6;
sbit KEY_IN_4  = P2^7;
sbit KEY_OUT_1 = P2^3;
sbit KEY_OUT_2 = P2^2;
sbit KEY_OUT_3 = P2^1;
sbit KEY_OUT_4 = P2^0;

unsigned char code LedChar[] = {  //数码管显示字符转换表
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char KeySta[4][4] = {  //全部矩阵按键的当前状态
    {1, 1, 1, 1},  {1, 1, 1, 1},  {1, 1, 1, 1},  {1, 1, 1, 1}
};

void main()
{
    unsigned char i, j;
    unsigned char backup[4][4] = {  //按键值备份,保存前一次的值
        {1, 1, 1, 1},  {1, 1, 1, 1},  {1, 1, 1, 1},  {1, 1, 1, 1}
    };
    
    EA = 1;       //使能总中断
    ENLED = 0;    //选择数码管DS1进行显示
    ADDR3 = 1;
    ADDR2 = 0;
    ADDR1 = 0;
    ADDR0 = 0;
    TMOD = 0x01;  //设置T0为模式1
    TH0  = 0xFC;  //为T0赋初值0xFC67,定时1ms
    TL0  = 0x67;
    ET0  = 1;     //使能T0中断
    TR0  = 1;     //启动T0
    P0 = LedChar[0];   //默认显示0
	
    while (1)
    {
        for (i=0; i<4; i++)  //循环检测4*4的矩阵按键
        {
            for (j=0; j<4; j++)
            {
                if (backup[i][j] != KeySta[i][j])  //检测按键动作
                {
                    if (backup[i][j] != 0)         //按键按下时执行动作
                    {
                        P0 = LedChar[i*4+j];       //将编号显示到数码管
                    }
                    backup[i][j] = KeySta[i][j];   //更新前一次的备份值
                }
            }
        }
    }
}
/* T0中断服务函数,扫描矩阵按键状态并消抖 */
void InterruptTimer0() interrupt 1
{
    unsigned char i;
    static unsigned char keyout = 0;  //矩阵按键扫描输出索引
    static unsigned char keybuf[4][4] = {  //矩阵按键扫描缓冲区
        {0xFF, 0xFF, 0xFF, 0xFF},  {0xFF, 0xFF, 0xFF, 0xFF},
        {0xFF, 0xFF, 0xFF, 0xFF},  {0xFF, 0xFF, 0xFF, 0xFF}
    };
    
    TH0 = 0xFC;  //重新加载初值
    TL0 = 0x67;
    //将一行的4个按键值移入缓冲区
    keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1;
    keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2;
    keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3;
    keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4;
    //消抖后更新按键状态
    for (i=0; i<4; i++)  //每行4个按键,所以循环4次
    {
        if ((keybuf[keyout][i] & 0x0F) == 0x00)
        {   //连续4次扫描值为0,即4*4ms内都是按下状态时,可认为按键已稳定的按下
            KeySta[keyout][i] = 0;
        }
        else if ((keybuf[keyout][i] & 0x0F) == 0x0F)
        {   //连续4次扫描值为1,即4*4ms内都是弹起状态时,可认为按键已稳定的弹起
            KeySta[keyout][i] = 1;
        }
    }
    //执行下一次的扫描输出
    keyout++;                //输出索引递增
    keyout = keyout & 0x03;  //索引值加到4即归零
    switch (keyout)          //根据索引,释放当前输出引脚,拉低下次的输出引脚
    {
        case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0; break;
        case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break;
        case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break;
        case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0; break;
        default: break;
    }
}

猜你喜欢

转载自blog.csdn.net/imxlw00/article/details/88321007