欢迎光临散文网 会员登陆 & 注册

第8章-函数进阶与按键(上:跟堂作业)

2023-08-26 09:41 作者:feifeiluan2  | 我要投稿

这节太难了,2个多小时分成

由于代码量大,把跟堂作业也搬过来了

课上例子,单键中断消抖读取

#include <reg52.h>

typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long ulong;

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;

// 数码管code
uchar code LedChar[] =
{
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};

bit KeySta=1;//中断读取按键后放到这儿

void main(void)
{
    uchar cnt = 0;
    bit backup = 1;
    bit keybuf = 1;

    ENLED = 0;
    ADDR3 = 1;
    ADDR2 = 0;
    ADDR1 = 0;
    ADDR0 = 0;

    TMOD=0x01;
    TH0=0xF8;
    TL0=0xCD;
    ET0=EA=TR0=1;

    P2 = 0xF7;
    P0 = LedChar[cnt];

    while (1)
    {
        if(KeySta != backup)
        {
            if(backup==0)
            {
                //松开
                cnt++;
                if(cnt>=10)
                {
                    cnt=0;
                }
                P0=LedChar[cnt];
            }
            else
            {
                //按下
            }
            backup=KeySta;//保存方便,下次比对
        }
    }
}

void Timer0_ISR(void)interrupt 1
{
    static uchar keybuf=0xFF;

    TH0=0xF8;
    TL0=0xCD;

    keybuf=(keybuf<<1)|KEY4;//读取按键状态,累计到这个类似FIFO变量里面

    if(keybuf==0)
    {
        //按下
        KeySta=0;
    }
    else if(keybuf==0xFF)
    {
        //松开
        KeySta=1;
    }
    else
    {
        //抖动
    }

}

课上例子,矩阵按键中断消抖读取
#include <reg52.h>

typedef unsigned char u8;
typedef unsigned int  u16;
typedef unsigned long u32;
typedef signed char i8;
typedef signed int  i16;
typedef signed long i32;

sbit ADDR0 = P1 ^ 0;
sbit ADDR1 = P1 ^ 1;
sbit ADDR2 = P1 ^ 2;
sbit ADDR3 = P1 ^ 3;
sbit ENLED = P1 ^ 4;

//4个列,要读取
sbit KEYIN1=P2^4;
sbit KEYIN2=P2^5;
sbit KEYIN3=P2^6;
sbit KEYIN4=P2^7;

//4个行,要拉低
sbit KEYOUT1=P2^3;
sbit KEYOUT2=P2^2;
sbit KEYOUT3=P2^1;
sbit KEYOUT4=P2^0;

//保存中断消抖后,读取按键状态
u8 KeySta[4][4]=
{
    {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}
};

// 数码管code
u8 code LedChar[] =
{
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};

void main(void)
{
    //保存上一次按键的状态
    u8 backup[4][4]=
    {
        {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}
    };

    u8 i,j,cnt;

    ENLED = 0;
    ADDR3 = 1;
    ADDR2 = 0;
    ADDR1 = 0;
    ADDR0 = 0;

    TMOD=0x01;
    TH0=0xF8;
    TL0=0xCD;
    ET0=EA=TR0=1;

    P0 = LedChar[cnt];

    while (1)
    {
        //扫描上一次状态和现在状态,有区别吗
        for(i=0; i<4; i++) //out
        {
            for(j=0; j<4; j++) //in
            {
                if(backup[i][j]!=KeySta[i][j])
                {
                    if(backup[i][j]==0)
                    {
                        //松开
                        P0=LedChar[i*4+j];
                    }
                    else
                    {
                        //按下
                    }
                    backup[i][j]=KeySta[i][j];
                }
            }
        }
    }
}

void Timer0_ISR(void)interrupt 1
{
    static u8 keyout=0;//控制4个线拉低的
    u8 i=0;
    
    //保存按键每一次读取的值
    static u8 keybuf[4][4]={
        {0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF}
    };

    TH0=0xF8;
    TL0=0xCD;

    //读keyout拉低行的,4个列按键状态
    keybuf[keyout][0]=(keybuf[keyout][0]<<1)|KEYIN1;//读第1列按键
    keybuf[keyout][1]=(keybuf[keyout][1]<<1)|KEYIN2;//读第2列按键
    keybuf[keyout][2]=(keybuf[keyout][2]<<1)|KEYIN3;//读第3列按键
    keybuf[keyout][3]=(keybuf[keyout][3]<<1)|KEYIN4;//读第4列按键

    //判断刚读取的4个按键,是否稳定
    for(i=0; i<4; i++)
    {
        if((keybuf[keyout][i] & 0x0F) == 0x00)//稳定为0
        {
            KeySta[keyout][i]=0;
        }
        else if((keybuf[keyout][i] & 0x0F) == 0x0F)//稳定为1
        {
            KeySta[keyout][i]=1;
        }
        else
        {
            //抖动
        }
    }

    //切换下一行拉低,方便下次读取
    keyout++;
    keyout&=0x03;
    switch(keyout)
    {
    case 0:
        KEYOUT4=1;
        KEYOUT1=0;
        break;
    case 1:
        KEYOUT1=1;
        KEYOUT2=0;
        break;
    case 2:
        KEYOUT2=1;
        KEYOUT3=0;
        break;
    case 3:
        KEYOUT3=1;
        KEYOUT4=0;
        break;
    }

}
//分析,太费内存了把,使用了16*3约50个字节的变量

课上例子,加法器,up=加;enter是等于;
#include <reg52.h>

typedef unsigned char u8;
typedef unsigned int  u16;
typedef unsigned long u32;
typedef signed char i8;
typedef signed int  i16;
typedef signed long i32;

sbit ADDR0 = P1 ^ 0;
sbit ADDR1 = P1 ^ 1;
sbit ADDR2 = P1 ^ 2;
sbit ADDR3 = P1 ^ 3;
sbit ENLED = P1 ^ 4;

// 4个列,要读取
sbit KEYIN1 = P2 ^ 4;
sbit KEYIN2 = P2 ^ 5;
sbit KEYIN3 = P2 ^ 6;
sbit KEYIN4 = P2 ^ 7;

// 4个行,要拉低
sbit KEYOUT1 = P2 ^ 3;
sbit KEYOUT2 = P2 ^ 2;
sbit KEYOUT3 = P2 ^ 1;
sbit KEYOUT4 = P2 ^ 0;

// 保存中断消抖后,读取按键状态
u8 KeySta[4][4] =
    {
    {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}};

// 数码管code
u8 code LedChar[16] =
    {
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E};

// 数码管缓冲区
u8 LedBuff[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

u8 code KeyCodeMap[4][4] = {
    {0x31, 0x32, 0x33, 0x26}, // 数字1,2,3,UP
    {0x34, 0x35, 0x36, 0x25}, // 数字4,5,6,LEFT
    {0x37, 0x38, 0x39, 0x28}, // 数字7,8,9,DOWN
    {0x30, 0x1B, 0x0D, 0x27}, // 数字0,ESC,ENTER,RIGHT

};
void KeyDriver();
void main(void)
{
    TMOD = 0x01;
    TH0 = 0xFC;
    TL0 = 0x66;
    ET0 = EA = TR0 = 1;

    ENLED = 0;
    ADDR3 = 1;

    LedBuff[0] = LedChar[0];

    while (1)
    {
        KeyDriver();
    }
}

void ShowNumber(u32 num)
{
    u8 buf[6];
    u8 i,j;

    for (i = 0; i < 6; i++)
    {
        buf[i] = num % 10;
        num /= 10;
    }

    for (i = 5; i >= 1; i--)
    {
        if (buf[i] == 0)
        {
            LedBuff[i] = 0xFF; // 不显示
        }
        else
        {
            break;
        }
    }
    for (j=0; j<=i;j++)
    {
        LedBuff[j] = LedChar[buf[j]];
    }
}
void KeyAction(u8 keycode)
{
    static u32 result = 0;
    static u32 addend = 0;

    if ((keycode >= 0x30) && (keycode <= 0x39))
    {
        // num
        addend = (addend * 10) + (keycode - 0x30);
        ShowNumber(addend);
    }
    else if (keycode == 0x26) // up,+
    {
        result += addend;
        addend = 0;
        ShowNumber(result);
    }
    else if (keycode == 0x0D) // enter =
    {
        result += addend;
        addend = 0;
        ShowNumber(result);
    }
    else if (keycode == 0x1B) // esc clear
    {
        addend = 0;
        result = 0;
        ShowNumber(0);
    }
}
void KeyDriver(void)
{
    // 保存上一次按键的状态
    static u8 backup[4][4] = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}};

    u8 i, j;
    // 扫描上一次状态和现在状态,有区别吗
    for (i = 0; i < 4; i++) // out
    {
        for (j = 0; j < 4; j++) // in
        {
            if (backup[i][j] != KeySta[i][j])
            {
                if (backup[i][j] == 0)
                {
                    KeyAction(KeyCodeMap[i][j]);
                }
                else
                {
                    // 按下
                }
                backup[i][j] = KeySta[i][j];
            }
        }
    }
}

void KeyScan(void)
{

    static u8 keyout = 0; // 控制4个线拉低的
    u8 i = 0;
    // 保存按键每一次读取的值
    static u8 keybuf[4][4] = {{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}};

    // 读keyout拉低行的,4个列按键状态
    keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEYIN1; // 读第1列按键
    keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEYIN2; // 读第2列按键
    keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEYIN3; // 读第3列按键
    keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEYIN4; // 读第4列按键

    // 判断刚读取的4个按键,是否稳定
    for (i = 0; i < 4; i++)
    {
        if ((keybuf[keyout][i] & 0x0F) == 0x00) // 稳定为0
        {
            KeySta[keyout][i] = 0;
        }
        else if ((keybuf[keyout][i] & 0x0F) == 0x0F) // 稳定为1
        {
            KeySta[keyout][i] = 1;
        }
        else
        {
            // 抖动
        }
    }

    // 切换下一行拉低,方便下次读取
    keyout++;
    keyout &= 0x03;
    switch (keyout)
    {
    case 0:
        KEYOUT4 = 1;
        KEYOUT1 = 0;
        break;
    case 1:
        KEYOUT1 = 1;
        KEYOUT2 = 0;
        break;
    case 2:
        KEYOUT2 = 1;
        KEYOUT3 = 0;
        break;
    case 3:
        KEYOUT3 = 1;
        KEYOUT4 = 0;
        break;
    }
}

void LedScan(void)
{
    static u8 i = 0;

    P0 = 0xFF; // 消影
    switch (i)
    {
    case 0:
        ADDR2 = 0;
        ADDR1 = 0;
        ADDR0 = 0;
        i++;
        P0 = LedBuff[0];
        break;
    case 1:
        ADDR2 = 0;
        ADDR1 = 0;
        ADDR0 = 1;
        i++;
        P0 = LedBuff[1];
        break;
    case 2:
        ADDR2 = 0;
        ADDR1 = 1;
        ADDR0 = 0;
        i++;
        P0 = LedBuff[2];
        break;
    case 3:
        ADDR2 = 0;
        ADDR1 = 1;
        ADDR0 = 1;
        i++;
        P0 = LedBuff[3];
        break;
    case 4:
        ADDR2 = 1;
        ADDR1 = 0;
        ADDR0 = 0;
        i++;
        P0 = LedBuff[4];
        break;
    case 5:
        ADDR2 = 1;
        ADDR1 = 0;
        ADDR0 = 1;
        P0 = LedBuff[5];
        i = 0;
        break;
    }
}

void Timer0_ISR(void) interrupt 1
{
    TH0 = 0xFC;
    TL0 = 0x66;
    LedScan();
    KeyScan();
}

//课后作业在下一篇



第8章-函数进阶与按键(上:跟堂作业)的评论 (共 条)

分享到微博请遵守国家法律