51单片机矩阵键盘实现时钟

本文详细介绍了使用51单片机通过矩阵键盘实现时钟的完整流程,包括矩阵键盘的接口电路设计、定时器中断的原理及实现、整体电路设计和程序设计。在矩阵键盘中断服务函数中,计数达到特定次数后,实现时钟功能。

前言

单片机实现时钟项目实战!

目录

一、矩阵键盘电路设计

1. 键盘接口电路设计

2. 定时器中断过程的实现原理

① 定时器初始化的主要步骤

② 定时器初值设定方法

③ 定时器中断服务函数的实现原理

二、整体电路原理图

三、程序设计

四、程序实现


一、矩阵键盘电路设计

1. 键盘接口电路设计

当无按键闭合时,P1.0 ~ P1.3 与 P1.4 ~ P3.7之间开路。当有键闭合时,与闭合键相连的两条 I0 口线之间短路。判断有无按键按下的方法是:第一步,置列线 P1.4 ~ P1.7 为输入状态,从行线 P1.0 ~ P1.3 输出低电平,读入列线数据,若某一列线为低电平,则该列线上有键闭合。

第二步,行线轮流输出低电平,从列线 P1.4 ~ P1.7 读入数据,若有某一列为低电平,则对应行线上有键按下,综合一二两步的结果,可确定按键编号。但是键闭合一次只能进行一次键功能操作,因此须等到按键释放后,再进行键功能操作,否则按一次键,有可能会连续多次进行同样的键操作。

图1 矩阵键盘设计局部电路图

图2 矩阵键盘对应的功能

2. 定时器中断过程的实现原理

定时器工作前先装入初值,利用送数指令将初值装入 TH0 和 TL0 或 TH1 和 TL1,高位数装入 TH0和 TH1,低位数装入 TL0 和 TL1。当发出启动命令后,

装初值寄存器开始计数,连续加 1,每一个机器周期加 1 一次,加到满值(各位全 1)。若再加 1,则溢出,同时将初值寄存器清零。如果继续计数定时,则需要重新赋初值,如下图3所示。

图3 矩阵键盘设计局部电路图

① 定时器初始化的主要步骤

第一步 选择工作方式,即对TMOD 赋初值。第二步 给定时器赋初值,即把初始常数装入THO TLO 或TH1 TL1。第三步根据需要设置中断控制字直接对中断允许寄存器E和优先级寄存器IP设置。第四步启动定时计数数器,若已规定用软件启动(即GATE=0),则可把TRO或TR1置1。若已规定出外中断端子电平启动(即GATE=1),则需给外端子加启动电平。

② 定时器初值设定方法

根据定时长短,选择工作方式,设用M表示最大计数值,则各种方式计数最大值如下。方式0:M = 2^13 = 8192,方式1 :M = 2^16 = 65536,方式2:M = 2^8 = 256,方式3:M = 2^8 = 256

③ 定时器中断服务函数的实现原理

中断服务程序:就是当计满 THO 、TLO 时溢出申请中断,然后单片机允许中断时,所要发生的事情.允许后就自动跳转到中断服务程序,并执行在服务程序中,如果不装入初值,那定时器中断服务完成后,就会从 0 开始重新计时,所以要在中断程序中重新计算并装入初值.然后给一个变量(变量的意义为中断次数),变量 +1 ,当中断次数达到 20 次的时候(50ms*20次 = 1000ms = 1s),次数清零,并且让产生指令,实现时钟定时功能。

二、整体电路原理图

 图4 整体电路设计

三、程序设计

通过 STC89C52 单片机,控制矩阵键盘能够实现开始、暂停、归零、计数、定时的功能,并在四个数码管上显示出来。

具体功能为:对前 14 个数码管进行定义,能够实现按键 4 为计时暂停,按键 8 为计时开始,按键 12 为暂停时钟,按键 16 为数值加 1,按键 13 为移动修改数值键,按键 15 为定时功能,其余按键为 0-9 数值键。

图5 代码实现流程图

四、程序实现

#include<reg52.h>

//--定义使用的IO口--//
#define GPIO_KEY P1
#define GPIO_DIG  P0 //段位选
sbit D1=P3^6;//段选
sbit D2=P3^7;//位选
unsigned char code DIG_PLACE[8] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
unsigned char codeseg[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
0x40};
unsigned char xianshi[8];//保存时钟的数据
char second,minit,hours,s,m;

char Time,state,set,T;
//state=0显示时间,state=1校对时间,state=2定时
//set校对或者定时时,设置哪一位

unsigned char KeyValue,KeyValue2;//keyValue2(0-15),keyValue(0-9加功能)
unsigned char KeyState; //记录按键的状态,0没有,1有
void Delay10ms(unsigned int c) //延时函数
{
    unsigned char a,b;
    for(; c>0; c--)
        for(b=38; b>0; b--)
            for(a=130; a>0; a--);
}

void KeyDown(void)
{
    GPIO_KEY=0x0f;   //测试列
    if(GPIO_KEY!=0x0f)
    {
        Delay10ms(1);//延时消抖
        if(GPIO_KEY!=0x0f)
        {
            KeyState=1;//有按键按下
            //测试列
            GPIO_KEY=0X0F;
            switch(GPIO_KEY)
            {
            case(0X07):
                KeyValue2=0;
                break;
            case(0X0b):
                KeyValue2=1;
                break;
            case(0X0d):
                KeyValue2=2;
                break;
            case(0X0e):
                KeyValue2=3;
                break;
            }
            //测试行
            GPIO_KEY=0XF0;
            Delay10ms(1);
            switch(GPIO_KEY)
            {
            case(0X70):
                KeyValue2=KeyValue2;
                break;
            case(0Xb0):
                KeyValue2=KeyValue2+4;
                break;
            case(0Xd0):
                KeyValue2=KeyValue2+8;
                break;
            case(0Xe0):
                KeyValue2=KeyValue2+12;
                break;
            }
            while(GPIO_KEY!=0xf0);   //等待按键松开
            if(KeyValue2==0)KeyValue=1;
            if(KeyValue2==1)KeyValue=2;
            if(KeyValue2==2)KeyValue=3;
            if(KeyValue2==4)KeyValue=4;
            if(KeyValue2==5)KeyValue=5;
            if(KeyValue2==6)KeyValue=6;
            if(KeyValue2==8)KeyValue=7;
            if(KeyValue2==9)KeyValue=8;
            if(KeyValue2==10)KeyValue=9;
            if(KeyValue2==13)KeyValue=0;

            if(KeyValue2==3)KeyValue=10;   //暂停
            if(KeyValue2==7)KeyValue=11;   //开始
            if(KeyValue2==11)KeyValue=12;  //归零
            if(KeyValue2==12)KeyValue=13;  //左移
            if(KeyValue2==14)KeyValue=14;  //右移
            if(KeyValue2==15)KeyValue=15;  //小时+1
        }
    }
}

void DigDisplay()
{
    unsigned char i;
    unsigned int j;

    for(i=0; i<4; i++)
    {
        GPIO_DIG = DIG_PLACE[i];  //发送位选
        D2=1;//573输出位选
        D2=0;//锁存

        GPIO_DIG = xianshi[i];     //发送段码
        D1=1;//输出段选
        D1=0;//锁存
        j = 100;       //扫描间隔时间设定
        while(j--);
        GPIO_DIG = 0x00;//消隐
        D1=1;
        D1=0;
    }
}
void Smgshow()
{
    if(hours/8%2==1)
        xianshi[0]=seg[minit/10]|0x80;
    else
        xianshi[0]=seg[minit/10];

    if(hours/4%2==1)
        xianshi[1]=seg[minit%10]|0x80;
    else
        xianshi[1]=seg[minit%10];

    if(hours/2%2==1)
        xianshi[2]=seg[second/10]|0x80;
    else
        xianshi[2]=seg[second/10];

    if(hours%2==1)
        xianshi[3]=seg[second%10]|0x80;
    else
        xianshi[3]=seg[second%10];
    DigDisplay();
}

void Flashshow()//设置时闪烁显示
{
    if(Time<50)
    {
        if(hours/8%2==1)
            xianshi[0]=seg[minit/10]|0x80;
        else
            xianshi[0]=seg[minit/10];

        if(hours/4%2==1)
            xianshi[1]=seg[minit%10]|0x80;
        else
            xianshi[1]=seg[minit%10];

        if(hours/2%2==1)
            xianshi[2]=seg[second/10]|0x80;
        else
            xianshi[2]=seg[second/10];

        if(hours%2==1)
            xianshi[3]=seg[second%10]|0x80;
        else
            xianshi[3]=seg[second%10];
    }
    else
    {
        if(set==3)
        {
            xianshi[0]=0x00;
        }
        if(set==2)
        {
            xianshi[1]=0x00;
        }
        if(set==1)
        {
            xianshi[2]=0x00;
        }
        if(set==0)
        {
            xianshi[3]=0x00;
        }
    }
    DigDisplay();
}

void Flashshow2()//定时结束时闪烁显示
{
    int i=0;
    while(i<1000) {
        T++;
        if(T>100)
            T=0;
        if(T<50)
        {
            if(hours/8%2==1)
                xianshi[0]=seg[minit/10]|0x80;
            else
                xianshi[0]=seg[minit/10];

            if(hours/4%2==1)
                xianshi[1]=seg[minit%10]|0x80;
            else
                xianshi[1]=seg[minit%10];

            if(hours/2%2==1)
                xianshi[2]=seg[second/10]|0x80;
            else
                xianshi[2]=seg[second/10];

            if(hours%2==1)
                xianshi[3]=seg[second%10]|0x80;
            else
                xianshi[3]=seg[second%10];
        }
        else
        {

            xianshi[0]=0x00;
            xianshi[1]=0x00;
            xianshi[2]=0x00;
            xianshi[3]=0x00;
        }
        DigDisplay();
    }

}

void main()
{
    second=55;
    minit=59;
    hours=0;
    TMOD=0X01;
    TH0 = 0xDC;
    TL0 = 0x00;  //10ms
    TR0=1;//启动定时功能
    ET0=1;//开定时器允许中断
    EA=1;//打开总中断
    state=0;
    m=59;
    s=59;
    while(1)
    {
        while(state==0)
        {
            KeyDown(); //扫描键盘
            if((KeyState==1))  //如果有按键按下
            {
                if(KeyValue==10)   //如果是第4个按键按下
                {
                    TR0=0;
                    ET0=0; //暂停,关闭定时功能,关闭定时器允许中断
                }
                if(KeyValue==11)  //如果是第8个按键按下
                {
                    TR0=1;
                    ET0=1; //开始
                }
                if(KeyValue==12)  //如果是第12个按键按下
                {
                    second=0;
                    minit=0;
                    hours=0;
                    TR0=1;
                    ET0=1; //归零
                }
                if(KeyValue==15)  //如果是第16个按键按下
                {
                    hours++;  //加1小时
                    if(hours>23)
                        hours=0;
                }

                if(KeyValue==13)  //如果是第13个按键按下
                {
                    state=1; //设置
                    set=0;
                }
                if(KeyValue==14)  //如果是第15个按键按下
                {
                    state=2; //定时
                    set=0;
                }

                KeyState=0;
            }
            Smgshow();
        }


        while(state==1)
        {
            KeyDown(); //扫描键盘
            if((KeyState==1))  //如果有按键按下
            {
                if(KeyValue==15)  //如果是第16个按键按下
                {
                    hours++;  //加1小时
                    if(hours>23)
                        hours=0;
                }
                if(KeyValue==13)  //如果是第13个按键按下
                {
                    set++;//左移
                    if(set>=4)
                    {
                        set=0;
                        state=0;
                    }
                }
                if(KeyValue==14)  //如果是第15个按键按下
                {
                    set--;//右移
                    if(set<0)
                    {
                        set=0;
                        state=0;
                    }
                }
                if(KeyValue==11)  //如果是第8个按键按下
                {
                    TR0=1;
                    ET0=1; //开始
                }


                if(KeyValue<10)
                {
                    if(set==0)
                    {
                        second=second/10%10*10+KeyValue;
                    }
                    if(set==1)
                    {
                        if(KeyValue<6)
                            second=second%10+KeyValue*10;
                    }
                    if(set==2)
                    {
                        minit=minit/10%10*10+KeyValue;
                    }
                    if(set==3)
                    {
                        if(KeyValue<6)
                        minit=minit%10+KeyValue*10;
                    }
                }

                KeyState=0;
            }
            Flashshow();
        }

        while(state==2)
        {
            KeyDown(); //扫描键盘
            if((KeyState==1))  //如果有按键按下
            {
                if(KeyValue==15)  //如果是第16个按键按下
                {
                    hours++;  //加1小时
                    if(hours>23)
                        hours=0;
                }
                if(KeyValue==13)  //如果是第13个按键按下
                {
                    set++;//左移
                }
                if(KeyValue==10)   //如果是第4个按键按下
                {
                    TR0=0;
                    ET0=0; //暂停,关闭定时功能,关闭定时器允许中断
                }
                if(KeyValue==11)  //如果是第8个按键按下
                {
                    TR0=1;
                    ET0=1; //开始
                }


                if(KeyValue<10)
                {
                    if(set==0)
                    {
                        second=second/10%10*10+KeyValue;
                        s=second;
                    }
                    if(set==1)
                    {
                        if(KeyValue<6)
                            second=second%10+KeyValue*10;
                        s=second;
                    }
                    if(set==2)
                    {
                        minit=minit/10%10*10+KeyValue;
                        m=minit;
                    }
                    if(set==3)
                    {
                        if(KeyValue<6)
                        minit=minit%10+KeyValue*10;
                        m=minit;
                        second=0;
                        minit=0;
                    }
                }

                KeyState=0;
            }
            Flashshow();
        }

    }
}

void time0() interrupt 1
{
    static unsigned int j;
    TH0 = 0xDC;
    TL0 = 0x00;  //重新装载10ms
    if(state==1)
    {
        Time++;
        if(Time>100)
            Time=0;
    }
    if(state==0)
    {
        j++;
        if(j==100) //1s
        {
            j=0;
            second++;
            if(second==60)     //秒满60清零
            {
                second=0;
                minit++;
                if(minit==60)     //分满60清零
                {
                    minit=0;
                    hours++;
                    if(hours>15)hours=0;   //时满16清零
                }
            }

        }
    }
    if(state==2)
    {
        Time++;
        if(Time>100)
            Time=0;
        if((minit>=m)&(second>=s))   //如果到时间
        {
            TR0=0;
            ET0=0; //暂停,关闭定时功能,关闭定时器允许中断
            Flashshow2();
        }
        else {
            j++;
            if(j==100) //1s
            {
                j=0;
                second++;
                if(second==60)     //秒满60清零
                {
                    second=0;
                    minit++;
                    if(minit==60)     //分满60清零
                    {
                        minit=0;
                        hours++;
                        if(hours>15)hours=0;   //时满16清零
                    }
                }

            }
        }
    }
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个写代码的修车工

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值