⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shizhongxiugai_v1.c

📁 89c51的数字钟程序
💻 C
字号:
#include <reg51.h>
#include <absacc.h>

/**************在设置模式下对秒分时的宏定义*****************/
#define SECOND 0   /*对应数码管右边两位*/
#define MINUTE 1   /*对应数码管中间两位*/
#define HOUR 2     /*对应数码管左边两位*/

/********************定义三种工作模式***********************/
#define CLOCK clockstr /*时钟模式*/
#define DATE datestr   /*日期模式*/
#define TIMER timerstr /*秒表模式*/

/****************以下是所有子函数的声明*********************/
void sys_init(void);                    /*系统的初始化程序*/
void display(void);   /*动态刷新一次数码管子程序*/
void clockplus(void);   /*时间加1S对分时日月年进位的子程序*/
void timerplus(void);   /*秒表走时加1/100秒子程序*/
void update_clockstr(void);  /*更新时间显示编码*/
void update_datestr(void);   /*更新日期显示编码*/
void update_timerstr(void);  /*更新秒表时间的显示编码*/
void delay(int);    /*延时子程序*/
void update_dispbuf(unsigned char *);  /*更新显示缓冲区*/
void getkeycode(void);  /*获取键值子程序*/
unsigned char getmonthdays(unsigned int,unsigned char);/*计算某月的天数子程序*/

/*功能键功能子函数*/
void Akey(void);    /*当前设置位+1 开关秒表*/
void Bkey(void);    /*当前设置位-1*/
void Ckey(void);    /*设置位选择  秒表清零*/
void Dkey(void);    /*切换三种工作模式*/

/**********************全局变量声明部分*********************/
unsigned char led[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};/*从0~9的LED编码*/

struct{        /*时间结构体变量*/
 unsigned char s;
 unsigned char m;
 unsigned char h;
 }clock={30,59,23};

struct{                                 /*日期结构体变量*/
        unsigned char year;
        unsigned char month;
        unsigned char day;
        }date={7,1,1};

struct{                                 /*秒表时间结构体变量*/
        unsigned char ms;
        unsigned char s;
        unsigned char m;
        }timer={0,0,0};

sfr p0=0x80;
sfr p1=0x90;
sfr p2=0xa0;
sbit p10=P1^0;
sbit p11=P1^1;
sbit p12=P1^2;
sbit p13=P1^3;

unsigned char dispbuf[6]; /*显示缓冲区数组*/
unsigned char clockstr[6];/*时间显示的数码管编码数组*/
unsigned char datestr[6]; /*日期显示的数码管编码数组*/
unsigned char timerstr[6];/*秒表显示的数码管编码数组*/

unsigned int itime=0,idot=0;/*定时器0中断计数,秒表小数点闪烁控制*/
unsigned char itime1=0;   /*定时器1中断计数*/

bdata bit IsSet=0;  /*设置模式标志位 0:正常走时 1:设置模式*/
unsigned char SetSelect; /*在设置模式IsSet=1时,正在被设置的位*/
unsigned char *CurrentMode; /*标志当前正设置的功能,如CurrentMode=CLOCK等*/

void main(void)
{
    sys_init();
    while(1)
     {
      while(p10&&p11&&p12&&p13==1) /*检测是否有键按下,无则一直进行LED的刷新显示*/
            display();
      getkeycode();  /*有键按下时得到键值,并送入键值处理程序*/
      display();
     }
}

void sys_init(void)
{p1=0xff;     /*写1以便读按键*/
 p2=0xff;     /*LED全灭*/
 TMOD=0x22;  /*定时器0和1都设置为工作方式2,基准定时250×1us=250us=0.25ms*/
 TH0=6;          /*定时器0中断服务用来产生1秒时钟定时及闹钟蜂鸣器蜂鸣脉冲*/
 TL0=6;          /*定时器1中断服务留给秒表使用,产生1/100秒定时*/
 TH1=6;
 TL1=6;
 ET0=1;     /*定时器0允许*/
 ET1=1;     /*定时器1允许*/
 EA=1;      /*cpu允许中断*/
 TR0=1;     /*定时器0开始计时*/
 TR1=0;     /*秒表缺省为停止*/
 update_clockstr();       /*初始化时钟显示编码数组*/
 update_datestr();        /*初始化日期显示编码数组*/
 update_timerstr();       /*初始化秒表显示编码数组*/
 CurrentMode=CLOCK;       /*默认的显示摸式为时钟*/
 update_dispbuf(CurrentMode);        /*初始化显示缓冲数组*/
 display();
}

void timer0(void) interrupt 1 using 1  /*定时器0中断服务器,用来产生1秒定时*/
{
 itime++;
 if(itime==2000)
  {
   if(IsSet)  /*在设置模式下,对正在设置的位闪烁显示*/
    {
     dispbuf[SetSelect*2]=0x80;  /*对正在设置的位所对应的显示缓冲区元素赋0,使LED灭,只显示小数点*/
     dispbuf[SetSelect*2+1]=0;
    }
  }
 if(itime==4000)   /*两千次计数为1S  4000×0.25ms=1s*/
  {
   itime=0;   /*定时1s时间到,软计数清零*/
   clockplus();   /*时间结构体变量秒数加1 */
   update_clockstr();  /*更新时间显示编码数组 */
   update_datestr();   /*更新日期显示编码*/
   if(CurrentMode!=TIMER) update_dispbuf(CurrentMode);
  }
}

void timer1(void) interrupt 3 using 2    /*定时器1中断服务器,用来产生1/100秒定时*/
{
 idot++;
 if(++itime1==40)       /*40*0.25ms=10ms*/
  {
   itime1=0;
   timerplus();
   update_timerstr();
   if(CurrentMode==TIMER) update_dispbuf(CurrentMode);
   else
    {
     if(idot<2000)                  /*闪烁显示小数点*/
      {
       dispbuf[2]=dispbuf[2]|0x80;
       dispbuf[4]=dispbuf[4]|0x80;
      }
     else
      {dispbuf[2]=dispbuf[2]&0x7f;  /*关闭小数点的显示*/
       dispbuf[4]=dispbuf[4]&0x7f;
      }
    }
  }
 if(idot==4000) idot=0;
}

void clockplus(void)  /*时间加1s判断分,时,日,月,年子函数*/
{
 if(++clock.s==60)  /*秒位判断*/
 {
  clock.s=0;
  if(++clock.m==60) /*分位判断*/
  {
   clock.m=0;
   if(++clock.h==24) /*时位判断*/
   {
    clock.h=0;
    if(++date.day==(getmonthdays(date.year,date.month)+1))
     {
      date.day=1;
      if(++date.month==13)
      {date.month=1;
       if(++date.year==100) date.year=0;
      }
     }
   }
  }
 }
}

/*秒表功能子模块*/
void timerplus()        /*秒表1/100秒位加1,判断秒、分子程序*/
{
 if(++timer.ms==100)
 {
  timer.ms=0;
  if(++timer.s==60)
   {
    timer.s=0;
    if(++timer.m==60) timer.m=0;
   }
 }
}

void update_clockstr(void) /*更新时钟显示代码数组clockstr*/
{
 clockstr[0]=led[clock.s%10];  /*给元素0赋相应数码管显示编码,编码序号是秒数的个位*/
 clockstr[1]=led[(int)(clock.s/10)]; /*给元素1赋相应数码管显示编码,编码序号是秒数的十位*/
 clockstr[2]=led[clock.m%10];  /*以下类推*/
 clockstr[3]=led[(int)(clock.m/10)];
 clockstr[4]=led[clock.h%10];
 clockstr[5]=led[(int)(clock.h/10)];
}

void update_datestr(void)       /*更新日期显示代码数组datestr*/
{
 datestr[0]=led[date.day%10];
 datestr[1]=led[(int)(date.day/10)];
 datestr[2]=led[date.month%10];
 datestr[3]=led[(int)(date.month/10)];
 datestr[4]=led[date.year%10];
 datestr[5]=led[(int)(date.year/10)];
}

void update_timerstr(void)      /*更新秒表显示代码数组timerstr*/
{
 timerstr[0]=led[timer.ms%10];
 timerstr[1]=led[(int)(timer.ms/10)];
 timerstr[2]=led[timer.s%10];
 timerstr[3]=led[(int)(timer.s/10)];
 timerstr[4]=led[timer.m%10];
 timerstr[5]=led[(int)(timer.m/10)];
}

void display(void)        /*刷新显示六位LED一次*/
{unsigned char i;
 for(i=0;i<6;i++,p2=0xff)
 {p0=dispbuf[i];
  switch(i)
  {case 0: p2=0xfe;delay(50);break;
   case 1: p2=0xfd;delay(50);break;
   case 2: p2=0xfb;delay(50);break;
   case 3: p2=0xf7;delay(50);break;
   case 4: p2=0xef;delay(50);break;
   case 5: p2=0xdf;delay(50);break;
   default: break;
  }
 }
}

/*void update_dispbuf(unsigned char *str)    /*更新显示缓冲区子函数,参数为要用来更新缓冲区的源字符数组的首地址*/
/*{if(strcmp(str,CLOCK)==0)
    {   dispbuf[0]=clockstr[0]; /*将要更新的源字符数组内容COPY至dispbuf数组,用作显示缓冲区*/
/*        dispbuf[1]=clockstr[1];
        dispbuf[2]=clockstr[2]|0x80; /*默认把时位和分位后面的小数点显示出来,根据需要再取舍*/
/*        dispbuf[3]=clockstr[3];
        dispbuf[4]=clockstr[4]|0x80;
        dispbuf[5]=clockstr[5];
    }
 else if(strcmp(str,TIMER)==0)
	{dispbuf[0]=timerstr[0];
         dispbuf[1]=timerstr[1];
         dispbuf[2]=timerstr[2]|0x80;
         dispbuf[3]=timerstr[3];
         dispbuf[4]=timerstr[4]|0x80;
         dispbuf[5]=timerstr[5];
	}
      else if(strcmp(str,DATE)==0)
            {dispbuf[0]=datestr[0];
             dispbuf[1]=datestr[1];
             dispbuf[2]=datestr[2]|0x80;
             dispbuf[3]=datestr[3];
             dispbuf[4]=datestr[4]|0x80;
             dispbuf[5]=datestr[5];
            }
} */

void update_dispbuf(unsigned char *str)    /*更新显示缓冲区子函数,参数为要用来更新缓冲区的源字符数组的首地址*/
{
        dispbuf[0]=str[0]; /*将要更新的源字符数组内容COPY至dispbuf数组,用作显示缓冲区*/
        dispbuf[1]=str[1];
        dispbuf[2]=str[2]|0x80; /*默认把时位和分位后面的小数点显示出来,根据需要再取舍*/
        dispbuf[3]=str[3];
        dispbuf[4]=str[4]|0x80;
        dispbuf[5]=str[5];
}

void delay(int i)  /*延时子函数*/
{
  while(i--);
}

void getkeycode(void) /*键盘扫描子程序,返回获得的键码*/
{
 display();              /*用刷新数码管显示的时间去抖*/
 if(p10==0) Akey();       /*对当前设置位进行加一操作,如果设置秒位,则给秒位清零,秒表模式下启闭走时*/
 else if(p11==0) Bkey();  /*对当前设置位进行减一操作,如果设置秒分,则给秒位清零,类比Akey()函数*/
       else if(p12==0) Ckey(); /*正常走时模式和设置模式的切换*/
             else if(p13==0) Dkey(); /*工作状态切换:时钟、日期、秒表*/
 update_dispbuf(CurrentMode);
}

unsigned char getmonthdays(unsigned int year,unsigned char month)/*得到某月的天数*/
{
 unsigned char days;
 switch (month)
 {
  case 4:
  case 6:
  case 9:
  case 11:days=30;
          break;
  case 2: if(year%4==0) days=29;
   else days=28;
          break;
  default:days=31;
          break;
 }
 return days;
}

/*功能键子函数部分*/
void Akey(void) /*对当前设置位进行加一操作,如果设置秒位,则给秒位清零,秒表模式启/停秒表*/
{
 if(CurrentMode==TIMER)  /*秒表模式下启闭走时*/
  {TR1=!TR1;
   return;
  }
 if(!IsSet) return;     /*如果不是设置模式退出*/
 switch (SetSelect)
 {
  case SECOND:if(CurrentMode==CLOCK)
               {
                clock.s=0;  /*如果当前被设置位是秒位,则清零秒位*/
                update_clockstr();
               }
              if(CurrentMode==DATE)
               {
                if(++date.day==(getmonthdays(date.year,date.month)+1)) date.day=1;
                update_datestr();
               }
              break;
  case MINUTE:if(CurrentMode==CLOCK)
               {
                if(++clock.m==60) clock.m=0; /*如果当前被设置分位,则分位加1*/
		            update_clockstr();
               }
              if(CurrentMode==DATE)
               {
                if(++date.month==13) date.month=1;
                update_datestr();
               }
              break;
  case HOUR:  if(CurrentMode==CLOCK)
               {
                if(++clock.h==24) clock.h=0; /*如果当前被设置时位,则时位加1*/
                update_clockstr();
               }
              if(CurrentMode==DATE)
               {
                if(++date.year==100) date.year=0;
                update_datestr();
               }
              break;
    default:   break;
 }
}

void Bkey(void)  /*对当前设置位进行减一操作,如果设置秒分,则给秒位清零,类比Akey()函数*/
{
        if(!IsSet) return;
 switch (SetSelect)
 {
  case SECOND:if(CurrentMode==CLOCK)
               {
                clock.s=0;
                update_clockstr();
               }
              if(CurrentMode==DATE)
               {
                if(--date.day==0x00) date.day=getmonthdays(date.year,date.month);
                update_datestr();
               }
              break;
  case MINUTE:if(CurrentMode==CLOCK)
               {
                if(--clock.m==0xff) clock.m=59;
                update_clockstr();
               }
              if(CurrentMode==DATE)
               {
                if(--date.month==0x00) date.month=12;
                update_datestr();
               }
       break;
  case HOUR:  if(CurrentMode==CLOCK)
               {
                if(--clock.h==0xff) clock.h=23;
                update_clockstr();
               }
              if(CurrentMode==DATE)
               {
                if(--date.year==0xffff) date.year=99;
                update_datestr();
               }
	      break;
  default:    break;
 }
}

void Ckey(void) /*正常走时模式和设置模式的切换*/
{
  if(CurrentMode==TIMER)
	{
        TR1=0;          /*初始化定时器1设置,停止秒表记时*/
        TH1=6;
        TL1=6;
        timer.ms=0;     /*初始化秒表数组*/
        timer.s=0;
        timer.m=0;
        update_timerstr();
	}
  else
	{
     if(IsSet==0) /*在非秒表模式下,第一次按下C键进入设置模式,设置时位*/
	 {
	  IsSet=1; /*置位标志位,进入设置模式 */
	  SetSelect=HOUR;
	  return;
	 }   /*第二次按C键设置分位,第三次按键设置秒位,第四次按键完成退出设置*/
     if(SetSelect==SECOND) /*按到第四次,即设置完秒位后,将标志位IsSet置0,完成设置*/
	 {
      IsSet=0; /*复位标志位,进入正常走时模式*/
      return;
	 }
     if(SetSelect>0) SetSelect--;    /*设置位的标志变量SetSelect=2:时位 1:分位 0:秒位*/
	}
}

void Dkey(void) /*工作状态切换:时钟、日期、秒表*/
{
        if(CurrentMode==CLOCK)         /*切换至日期,同时关闭设置模式*/
		    { CurrentMode=DATE;
		      IsSet=0;
          return;
        }
        if(CurrentMode==DATE)          /*切换至秒表,同时关闭设置模式*/
        { CurrentMode=TIMER;
          IsSet=0;
          return;
        }
        if(CurrentMode==TIMER)         /*切换至时钟*/
        {
          CurrentMode=CLOCK;
          return;
        }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -