VegoSong

记录点滴生活,学习心得,分享经验

院电赛多功能电子时钟设计思路及源码

(一)功能

从默认时间7:00:00(24小时制)开始显示时间;使用4*4矩阵键盘(每个键功能如图1)可以设置当前时间、闹铃时间以及当前日期,数码管实时显示设置数据,设置完成后数码管自动显示当前时间并继续运行;如果当前时间与闹铃时间相同,蜂鸣器触发持续报警,按下取消闹铃键,蜂鸣器停止报警,按下显示日期按钮,数码管显示当前日期以及日期对应星期几。

图1 矩阵键盘具体功能

(二)技术指标

晶体数码管的显示,矩阵键盘与晶体数码管的交互,蜂鸣器的鸣叫,时间与秒数的换算,日期对应星期的计算。

  • 设计方案

(一)需要使用的外部硬件:

因51单片机开发箱已含有题目所需的晶体数码管、蜂鸣器和矩阵键盘,从方便开发、节省时间方面考虑,本小组采用51单片机开发箱。

(二)编程部分

本小组使用C语言对单片机编程,开发环境选择Keil uVision4软件,程序下载软件使用普中科技单片机程序下载软件V1.8.2。

  • 原理框图
《院电赛多功能电子时钟设计思路及源码》

图2 模块相互联系

  • 电路连接

P0接数码管段选J12,P1接数码管位选J16,P2^0至P2^6接静态数码管段选JP3,P2^7接蜂鸣器J8,P3接矩阵键盘JP4。

代码部分:

/********************************************************

              E题   数码电子表
制作小组成员:宋xy 2017*******8
              石yf 2017*******0
********************************************************/


//**********************头文件定义*************************
#include <reg52.h>
//*********************************************************

//********************全局变量定义*************************
//此表为8个数码管位选控制, 共阴数码管 1-8个  
unsigned char Disp_Bit[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdF,0xbF,0x7F};    //位选控制   查表的方法控制
//此表为 LED 的字模, 共阴数码管 "0-9" " - "                                             
unsigned char Disp_Code[11] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};  //共阴数码管段码控制
unsigned long Second=25200;//定义初始时间(7A.M)
unsigned int AlarmSecond=50;//定义闹钟时间
unsigned char Int_Count;  
unsigned char temp[8];      //显示时间函数中储存时间的每一位  
int i,j;                      //万用计数变量
unsigned char KEYValue;      //按键函数返回的键值
unsigned char KEYValues[15]; //用于储存设置时间,日期的每一位
unsigned char AlarmValue[11];//用于储存设置闹铃时间的每一位
unsigned char Alarm_Flag=0;     //闹铃标志位(0为关闭1为打开)
unsigned int Year=2018;             //定义初始年份
unsigned char Month=1;             //定义初始月份
unsigned char Day=1;             //定义初始日期
unsigned int week;                 //定义星期
unsigned int id[17]={2,1,0,1,2,3,2,1,10,2,1,1,1,3,1,1,0};             //储存作者学号
//********************************************************* 

//********************位定义*************************
sbit SPK=P2^7;             //声明蜂鸣器端口
//***************************************************

//********************子函数定义*************************
void DisplayTime();           //声明显示时间子函数
void DisplayDate();           //声明显示时间子函数
unsigned int SettingTime();//声明设置时间子函数
unsigned int KeyDown();       //声明按键子函数
unsigned int AlarmSetting();//声明闹钟设置子函数
unsigned int SettingDate();//声明设置日期子函数
void delay(unsigned int i);    //声明延时子函数
void Timer_Ini(void);        //声明计时器子函数
void Ring(void);            //声明蜂鸣器蜂鸣子函数
void SettingTemDisplay();    //声明设置时间零时显示函数
void AlarmTemDisplay();        //声明设置闹铃零时显示函数
void DateTemDisplay();        //声明设置日期零时显示函数
void DisplayID();            //声明显示作者QQ函数
void iWeek();               //声明根据日期计算星期函数
//*******************************************************

void main()
{     
     Timer_Ini();
     while(1)
     {
        if(Int_Count>=20) //判断秒数增加  
        {
            Second++;      //秒数加一
            Int_Count = 0; //重置计数
        }
        KeyDown();
        if(KEYValue==10)
        {
        SettingTime();      //进行时间设置操作
        }
        if(KEYValue==11)
        {
        AlarmSetting();     //进行闹钟设置操作
        }
        if(KEYValue==12)
        {
        Alarm_Flag = 0;     //使得闹铃标志位为0,蜂鸣器停止鸣叫
        }
        if(KEYValue==13)
        {
        SettingDate();     //设置日期
        }

        if(KEYValue==14)
        {
        DisplayDate();     //显示日期
        }
        if(KEYValue==15)
        {
        DisplayID();     //显示作者QQ
        }
        if(Second==AlarmSecond)
        {
            Alarm_Flag = 1;
        }
        if(Alarm_Flag==1)
        {
        Ring();
        }
        DisplayTime();
        if((Second/3600/10)==2&&(Second/3600%10==4))//判断是否迎来新的一天
        {
       if((Second%3600/60/10==0)&&(Second%3600/60%10==0))
            {
        if((Second%60/10==0)&&(Second%60%10==0))
                {
                Day++;
                Second = 0;
                }
            }
        } 

     }
}
//*******显示时间子函数************//
void DisplayTime()    
{
         temp[0] = Second/3600/10;  // 小时1
         temp[1] = Second/3600%10;  // 小时2
         temp[2] = 10;  // -
         temp[3] = Second%3600/60/10;   // 分钟1
         temp[4] = Second%3600/60%10;   // 分钟2
         temp[5] = 10;  // -
         temp[6] = Second%60/10;        // 秒钟1
         temp[7] = Second%60%10;    // 秒钟2

         for(i=0;i<8;i++)
         {
            P1 = Disp_Bit[i];  //第i个数码管位选    1011 1111   0xbf
            P0 = Disp_Code[temp[i]];     //第i个数码管的编码
            delay(2);
          }
}
//*******时间设置零时显示子函数(用于设置时实时显示)************//
void SettingTemDisplay()    
{
         temp[0] = KEYValues[0];  // 小时1
         temp[1] = KEYValues[2];    // 小时2
         temp[2] = 10;  // -
         temp[3] = KEYValues[4];    // 分钟1
         temp[4] = KEYValues[6];    // 分钟2
         temp[5] = 10;  // -
         temp[6] = KEYValues[8];        // 秒钟1
         temp[7] = KEYValues[10];   // 秒钟2

         for(j=0;j<8;j++)
         {
            P1 = Disp_Bit[j];  //第i个数码管位选    1011 1111   0xbf
            P0 = Disp_Code[temp[j]];     //第i个数码管的编码
            delay(2);
          }
}
 //*******显示日期子函数************//
void DisplayDate()
{
         iWeek();
         while(1)
         {
         temp[0] = Year/1000;  // 年份1
         temp[1] = Year%1000/100;   // 年份2
         temp[2] = Year%100/10; // 年份3
         temp[3] = Year%10; // 年份4
         temp[4] = Month/10;    // 月份1
         temp[5] = Month%10;    // 月份2
         temp[6] = Day/10;      // 日期1
         temp[7] = Day%10;      // 日期2

         for(i=0;i<8;i++)
         {
            P1 = Disp_Bit[i];  //第i个数码管位选    1011 1111   0xbf
            P0 = Disp_Code[temp[i]];     //第i个数码管的编码
            delay(2);
          }
        P2 = ~Disp_Code[week]; //共阳数码管显示星期
        if(P3!=0x0f)//读取按键是否按下
        {
            break;
        }

         }

}
 //*******闹钟设置零时显示子函数(用于设置时实时显示)************//
void AlarmTemDisplay()    
{
         temp[0] = AlarmValue[0];  // 小时1
         temp[1] = AlarmValue[2];   // 小时2
         temp[2] = 10;  // -
         temp[3] = AlarmValue[4];   // 分钟1
         temp[4] = AlarmValue[6];   // 分钟2
         temp[5] = 10;  // -
         temp[6] = AlarmValue[8];       // 秒钟1
         temp[7] = AlarmValue[10];  // 秒钟2

         for(j=0;j<8;j++)
         {
            P1 = Disp_Bit[j];  //第i个数码管位选    1011 1111   0xbf
            P0 = Disp_Code[temp[j]];     //第i个数码管的编码
            delay(2);
          }
}
//*******日期设置零时显示子函数(用于设置时实时显示)************//
void DateTemDisplay()    
{
         temp[0] = KEYValues[0];  // 年份1
         temp[1] = KEYValues[2];    // 年份2
         temp[2] = KEYValues[4];    // 年份3
         temp[3] = KEYValues[6];    // 年份4
         temp[4] = KEYValues[8];    // 月份1
         temp[5] = KEYValues[10];   // 月份2
         temp[6] = KEYValues[12];       // 日期1
         temp[7] = KEYValues[14];       // 日期2

         for(j=0;j<8;j++)
         {
            P1 = Disp_Bit[j];  //第i个数码管位选    1011 1111   0xbf
            P0 = Disp_Code[temp[j]];     //第i个数码管的编码
            delay(2);
          }
}
//*******设置时间子函数************//
unsigned int SettingTime()
{
    i=-1,j;
    while(1)
    {   
        SettingTemDisplay();
        if(P3!=0x0f)//读取按键是否按下
    {
        KEYValue = KeyDown();
        KEYValues[i]=KEYValue;
        i++;
     }
        if(i==11)
        {
         break;
        }

    }
    Second=KEYValues[0]*36000+KEYValues[2]*3600+KEYValues[4]*600+KEYValues[6]*60+KEYValues[8]*10+KEYValues[10];
    return(Second);             
}

//*******闹铃设置子函数************//
unsigned int AlarmSetting()
{
    i=-1;
    while(1)
    {
        AlarmTemDisplay();
        if(P3!=0x0f)//读取按键是否按下
    {
        KEYValue = KeyDown();
        AlarmValue[i]=KEYValue;
        i++;

     }
        if(i==11)
        {
         break;
        }
    }
    AlarmSecond=AlarmValue[0]*36000+AlarmValue[2]*3600+AlarmValue[4]*600+AlarmValue[6]*60+AlarmValue[8]*10+AlarmValue[10];
    return(AlarmSecond);
}
//*******设置日期子函数************
unsigned int SettingDate()
{
    i=-1;
/*    for(i=0;i<15;i++)//清空KeyValues
    {
    KEYValues[i]=0;
    }*/
    while(1)
    {   
        DateTemDisplay();
        if(P3!=0x0f)//读取按键是否按下
    {
        KEYValue = KeyDown();
        KEYValues[i]=KEYValue;
        i++;
     }
        if(i==15)
        {
         break;
        }

    }
    Year = KEYValues[0]*1000+KEYValues[2]*100+KEYValues[4]*10+KEYValues[6];
    Month = KEYValues[8]*10+KEYValues[10];
    Day =  KEYValues[12]*10+KEYValues[14];
    return(Year);           
}
//    
//*******按键子函数************//
unsigned int KeyDown()
{
    char a=0;
    P3=0x0f;
    if(P3!=0x0f)//读取按键是否按下
    {
        delay(10);//延时10ms进行消抖
        if(P3!=0x0f)//再次检测键盘是否按下
        {   
            //测试列
            P3=0X0F;
            switch(P3)
            {
                case(0X07): KEYValue=0;break;
                case(0X0b): KEYValue=1;break;
                case(0X0d): KEYValue=2;break;
                case(0X0e): KEYValue=3;break;
            }
            //测试行
            P3=0XF0;
            switch(P3)
            {
                case(0X70): KEYValue=KEYValue;break;
                case(0Xb0): KEYValue=KEYValue+4;break;
                case(0Xd0): KEYValue=KEYValue+8;break;
                case(0Xe0): KEYValue=KEYValue+12;break;
            }
            while((a<50)&&(P3!=0xf0))     //检测按键松手检测
            {
                delay(10);
                a++;
            }
        }
    }
    return(KEYValue);
}
void miaobiao(void) interrupt 3
{
    TH1 = 0x3C;      //  (65536 - X)*1us = 50000us    x = 15536  
    TL1 = 0xB0;

    Int_Count++;  // 50ms  +1
}


//*******自定义延时子函数************//
void delay(unsigned int i)           
{
    unsigned int j;
    for(i; i > 0; i--)             //循环i*j次 机器在这里执行需要一段时间 也就达到了延时效果
        for(j = 100; j > 0; j--);
}


void Timer_Ini(void)
{
    TMOD = 0x10;                                                                                                           
    TH1 = 0x3C;      //  (65536 - X)*1us = 50000us    x = 15536  
    TL1 = 0xB0;
    EA = 1;
    ET1 = 1;
    TR1 = 1;
}

void Ring(void)
{
    SPK = ~SPK;
    delay(2);
}
//*******显示作者学号************//
void DisplayID()
{
         while(1)
         {
         temp[0] = id[0];
         temp[1] = id[1];
         temp[2] = id[2];
         temp[3] = id[3];
         temp[4] = id[4];
         temp[5] = id[5];
         temp[6] = id[6];
         temp[7] = id[7];

         for(i=0;i<8;i++)
         {
            P1 = Disp_Bit[i];  //第i个数码管位选    1011 1111   0xbf
            P0 = Disp_Code[temp[i]];     //第i个数码管的编码
            delay(2);
          }
        if(P3!=0x0f)//读取按键是否按下
        {
            break;
        }
        if(Int_Count>=25) //判断秒数增加  
        {
            for(i=0;i<17;i++)
         {
         id[i]=id[i+1];
         }    
            Int_Count = 0; //重置计数
        }

         }

}
//*******根据日期计算星期************//
void iWeek()
{
    int c,s;
    if (Month==1) c=Day;
    else if (Month==2) c=31+Day;
    else if (Month==3) c=31+28+Day;
    else if (Month==4) c=31+28+31+Day;
    else if (Month==5) c=31+28+31+30+Day;
    else if (Month==6) c=31+28+31+30+31+Day;
    else if (Month==7) c=31+28+31+30+31+30+Day;
    else if (Month==8) c=31+28+31+30+31+30+31+Day;
    else if (Month==9) c=31+28+31+30+31+30+31+31+Day;
    else if (Month==10) c=31+28+31+30+31+30+31+31+30+Day;
    else if (Month==11) c=31+28+31+30+31+30+31+31+30+31+Day;
    else if (Month==12) c=31+28+31+30+31+30+31+31+30+31+30+Day;
    if (Month>2)
    {if (Year%100==0) {if (Year%400==0) c=c+1;}
    else if (Year%4==0) c=c+1;}
    s=(Year-1)*365+(Year-1)/4-(Year-1)/100+(Year-1)/400+c+1;
    week=s%7;
    if(week==0) week=7;
}
点赞

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注