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

第8章-函数进阶与按键(下,课后作业+抓波欣赏)

2023-08-26 13:35 作者:feifeiluan2  | 我要投稿

这节课,真麻烦,全书最难的之一,

// 课后第4题,按一个键K12-DOWN,数码管从F减到0
// 按键的扫描,也结合了http://www.dumenmen.com吴坚鸿老师的思路
// 一切皆计数
#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;

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

bit keyFlag = 0; // 0=没有按键;

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

    ENLED=0;
    ADDR3=1;
    ADDR2=0;
    ADDR1=0;
    ADDR0=0;
    
    KEYOUT3=0;
    
    cnt=0x0F;
    P0 = LedChar[cnt];

    while (1)
    {
        if(keyFlag)
        {
            keyFlag=0;
            cnt--;
            cnt&=0x0F;
            P0=LedChar[cnt];
        }
    }
}



void Timer0_ISR(void) interrupt 1
{
    static u16 cnt=0;
    
    TH0 = 0xFC;
    TL0 = 0x66;
    
    if(KEYIN4==0)
    {
        cnt++;
        if(cnt==40)//40ms
        {
            keyFlag=1;
        }
    }
    else
    {
        cnt=0;
    }
}



// 课后第5题,减法计算器,干脆扩展成加减乘除
// 在老师的基础上,上=加,下=减,左=乘,右=除(除数为0,不理会)
// 为了简单,不支持连续运算,必须按步奏来
// 步奏0:输入x,输入+/-号等; 得到第一个操作数x和运算符op
// 步奏1:输入y,输入等号得到结果;得到第二个操作数y,,然后计算 y = (x op y)
// 步奏2:再输入+/-号等,回到步奏1;得到下一次的运算符op,上次结果作为第一个操作数x,

// 按键的扫描,也结合了http://www.dumenmen.com吴坚鸿老师的思路
// 一切皆计数
#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;

// 数码管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 key = 0; // 0=没有按键;非零=按键code

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;

    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 u8 step = 0;
    static u32 result = 0;
    static u32 addend = 0;
    static u8 op;

    if (keycode == 0x1B) // esc
    {
        addend = 0;
        result = 0;
        step = 0;
        ShowNumber(0);
        return;
    }

    switch (step)
    {
    case 0:
        // 步奏0:输入x,输入+/-号等; 得到第一个操作数x和运算符op
        if (keycode >= '0' && keycode <= '9')
        {
            addend = addend * 10 + keycode - '0';
            ShowNumber(addend);
        }
        else if (keycode == 0x25 || keycode == 0x26 || keycode == 0x27 || keycode == 0x28) // 加减乘除
        {
            result = addend;
            addend = 0;
            op = keycode;
            ShowNumber(0);
            step++;
        }
        break;
    case 1:
        // 步奏1:输入y,输入等号得到结果;得到第二个操作数y,,然后计算 y = (x op y)
        if (keycode >= '0' && keycode <= '9')
        {
            addend = addend * 10 + keycode - '0';
            ShowNumber(addend);
        }
        else if (keycode == 0x0D) // enter =
        {
            if (op == 0x26) //+
            {
                result += addend;
            }
            else if (op == 0x28) //-
            {
                result -= addend;
            }
            else if (op == 0x25) //*
            {
                result *= addend;
            }
            else if (op == 0x27) // /
            {
                if (addend != 0)
                {
                    result /= addend;
                }
            }
            ShowNumber(result);
            step++;
        }
        break;
    case 2:
        // 步奏2:再输入+/-,回到步奏1;得到下一次的运算符op,上次结果作为第一个操作数x,
        if (keycode == 0x25 || keycode == 0x26 || keycode == 0x27 || keycode == 0x28) // 加减乘除
        {
            op = keycode;
            addend = 0;
            ShowNumber(0);
            step = 1;
        }
        break;
    default:
        break;
    }
}
void KeyDriver(void)
{
    if (key)
    {
        KeyAction(key);
        key = 0;
    }
}

void KeyScan(void)
{
    static u8 step = 0;
    static u8 hang = 0; // 控制4个线拉低
    static u16 cnt = 0;

    switch (step)
    {
    case 0: // 拉低1行
        if (hang == 0)
        {
            KEYOUT4 = 1;
            KEYOUT1 = 0;
        }
        else if (hang == 1)
        {
            KEYOUT1 = 1;
            KEYOUT2 = 0;
        }
        else if (hang == 2)
        {
            KEYOUT2 = 1;
            KEYOUT3 = 0;
        }
        else if (hang == 3)
        {
            KEYOUT3 = 1;
            KEYOUT4 = 0;
        }
        step++; // 进入下一步,1ms以后进来读取列
        break;
    case 1:
        if (KEYIN1 && KEYIN2 && KEYIN3 && KEYIN4)
        {
            // 没有任何按键按下,或者发生了抖动
            cnt = 0;
            // 切换下一行拉低
            hang++;
            hang &= 0x03;
            step = 0; // 回到第一步
        }
        else
        {
            cnt++;           // 有按键按下,计数器++
            if (cnt == 40) // 能坚持到40ms的,算一次合理按键
            {
                u8 lie;
                if (KEYIN1 == 0)
                {
                    lie = 0;
                }
                else if (KEYIN2 == 0)
                {
                    lie = 1;
                }
                else if (KEYIN3 == 0)
                {
                    lie = 2;
                }
                else if (KEYIN4 == 0)
                {
                    lie = 3;
                }
                key = KeyCodeMap[hang][lie];
            }
        }
        break;
    }
}

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

    ENLED = 1; // 关闭138;
    ADDR3 = 1; //确保选138的后八路

    P1 &= 0xF8; // 1111-1000
    P1 |= i;    // xxxx-xiii;
    P0=LedBuff[i];

    ENLED = 0;

    if (++i == 6)
    {
        i = 0;
    }
}

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


课后第5题,波形抓取,按键1和5

最后欣赏一下,老师课堂上的例子,波形抓取,按键1和5


第8章-函数进阶与按键(下,课后作业+抓波欣赏)的评论 (共 条)

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