基于数码管的简单时钟系统

  • 主要实现:能够在数码管上显示时,分,秒;
    设置闹钟(蜂鸣器);
    利用51单片机的定时器功能进行计时。
    说明:在程序的编写过程中无法实现减一的操作,没按一次减一的键总是不止一次地减一。这个问题尚未解决,详情见附录的程序部分。希望各路大神看到了能指点一二,在此不胜感激。
  • 系统仿真图:
    仿真图
  • 程序如下:
#include<reg51.h>    //头文件
#define uchar unsigned char     //宏定义 之后用uchar代替unsigned char 这里指无符号字符
#define uint unsigned int      //宏定义 同上 无符号整数
sbit beep=P0^0;
uchar dat[]={0,0,10,0,0,10,2,1};   //定义初始化显示时间数组
uchar dat1[]={0,0,10,0,0,10,0,0};    //定义初始化闹钟设定值数组,本程序中闹钟只设定到分
uchar dis_bit[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};   //数码管位选
uchar code SEG7[11]={0xC0,/*0*/0xF9,/*1*/0xA4,/*2*/0xB0,/*3*/0x99,/*4*/0x92,/*5*/0x82,/*6*/0xF8,/*7*/
                       0x80,/*8*/0x90,/*9*/0xBF,/*-*/};   //共阴极数码管字段码

uchar  key_code[]= {           /*列检测时按键按下时key的可能值,通过对这些值的判断也就可以知道具体按键的位置*/
   0x7e,0x7d,0x7b,0x77,        /*当列中的最高位P2.7为0时,这一列四个按键按下时(即对应行值变为0)的key的值,对应的键值为0,1,2,3*/
   0xbe,0xbd,0xbb,0xb7,        /*当列中的P2.6为0时,这一列四个按键按下时(即对应行值变为0)的key的值,对应的键值为4,5,6,7*/
   0xde,0xdd,0xdb,0xd7,        /*当列中的P2.5为0时,这一列四个按键按下时(即对应行值变为0)的key的值,对应的键值为8,9,A,B*/
   0xee,0xed,0xeb,0xe7         /*当列中的P2.4为0时,这一列四个按键按下时(即对应行值变为0)的key的值,对应的键值为C,D,E,F*/
                   };
uchar code ksp[4]={0x7f,0xbf,0xdf,0xef};  //确定列的前提下(分别给每列置零)进行行检测

uint tcount,t_beep;
uchar flag=0;   //闹钟切换标志位,
uchar flag_beep=0; //蜂鸣器响标志位,=1表示蜂鸣器响 
/*flag=0,设定闹钟;flag=1,显示正常时间*/
struct time{uint second;uint minute;uint hour;}time1;   //定义名为time的结构体,变量名time1
uchar n,i,k;

void delay(n)    //延时函数
  {while(n--)
    {
      for(i=110;i>0;i--);
    } 
   }

  void display(void)      //数字显示
{
  if(flag==0)          //显示正常时间
  {  
     for(k=0;k<8;k++)
     {
      P3=dis_bit[k];
      P2=SEG7[dat[k]];     //p2接数码管a-g,p3接数码管1-8,控制动态扫描输出
      delay(5);
      P3=0X00;
      }
  }
  if(flag==1)       //显示闹钟设定时间
  {
     for(k=0;k<8;k++)
     {
      P3=dis_bit[k];
      P2=SEG7[dat1[k]];     //p2接数码管a-g,p3接数码管1-8,控制动态扫描输出
      delay(5);
      P3=0X00;              //消影
      }
  }
}

uchar keypad_scan()
{
    uchar key,temp=0;
    P1=0xf0;
    if(P1!=0xf0)
    {
       delay(10);
       if(P1!=0xf0)
       {
              do{
                 for(i=0;i<4;i++) //检测四列,按键必定在这四列之中
                 {
                       P1=ksp[i];     //重新给P2口赋值,此时列已经确定了
                       if(P1!=ksp[i])   //某一行值变为0,P2口的值发生改变
                       {
                            delay(10);      //消抖,按键抖动
                            key=P1;
                            if(key!=ksp[i])  //再次确认四行中有某行变为0
                            {
                                  while(temp!=ksp[i])
                                  {P1=ksp[i];temp=P1;display();}
                                  return(key);    //此时的key值既包含了行值信息又包含了列值信息。
                            }
                        }
                  }
                }while(1);
      }
    }
}

uchar gotkey()
{
   uchar temp;
   temp=keypad_scan();         
   for(i=0;i<16;i++)
   {
      if(temp==key_code[i])   //查表确定键盘号
            return(i);
   }
}

 void keyscan(void)    //时间调整函数
{  uchar keynum;
   keynum=gotkey();
   EA=0;     //中断开关。=0关中断
   if(keynum==0)    //开始设定闹钟时间
   {
       flag=1;
       TR0=0;
    }
   if(keynum==1)    //暂停功能触发,停止计时,便于调整时间
   {
       flag=0;
       TR0=0;ET0=0;  //ET0为定时器T0的中断控制位。=0禁止中断;TR0运行控制位,位于TCON内部,=1定时器可能工作
    }
   if(keynum==2)
   {  
       if(flag==0)    //时钟调整每次加1
       {
          dat[6]++;
          if((dat[7]==2)&&(dat[6]>3))       
          {
             dat[7]=0; 
             dat[6]=0;
           }
          if(dat[6]>9)
          { 
             dat[6]=0;
             dat[7]++;
             if(dat[7]>2)
             {
                dat[7]=0;
             }
          }    
       }
       if(flag==1)   //闹钟时钟定时
       {
          dat1[6]++;
          if((dat1[7]==2)&&(dat1[6]>3))     
          {
             dat1[7]=0; 
             dat1[6]=0;
          }
          if(dat1[6]>9)
          {
              dat1[6]=0;
              dat1[7]++;
              if(dat1[7]>2)
              {
                dat1[7]=0;
              }
          } 
       }
   }    
   if(keynum==3)
   { 
    if(flag==0)   //分钟调整每次加一
    {
       dat[3]++;
       if(dat[3]>=9)
       {
           dat[4]++;
           dat[3]=0;
        if(dat[4]>5)
        {
           dat[4]=0;
        }
       } 
    }
    if(flag==1)   //闹钟分钟定时
    {
       dat1[3]++;
       if(dat1[3]>9)
       {
          dat1[4]++;
          dat1[3]=0;
          if(dat1[4]>5)
          {
              dat1[4]=0;
          }
       }
     }
   }      
     if(keynum==4)      //暂停结束,显示正常时间;正常情况按下时无影响
     { 
        flag=0;
        TR0=1;ET0=1;     
     }
     if(keynum==5)
     {
        dat1[0]=0;
        dat1[1]=0;
        dat1[3]=0;
        dat1[4]=0;
        dat1[6]=0;
        dat1[7]=0;
     }
/*   if(keynum==6)               
     {  
       if(flag==0)         //时钟减一
       {
         if(dat[6]!=0)
          {  dat[6]=dat[6]-1; }
         else
         {
            if((dat[6]==0)&&(dat[7]!=0))
            {
               dat[7]=dat[7]-1;
               dat[6]=9;
            }
            else
            {
               dat[6]=3;
               dat[7]=2;
            }
         }
       }
       if(flag==1)         //闹钟时钟减一
       {
         if(dat1[6]!=0)
            dat1[6]=dat1[6]-1;
         else
         {
            if((dat1[6]==0)&&(dat1[7]!=0))
            {
               dat1[7]=dat[7]-1;
               dat1[6]=9;
            }
            else
            {
               dat1[6]=3;
               dat1[7]=2;
            }
         }
       }
     }
     if(keynum==7)
     {
        if(flag==0)        //分钟减一
       {
         if(dat[3]!=0)
            dat[3]=dat[3]-1;
         else
         {
            if((dat[3]==0)&&(dat[4]!=0))
            {
               dat[4]=dat[4]-1;
               dat[3]=9;
            }
            else
            {
               dat[3]=9;
               dat[4]=5;
            }
         }
       }
       if(flag==1)         //闹钟分钟减一
       {
         if(dat1[3]!=0)
            dat1[3]=dat1[3]-1;
         else
         {
            if((dat1[3]==0)&&(dat1[4]!=0))
            {
               dat1[4]=dat1[4]-1;
               dat1[3]=9;
            }
            else
            {
               dat1[3]=9;
               dat1[4]=5;
            }
         }
       }
     }        */
    EA=1;   //中断开关,开中断
}    

void init(void)     //初始化函数
{
    TMOD = 0x11;    //TMOD特殊功能寄存器。控制两个定时器T1,T0,这里=00010001,T1T0处于工作方式1,定时开关仅由TR0控制
    TH0 = 0xDB;   //预置数计时,转为十进制56319,到65536结束。计时约10ms
    TL0 =0xFF;
    ET0=1; 
    TR0=1;
    tcount=0;
    EA = 1;
    beep=1;
    t_beep=0;
    flag=0;
    flag_beep=0;
}

void main()
{
    init();
    delay(10);
    while(1)    //只要条件为真就一直循环。
      {
       display();
       keyscan();
       if((dat[7]==dat1[7])&&(dat[6]==dat1[6])&&(dat[4]==dat1[4])&&(dat[3]==dat1[3])&&(dat[1]==dat1[1])&&(dat[0]==dat1[0])) 
       /*以上条件同时成立*/
       {  
           flag_beep=1;     //当正常时间到达设定时间时,将蜂鸣器响标志置为1
       }
       if(flag_beep)
       {
          if(t_beep%2==0)
          { beep=0;delay(5);}
          beep=1;   
        }
      }
   }

void timer_0() interrupt 1 
{  
   ET0=0;     //T0禁止中断
   TR0=0;
   TH0 = 0xDB;
   TL0 = 0xFF;
   TR0=1;
   tcount++;
   if(tcount==100)    //定时器是否满1秒
   {
        time1.second++;
        t_beep++;
        if(t_beep==60)       //蜂鸣器持续响60s
        {
           flag_beep=0;
           t_beep=0;
        }
        tcount=0;
        dat[0]=(time1.second)%10;
        dat[1]=(time1.second)/10;   //显示秒
        if(time1.second>59)
        {   
           dat[0]=0;
           dat[1]=0;
           time1.second=0;
           time1.minute++;
           dat[3]=(time1.minute)%10;
           dat[4]=(time1.minute)/10;   //显示分
           if(time1.minute>59)
           { 
              dat[3]=0;
              dat[4]=0;
              time1.minute=0;
              time1.hour++; 
              dat[6]=time1.hour%10;     //显示小时
              dat[7]=time1.hour/10;
              if(time1.hour>23)
              { 
                  dat[6]=0;
                  dat[7]=0;
                  time1.hour=0; 
               }
            }
        } 
   }
   ET0=1;
}

本设计相关工程文件和仿真文件见:基于数码管的简单时钟系统

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值