C51的日历时钟程序

发布者:AngelicWhisper最新更新时间:2016-11-24 来源: eefocus关键字:c51  日历时钟 手机看文章 扫描二维码
随时随地手机看文章

//程序功能:日历,时钟,温度显示(测温代码暂没加上,加上后程序将超过4k,注意芯片型号选用),温度传感器采用18B20
// 日历与时钟,温度分时切换显示,采用8位共阳数码管
// 数据输出P1, 位码驱动P2
// 也可以采用12864LCD显示,该程序暂时没写.
#include  
#include  
#define unchar unsigned char
#define unint unsigned int
unchar code dispcode[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,
                        0Xbf,0x9c,0xc6,0x7f,0xff};      //数码管字形表,0-9,-,o,C,.,灭
unchar code rili1997code[]={0x2,0x5,0x5,0x1,0x3,0x6,0x1,0x4,0x0,0x2,0X5,0x0};  //1996年12个月的月份星期校正码
unchar timecnt=19; //定时中断计数器          
unchar timeadd1=0;    //时间加1判断
unchar newday=0;      //日期加1判断
unchar week;  //星期
unchar data date[]={9,12,9};
unchar data time[]={11,59,55};
unchar data wendu[]={14,19,116};  //wendu[0]=10为负,显示-;wendu[0] =14为正,符号位不显示, 原理参考数码管字形表
                                 //wendu[1]是整数温度值,wendu[2]/10是"°"显示,wendu[2]/10+1显示C,wendu[2]%110是小数点后的温度值   
unchar t=150;    //延时常数
unchar cnt=0;    //显示控制计数器
//#define SSL  0x7f    //秒低位段码地址
//#define SSH  0XBF    //秒高位段码地址
//#define _L   0XDF    //8位数码管显示,分钟与秒之间的-分隔符
//#define MML  0XEF    //以下同
//#define MMH  0XF7
//#define _H   0XFB    //8位数码管显示,小时与分钟之间的-分隔符
//#define HHL  0XFD
//#define HHH  0XFE
sbit timeset=P3^2;   //时间调整键
sbit dateset=P3^3;   //日历调整键
sbit add=P3^4;   //加调整
sbit dec=P3^5;   //减调整


//日期加1函数
//当日期有进位时调用,判断年,月,日的最大值
void dateadd1(unchar i)

  {  unchar j=0;
 switch(i)
 { case 0:if(date[0]==99)     //年采用低2位表示
             date[0]=0;
   else 
            date[0]++;break;
   case 1:if(date[1]==12)
             date[1]=1;
    else 
       date[1]++;break;
   case 2:
         switch(date[1])
        {case 4:      //4,6,9,11月的最大天数是30
        case 6: 
         case 9:
         case 11:if(date[2]==30)
                         {date[2]=1; 
              j++;    //j++表示月份加1,以下同
             }   
              else  
              {date[2]++; }
               break;
        case 1:     //1,3,5,7,8,10,12月的最大天数是31
        case 3:
        case 5:
        case 7:
      case 8:
      case 10:
      case 12: if(date[2]==31)
                             {date[2]=1;  j++;  } 
                   else
                    date[2]++;  break;

       case 2:if(date[0]%400==0)     //2月份需要判断是否是闰年
                          {if(date[2]==29)     //能被400整除的世纪年是闰年
                       {date[2]=1; j++; }    //闰年2月29天,月份加1
                     else
                     date[2]++;break; 
                     }   
                          else
                       {if(date[0]%4==0)     //非世纪年,能被4整除是闰年
                          {if(date[2]==29)
                         {date[2]=1;j++; }
                          else
                          date[2]++; break;
                       }
                     else
                         {if(date[2]==28)     //非闰年2月28天
                         {date[2]=1;j++;}
                       else  
                       date[2]++; break;
                      }
                    }   
        default:break;
       
    }
    if(j)
     { if(date[1]==12)   //如果进位的月份是12月,置月份date[1]为1
          date[1]=1;
    else
       date[1]++;

     }
}  }

}

void datedec1(unchar i)
{   unchar j=0;
    switch(i)
 { case 0: if(date[0]==0)
              date[0]=99;
     else
           date[0]--;break;
   case 1:if(date[1]==0)
             date[1]=12;
    else 
       date[1]--;break;
   case 2:
          switch(date[1])
    { case 4:      //4,6,9,11月的最大天数是30
    case 6: 
     case 9:
      case 11:if(date[2]==0)
                          date[2]=30; 
           else  
              date[2]--;
               break;
      case 1:     //1,3,5,7,8,10,12月的最大天数是31
      case 3:
       case 5:
        case 7:
      case 8:
      case 10:
      case 12: if(date[2]==0)
                             date[2]=31;   
                   else
                    date[2]--;  break;

       case 2:if(date[0]%400==0)     //2月份需要判断是否是闰年
                          {if(date[2]==0)     //能被400整除的世纪年是闰年
                       date[2]=29;     //闰年2月29天,月份进位
                     else
                     date[2]--;break; 
                     }   
                          else
                       {if(date[0]%4==0)     //非世纪年,能被4整除是闰年
                          {if(date[2]==0)
                         date[2]=29;
                          else
                          date[2]--; break;
                       }
                     else
                         {if(date[2]==0)     //非闰年2月28天
                         date[2]=28;
                       else  
                       date[2]--; break;
                      }
                    }   
        default:break;
       
    }
    
   }
}

void add1(unchar i)   //时间加1函数

if(i) 
  { 
     timeadd1--;
     if(time[2]==59)    //秒加1
       {time[2]=0;
        time[1]++;
      if(time[1]==60) //分加1
        {time[1]=0;
         time[0]++;  
       if(time[0]==24)  //小时加1
         { time[0]=0;
     newday++;
    }
   }
  }
   else
    time[2]++; 
 }
//if(newday)
//   {
//     dateadd1(newday);
//    }  
 }

//延时函数
void delay(unchar x)   
{unsigned char i=0;
   while(i  i++;
}
//显示函数:
//(1)显示时间,格式:HH(2位)-(1位)MM(2位)(空1位) SS(2位)(共8位), 
//(2)显示日历,格式:月(2位)-(1位)日(2位)(空2位) 星期(1位), 
//(3)显示日期(只在调整日期时出现),格式:年-月 日       
//(4)显示温度  
//(5)显示过程:30秒的前25秒显示时间,后5秒显示日历
void display(unchar x,unchar y,unchar z,unchar r,unchar k)      
{   unchar  a=150;                                    
   cnt++;                                       
  if(cnt==300)             
     cnt=0;           //函数使用说明:
      if(((r!=5)&&(r!=2))||(cnt>a)||(r==6))       //显示函数x,y,z参数,分别对应显示时间的时,分,秒,或显示日期的年,月,日
         {if(r==6)
       P1=dispcode[z/10+1];
    else
       P1 =dispcode[z%10];           //或显示日历的,月,日,星期,或温度的正负,温度,oC.   
          P2 =0x7f;//SSL;                          //k:星期控制参数,当显示日历时,k=1,星期显示一位数,k为其他值时,不影响其他显示方式
          delay(t);           //r:显示控制参数,当r取不同值时,闪动显示待调整项,只有闪动项才可以用键盘调整其值.
   if( k!=1)           //当r分别取0,1,2,时,对应的hh,mm,ss将闪动,进入调整.r为3,4,5时,分别对应年,月,日闪动调整
        {P1=dispcode[z/10];        //r=6时,为显示温度时,特有的方式
            P2=0xbf;//SSH;                         //
            delay(t);
      }
   }
    if(((r!=4)&&(r!=1))||(cnt>a)||(r==6))
         { if(r==6)
        P1=dispcode[y%10]-0x80;      //用于显示小数点
    else 
        P1 =dispcode[y%10];
          P2=0xef;//MML;                       //
        delay(t);
    if(r==6)       //当温度的高位是0时,不显示
    if(y/10==0)
       P1=dispcode[14];
    
    P1=dispcode[y/10];
          P2=0xf7;//MMH;                       //
          delay(t);
          }

   if((r==6)||((r!=3)&&(r!=0))||(cnt>a))
      {if(r==6)
      P1=0XFF;
    else
       P1 =dispcode[x%10];
     P2=0xfd;//HHL;
           delay(t);
    if(r==6)
       P1=0XFF;
    else
            P1=dispcode[x/10];
         P2=0xfe;//HHH;
         delay(t);
          }
       
    if((r==6)||(cnt>a))                 //r=6可用于温度测量显示控制
        {if(r==6)
     P1=dispcode[wendu[0]];
   else
     P1 =dispcode[10];//dispcode[y%10];
         P2=0xfb;//_H;
         delay(t);
   }
   if(r==6)
   {P1=dispcode[wendu[2]%110];
    P2=0xdf;
    delay(t);
   }
  
 }

void keyscan()       //键盘扫描函数,用于扫描P3.2(timeset),P3.3(dateset),P3.4(add),P3.5(dec)键是否按下
{ unchar i=0,j=0;
if(dateset==0)
     {display(date[0],date[1],date[2],8,0);       //延时
      if(dateset==0)
      while(i<3)
    {   display(date[0],date[1],date[2],i,0);
      if(add==0)
        {display(date[0],date[1],date[2],i,0);
         if(add==0)
         dateadd1(i);
      display(date[0],date[1],date[2],i,0);
      display(date[0],date[1],date[2],i,0);
      display(date[0],date[1],date[2],i,0);
      display(date[0],date[1],date[2],i,0);
      }
      if(dec==0)
      {display(date[0],date[1],date[2],i,0);
       
       if(dec==0)
       datedec1(i);
       display(date[0],date[1],date[2],i,0);
       display(date[0],date[1],date[2],i,0);
       display(date[0],date[1],date[2],i,0);
       display(date[0],date[1],date[2],i,0);
      }
      if(dateset==0)
         {display(date[0],date[1],date[2],i,0);
          if(dateset==0)
        i++;
     display(date[0],date[1],date[2],i,0);
     display(date[0],date[1],date[2],i,0);
     display(date[0],date[1],date[2],i,0);
     display(date[0],date[1],date[2],i,0);
      }
     
     }
   } 
         
if(timeset==0)
     {delay(100);       //短暂延时
      if(timeset==0)
      delay(100);
    
        while(j<3)
      { display(time[0],time[1],time[2],j,0);
      if(add==0)
        {delay(200);
         if(add==0)
        { //delay(200);
     switch(j)
        {case 0:if(time[0]==24)
                  time[0]=0;
        else
         time[0]++;break;
         display(time[0],time[1],time[2],j,0);
      case 1:
      case 2:if(time[j]==60)
                time[j]=0;
        else
           time[j]++;
      default:break;
      } //delay(100);
     // display(time[0],time[1],time[2],j,0);
         }
        }     
      if(dec==0)
      {delay(200);
       if(dec==0)
       switch(j)
       {case 0:if(time[0]==0)
                  time[0]=23;
        else
         time[0]--;break;
         display(time[0],time[1],time[2],j,0);
           case 1:
      case 2:if(time[j]==0)
                time[j]=59;
        else
           time[j]--;
           display(time[0],time[1],time[2],j,0);
      default:break;
     } delay(100);
      }
      if(timeset==0)
         {
         display(time[0],time[1],time[2],j,0);
         //display(time[0],time[1],time[2],j,0);
          if(timeset==0)
        j++;
      }
     
     }
   
    }            
}

 

 

 


void datetoweek(unchar x,unchar y,unchar z,unchar p) //计算指定日期是星期几,x,y,z参数分别为年,月,日;
{if(p) 
  { int year;
     year=1997+x+3;
     dateadd1(2);
  newday--;

 if((year%400)==0)          //p为是否执行该函数条件,即变量newday(由hh进位产生),
   {if(y<3)           //当hh没有进位时,newday=0,不执行该函数 
         {unchar i,j;                               //日期加1,要进行日历调整
      j=rili1997code[y-1];     
      i=(((year-1997)/4+(year-1997)+j)-1); 
      week=(z+i+1)%7;              //
       }
       else
       {unchar  i,j;
        j=rili1997code[y-1];
         i=(((year-1997)/4+(year-1997)+j));
         week=(z+i+1)%7;
          }
   }
  else
      { if(year%4==0)
     {if(y<3)
          {unchar i,j;
           j=rili1997code[y-1];
           i=(((year-1997)/4+(year-1997)+j)-1);
           week=(z+i+1)%7;
           }
            else
           {unchar i,j;
            j=rili1997code[y-1];
            i=(((year-1997)/4+(year-1997)+j));
            week=(z+i+1)%7;
              }
     }
  else
     { unchar i,j;
            j=rili1997code[y-1];
            i=(((year-1997)/4+(year-1997)+j));
            week=(z+i+1)%7;
      }
    }
    }
}

 void displaycontrol() //显示控制函数

  if(time[2]%30<=20)              //30秒的前25秒显示时间,后5秒显示日历
    display(time[0],time[1],time[2],7,0);
  //if((time[2]%30<=25)&&(time[2]%30>20))
  else
    if(time[2]%30<=25)
    display(date[1],date[2],week,8,1);
 // if((time[2]%30<=30)&&(time[2]%30>25))
     else
       display(wendu[0],wendu[1],wendu[2],6,0);
}

void main(void)    //  主函数

   
  TMOD=0x01; 
  TH0=((65535-50000)/256);  //定时器赋初值
  TL0=((65535-50000)%256);
  ET0=1; 
  EA=1;
  TR0=1;
  while(1) 
    {
    keyscan();       //键盘扫描
 add1(timeadd1);   //加1
    datetoweek(date[0],date[1],date[2],newday);
    displaycontrol();          //时间,日历,温度等显示控制
    } 
 }

 void t0 (void)interrupt 1 using 0  //定时中断函数
{

  TH0+=((65536-50000)/256);
  TL0+=((65536-50000)%256);
  timecnt--;
if(timecnt==0)
  { timecnt=19;
     timeadd1++;
   }
}


关键字:c51  日历时钟 引用地址:C51的日历时钟程序

上一篇:Keil C51程序设计中精确延时的总结
下一篇:89C51单片机的P0~P3端口进行输入时为什么要设置为1?

推荐阅读最新更新时间:2024-03-16 15:22

C51单片机存储器类型有哪些?
C51存储器类型有bit sbit data xdata bdata pdata sfr code等,可能不全面有遗漏对应的物理存储器是: bit,即位数据:数据存储器位寻址区,即20H~2FH的范围,共16个字节,16*8=128个位,位地址00h~7fh,连续的。 sbit:特殊功能寄存器中的位数据:只有能够被8整除的那些特殊功能寄存器中的各个位才能被称为sbit,位地址80H~FFH,不连续的,间断的。 data:数据区,对51为00H~7FH共128个字节,对52为00H~FFH,共256个字节,用MOV寻址,前128用直接寻址或寄存器(R0~R7)寻址,后128用R0、R1间接寻址。 xdata:外部数据区,00
[单片机]
C51 蜂鸣器生日快乐代码
#include #define uint unsigned int #define uchar unsigned char sbit beep = P1^5; uchar code SONG_TONE ={212,212,190,212,159,169,212,212,190,212,142,159, 212,212,106,126,159,169,190,119,119,126,159,142,159,0}; uchar code SONG_LONG ={9,3,12,12,12,24,9,3,12,12,12,24, 9,3,12,12,12,12,12,9,3,12,12,12,24,0}; //延时 void Dela
[单片机]
C51延时程序再抛砖原创
看到了个好帖,我在此在它得基础上再抛抛砖! 有个好帖,从精度考虑,它得研究结果是: void delay2(unsigned char i) { while(-i); } 为最佳方法。 分析:假设外挂12M(之后都是在这基础上讨论) 我编译了下,传了些参数,并看了汇编代码,观察记录了下面的数据: delay2(0):延时518us 518-2*256=6 delay2(1):延时7us(原帖写 5us 是错的,^_^) delay2(10):延时25us 25-20=5 delay2(20):延时45us 45-40=5 delay2(100):延时205us 205-200=5 delay2(200):延时405us 405-40
[单片机]
4×4键盘C51单片机程序源码分享
/*MCU:AT89S52*/ #include #include #define uchar unsigned char int key; int del; void Key_Scan(void); /************主程序*************/ void main(void) { void Key_Scan(void); void delay(int); while(1) { Key_Scan(); delay(2000); } } /********矩键查寻键值4*4程序******/ void Key_Scan(void) { uchar readkey; uchar x_temp,y_temp; P
[单片机]
4×4键盘<font color='red'>C51</font>单片机程序源码分享
C51单片机串行口中断服务程序
//出入均设有缓冲区,大小可任意设置。 //可供使用的函数名: //char getbyte(void);从接收缓冲区取一个byte,如不想等待则在调用前检测inbufsign是否为1。 //getline(char idata *line, unsigned char n); //获取一行数据回车结束,已处理backspce和delete,必须定义最大输入字符数 //putinbuf(uchar c);模拟接收到一个数据 //putbyte(char c);放入一个字节到发送缓冲区 //putbytes(unsigned char *outplace,j);放一串数据到发送缓冲区,自定义长度 //putstring(unsign
[单片机]
I2C串行总线标准驱动程序(C51)
I2C串行总线标准驱动程序(C51)-万能程序 /*------------------------------------------------------------------------------------------ I2C.c 1.1b ===================================================================================*/ #i nclude reg51.h #i nclude intrins.h unsigned char SystemError; sbit SCL= P1^6; //定义串行时钟线所在口 使用时根据自己
[单片机]
24CXX读写驱动C51程序
/************************** 文件所用资源 1.端口:P0.2,P0.3 2.调用delay_ms函数 **************************/ /************************ 端口定义 ************************/ sbit i2c_dat =P0^2; sbit i2c_clk =P0^3; #define IIC_TIME 10 //IIC操作延时 //========在此设定芯片地址============= #define W_ADD_COM 0xa0 //写字节命令及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 0 #
[单片机]
最简单的4*4矩阵键盘程序 c51
调试通过. key_scan_p2() //定时器,或者主程序扫描 { uchar x,y,z; P2=0x0f; x=P2&0x0f; P2=0xf0; y=P2&0xf0; z=x|y; if(z!=key_value1) key_value1=z; //如果两次结果不同 else { if(key_value1 == 0xff) key_release=0; else { if (key_release==0) //所有按键已经松开了吗? { key_release = (z ^ 0xFF); key_val = z; switch(key
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
热门活动
换一批
更多
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

更多精选电路图
换一换 更多 相关热搜器件
更多每日新闻
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved