单片机大数字万年历电子钟制作 带农历年属性温度

介绍

LCD12864大数字万年历电子钟设计,用了一个多星期时间,经过实物实测,每月时间相差几分钟,这是时钟走时芯片决定的,温度显示还算正常。

图片

万年历图片

单片机板子

代码

#include

#include

//#include 

#include

#define uchar unsigned char

#define uint unsigned int

/******LCD12864通讯端口******/

sbit RS_LCD12864=P2^7;     //定义选择显示类型, 定义数据或指令,1=数据,0=指令

sbit RW_LCD12864=P2^6;    //定义读写信号控制端, 定义读或写??1=读,??0=写

sbit EN_LCD12864=P2^5;    //定义数据锁存信号, 定义使能操作, 1=能,??0=否

#define LCD12864_Databus P0   //定义数据端

#define sc0 0        

#define sc1 1         

uchar DS1302_flag;        //定义DS1302RAM中是否写数的标志位,第一次开机初始化后RAM中写1

sbit CS1=P2^4;    //定义选择芯片右半屏信号

sbit CS2=P2^3;    //定义选择芯片左半屏信号

/*******DS1302时钟端口******/

sbit SCLK=P2^0;     //DS1302时钟口

sbit DATA=P2^1;    //DS1302串口数据

sbit RST=P2^2;    //DS1302的复位口

uchar code Write_RTC_ADDR[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};

uchar code READ_RTC_ADDR[7] ={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};

uchar TIME[7]={0, 0x38, 0x15, 0x25, 0x05, 0x03, 0x22};

//2022年5月25星期3,15:38:00

/***********DS18B20**********/

sbit DQ=P3^7;        //温度探测口

uchar fb;            //文字反白标示

uint tempvalue;     //温度值,此变量若为uchar则温度不正常

uchar Temp_Flag;  //温度正负标志



/***************按键端口************/

sbit  set =P1^0;                 //设置

sbit  key1=P1^1;               //加           

sbit  key2=P1^2;                            //减

sbit  key3=P1^3;                        //蜂鸣开关

sbit  key4=P1^4;                       //背光开关



uchar setflag=0;                   //按键计数,决定调节的日期和时间

sbit  bl=P3^5;                           //背光控制端

sbit  bz=P3^6;                          //蜂鸣控制端

uchar tempa;              //调时

/*********农历部分********/

#define uint unsigned int

char sec,min,hour,day,month,year,week;    //定义全局变量,秒,分,时,日,月,年和星期

bit century;   //世纪位标志,0为20世纪,1为19世纪

uchar sec_count=0;//定义定时计数,当sec_count==20时,秒加一

code uchar table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表

code uchar day_code1[9]={0x0,0x1f,0x3b,0x5a,0x78,0x97,0xb5,0xd4,0xf3};//月份数据表

code uint  day_code2[3]={0x111,0x130,0x14e};

bit c_moon;

data uchar year_moon,month_moon,day_moon;



/*******函数声明********/

//读取数据表中农历月的大月或小月,如果该月为大返回1,为小返回0

bit get_moon_day(uchar month_p,uint table_addr);

void Conversion(bit c,char year,char month,char day);//输入阳历数据,输出阴历数据

void Conver_week();                 //输入BCD阳历数据,输出BCD星期数据

void delay_ms(uint x);



void Lcd12864_BusyChk();

void set_xy(unsigned char x,unsigned char y);



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

* 函数名称    :Conversion

* 功能描述    :输入阳历数据,输出阴历数据(只允许1901-2099年)

* 参数        :参数名称

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

void Conversion(bit c,char year,char month,char day)

{

//c=0 为21世纪,c=1 为19世纪 输入输出数据均为BCD数据

  uchar temp1,temp2,temp3,month_p;

  uint temp4,table_addr;

  bit flag2,flag_y;



  //定位数据表地址

  if(c==0) { table_addr=(year+0x64-1)*0x3; }

  else   { table_addr=(year-1)*0x3; }

  //定位数据表地址完成



  //取当年节日所在的公历月份

  temp1=year_code[table_addr+2]&0x60;

  temp1=_cror_(temp1,5);

  //取当年节日所在的公历月份完成



  //取当年节日所在的公历日

  temp2=year_code[table_addr+2]&0x1f;

  //取当年节日所在的公历日完成



  // 计算当年春年离当年元旦的天数,节日只会在公历1月或2月

  if(temp1==0x1) { temp3=temp2-1; }  

  else  { temp3=temp2+0x1f-1; }

  // 计算当年春年离当年元旦的天数完成



  //计算公历日离当年元旦的天数,为了减少运算,用了两个表

  //day_code1[9],day_code2[3]

  //如果公历月在九月或前,天数会少于0xff,用表day_code1[9],

  //在九月后,天数大于0xff,用表day_code2[3]

  //如输入公历日为8月10日,则公历日离元旦天数为day_code1[8-1]+10-1

  //如输入公历日为11月10日,则公历日离元旦天数为day_code2[11-10]+10-1

  if (month<10){ temp4=day_code1[month-1]+day-1; }

  else         { temp4=day_code2[month-10]+day-1;}

  if ((month>0x2)&&(year%0x4==0)&&(year!=0))

  temp4+=1; //如果公历月大于2月并且该年的2月为闰月,天数加1

  //计算公历日离当年元旦的天数完成



  //判断公历日在节日前还是节日后

  if (temp4>=temp3)

  { //公历日在节日后或就是节日当日使用下面代码进行运算

    temp4-=temp3;

    month=0x1;

    month_p=0x1;  //month_p为月份指向,公历日在节日前或就是节日当日month_p指向首月

    flag2=get_moon_day(month_p,table_addr); //检查该农历月为大小还是小月,大月返回1,小月返回0

    flag_y=0;

    if(flag2==0)temp1=0x1d; //小月29天

    else temp1=0x1e;     //大小30天

    temp2=year_code[table_addr]&0xf0;

    temp2=_cror_(temp2,4);  //从数据表中取该年的闰月月份,如为0则该年无闰月

    while(temp4>=temp1)

    {

      temp4-=temp1;

      month_p+=1;

      if(month==temp2)

          {

        flag_y=~flag_y;

        if(flag_y==0)month+=1;

      }

      else month+=1;flag2=get_moon_day(month_p,table_addr);

      if(flag2==0)temp1=0x1d;

      else temp1=0x1e;

    }

    day=temp4+1;

  }

  else

  {  //公历日在节日前使用下面代码进行运算

    temp3-=temp4;

    if (year==0x0){year=0x63;c=1;}

    else year-=1;

    table_addr-=0x3;

    month=0xc;

    temp2=year_code[table_addr]&0xf0;

    temp2=_cror_(temp2,4);

    if (temp2==0)month_p=0xc;

    else month_p=0xd;

        //month_p为月份指向,如果当年有闰月,一年有十三个月,月指向13,无闰月指向12



    flag_y=0;

    flag2=get_moon_day(month_p,table_addr);

if(flag2==0)

temp1=0x1d;

else

temp1=0x1e;

    while(temp3>temp1)

    {

      temp3-=temp1;

      month_p-=1;

      if(flag_y==0)month-=1;

      if(month==temp2)flag_y=~flag_y;

      flag2=get_moon_day(month_p,table_addr);

      if(flag2==0)temp1=0x1d;

      else temp1=0x1e;

    }

    day=temp1-temp3+1;

  }

  c_moon=c;

//原程序这里又把这得出的值变回BCD码。但根据我后面的程序,我不需要。

//后面用来显示的农历信息的程序分别是disp_t3()和disp_t4()

  year_moon=year;

  month_moon=month;

  day_moon=day;

}



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

* 函数名称    :Conver_week

* 功能描述    :输入BCD阳历数据,输出BCD星期数据(只允许1901-2099年)

* 参数        :  参数名称:        输入/输出?        类型                描述

* 算法:日期+年份+所过闰年数+月较正数之和除7 的余数就是星期,但如果是在

  闰年又不到3 月份上述之和要减一天再除7星期数。余数为0时,为星期天。

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

void Conver_week()

{//century=0 为21世纪,c=1 为19世纪 输入输出数据均为BCD数据

  uchar temp1,temp2;

  temp1=year;

  if (century==0){temp1=temp1+100;}  //如果为21世纪,年份数加100

  temp2=temp1/4;                     //所过闰年数只算1900年之后的

  temp2=temp1+temp2;

  temp2=temp2%7;                     //为节省资源,先进行一次取余,避免数大于255

  temp2=temp2+day+table_week[month-1];

  if (year%0x4==0&&month<3)temp2-=1;

  week=temp2%7;

}





/********************************LCD12864部分*****************************/

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

端口说明:EN_LCD12864:使能端锁存信号。RS_LCD12864:D/I 命令/数据寄存器选择端

          RW_LCD12864:读写信号控制端. define LCD_Data P0

          RS(D/I)=1,表示DB0-DB7显示数据; RS(D/I)=0,表示DB0-DB7显示指令数据

          RW=1,E=1,数据被读到DB7-DB0;RW=0,E=1--0,数据被读到DB7-DB0;数据被

写到IR或DR。

(定义数据端口为 LCD_Data为P0口)

          RST_LCD12864复位端口,不接或接高电平,低电平会导致复位

函数名称:void Lcd12864_BusyChk()

函数功能:忙检测,若忙则等待,最长等待时间为60MS(此判忙函数经过仿真已OK)

入口参数:无

出口参数:无

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

void Lcd12864_BusyChk()

{

      LCD12864_Databus=0x00;

EN_LCD12864=0;

RS_LCD12864=0;

RW_LCD12864=1;

EN_LCD12864=1;

      while(LCD12864_Databus&0x80);  //判断P0.7口

_nop_();

EN_LCD12864=0;

}



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

* 函数名称:  void set_xy(unsigned char x,unsigned char y)

               (仿真时的函数,已OK)

* 功能描述:  设置显示位置! X,Y分别代表横纵坐标!

* 输入参数?: unsigned char x,unsigned char y

*输出参数:  无??

*参数名称:? ?//列地址赋值,?x取值0----64,页面地址赋值,y取值0----8

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



/*void set_xy(unsigned char x,unsigned char y)

{

if (x>=64)

{CS1=1;CS2=0;}              //选择右半屏

else

{CS1=0;CS2=1;}             //选择左半屏

Lcd12864_BusyChk();

RS_LCD12864=0;

RW_LCD12864=0;

LCD12864_Databus=0x40|x; //列地址赋值,x取值0----64

EN_LCD12864=1;

EN_LCD12864=0;

Lcd12864_BusyChk();

RS_LCD12864=0;

RW_LCD12864=0;

LCD12864_Databus=0xb8|y;   //页面地址赋值,y取值0----8

EN_LCD12864=1;

EN_LCD12864=0;

LCD12864_Databus=0xff;

}*/



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

* 函数名称:  void set_xy(unsigned char x,unsigned char y)

               (实物时的函数,已OK)

* 功能描述:  设置显示位置! X,Y分别代表横纵坐标!

* 输入参数?: unsigned char x,unsigned char y

*输出参数:  无??

*参数名称:? ?//列地址赋值,?x取值0----64,页面地址赋值,y取值0----8

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











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

函数名称:void LCD12864_DispYanYueRi(fb)

函数功能:设置日期的时候,选中的参数可以反白显示,右屏第一行显示程序,

由which决定第几个参数黑显,如which==1时,年份黑显.

入口参数:无

出口参数:无

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



void LCD12864_DispYanYueRi(fb)              //显示年月日

{

  if(century)    //如果世纪为1

  {

       Lcd12864_DispChar(0,0,1,0);    //则第1行第1列显示’1”

       Lcd12864_DispChar(1,0,9,0);   //则第1行第2列显示’9”

  }

  else

  {

      Lcd12864_DispChar(0,0,2,0);   //则第1行第1列显示’2”

      Lcd12864_DispChar(1,0,0,0);  //则第1行第2列显示’0”

  }

     Lcd12864_DispChar(2,0,year/10,fb);  //第1行第3列显示年十位数

     Lcd12864_DispChar(3,0,year%10,fb); //第1行第4列显示年个位数

     Lcd12864_DispChar(4,0,11,0);                   //第1行第5列显示第11个数据”-”

     Lcd12864_DispChar(5,0,month/10,fb);   //第1行第6列显示月十位数

     Lcd12864_DispChar(6,0,month%10,fb); //第1行第7列显示月个位数

     Lcd12864_DispChar(7,0,11,0);                        //第1行第8列显示第11个数据”-”                  

     Lcd12864_DispChar(8,0,day/10,fb);   //第1行第9列显示日十位数

     Lcd12864_DispChar(9,0,day%10,fb);  //第1行第10列显示日个位数

}



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

函数名称:void LCD12864_DispShiFenMiao(fb)    显示时分秒

函数功能:设置时间的时候,选中的参数可以反白显示,右屏第二行显示程序,

由which决定第几个参数黑显,如which==1时,年份黑显.

入口参数:无

出口参数:无

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

void LCD12864_DispShiFenMiao(fb)

{

      Lcd12864_DispDaShuZi(0,2,hour/10,fb);    //第2行第1列显示小时十位数

      Lcd12864_DispDaShuZi(2,2,hour%10,fb);  //第2行第3列显示小时个位数

  if(sec%2==0)                          //如果秒为奇数则显示冒号,否则显示空

Lcd12864_DispDaShuZi(4,2,10,0);    //第2行第4列第10个大数字为显示冒号,不反白

  else

Lcd12864_DispDaShuZi(4,2,11,0);   //第2行第4列第11个大数字为显示空,不反白

      Lcd12864_DispDaShuZi(6,2,min/10,fb);  //第2行第6列显示分钟的十位数



      Lcd12864_DispDaShuZi(8,2,min%10,fb); //第2行第8列显示分钟的个位数

  if(sec%2==0)

Lcd12864_DispDaShuZi(10,2,10,0);      //第2行第10列第10个大数字为显示冒号,不反白

  else

Lcd12864_DispDaShuZi(10,2,11,0);      //第2行第10列第11个大数字为显示空,不反白

Lcd12864_DispDaShuZi(12,2,sec/10,fb);  //第2行第10列显示秒钟的十位数

      Lcd12864_DispDaShuZi(14,2,sec%10,fb); //显示秒钟

}



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

函数名称:void LCD12864_DispWeek(fb)    显示  周

函数功能:设置时间的时候,选中的参数可以反白显示,右屏第一行显示程序,

由which决定第几个参数黑显,如which==1时,年份黑显.

入口参数:无

出口参数:无

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



void LCD12864_DispWeek()

{

  uchar temp;



  Lcd12864_DispWord(12,0,27,0);            //第1行第13列第27个汉字为显示“周”字

  Conver_week();                          //调用星期阳历数据

  if(week)

temp=week;                      //赋week值为1----6,用来显示“一”----“六”

  else

week=26;                          //赋week值为0时,赋值26用来显示“日”

Lcd12864_DispWord(14,0,week,0);   //第1行第14列第26个汉字为显示“日”   

//verify_time();                     //此函数加上才能得到十二生肖后的农历日期

ReadTime_DS1302();

        GetTime_DS1302();



       Conversion(century,year,month,day); //得到农历日期



  if(c_moon)

temp=year_moon%12+12;       //如果是19世纪,则可直接得出年的属性

  else   

temp=(year_moon+100)%12+12; //农历年也过了世纪,则农历年加100再求属性

        Lcd12864_DispWord(0,6,temp,1); // 第7行第1列  显示十二生肖属性

}



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

函数名称:void LCD12864_DispNongLiRiQi(fb)    显示  农历日期

函数功能:第4行农历显示

由which决定第几个参数黑显,如which==1时,年份黑显.

入口参数:无

出口参数:无

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



void LCD12864_DispNongLiRiQi()

{

  uchar temp1,temp2;

//  verify_time();

  Conversion(century,year,month,day);   //得到农历日期,世纪年月日

  temp1=month_moon/10;

  temp2=month_moon%10;

//月份高位为0,低位为1,则月份前位显"正",后位显示“月”字

  if(temp1==0&&temp2==1)  //如果农历日期,月的十位为0,个位为1,则为正月

  {

      Lcd12864_DispWord(2,6,39,0);  //第7行第3列  显示”正”字

Lcd12864_DispWord(4,6,25,0);  //第7行第5列  显示”月”字

}

//月份高位为0,低位都大于等于2,则月份高位显月份,后位显月。      

  else if (temp1==0&&temp2>=2)

  {

      Lcd12864_DispWord(2,6,temp2,0);//第7行第3列  显示月份

Lcd12864_DispWord(4,6,25,0);   //第7行第5列  显示”月”字

  }



//月份高位为1,低位为0,则月份高位显“十”,后位显月。

  else if (temp1==1&&temp2==0)

  {

      Lcd12864_DispWord(2,6,0,0);  //第7行第3列  显示”十”字

Lcd12864_DispWord(4,6,25,0); //第7行第5列  显示”月”字

  }



//月份高位为1,低位为1,则月份高位显“冬”,后位显月。

  else if (temp1==1&&temp2==1)

  {

      Lcd12864_DispWord(2,6,29,0);    //第7行第3列  显示”冬”字

Lcd12864_DispWord(4,6,25,0);         //第7行第5列  显示”月”字

  }

  else

{

Lcd12864_DispWord(2,6,30,0);  //第7行第3列  显示”腊”字

Lcd12864_DispWord(4,6,25,0); //第7行第5列  显示”月”字

  }



  temp1=day_moon/10;

  temp2=day_moon%10;



  switch (temp1)

{      //日期高位为0,则前位显“初”

case 0:  Lcd12864_DispWord(6,6,10,0);    //第7行第7列  显示”初”字

Lcd12864_DispWord(8,6,temp2,0);//第7行第9列  显示低位字

break;



        //日期高位为1且低位不为0,则前位显“十”

case 1:  if(temp2)

  {

Lcd12864_DispWord(6,6,0,0);      //第7行第7列  显示”十”字

Lcd12864_DispWord(8,6,temp2,0); //第7行第9列  显示低位农历月份

break;

}

         else   //日期高位为1且低位为0,则显“初十”

{

Lcd12864_DispWord(6,6,10,0);  //第7行第7列  显示”初”字

Lcd12864_DispWord(8,6,0,0);  //第7行第9列  显示”十”字

break;

}

//日期高位为2,则前位显“廿”

case 2:  Lcd12864_DispWord(6,6,11,0); //第7行第7列  显示”"廿"字

Lcd12864_DispWord(8,6,temp2,0);     //第7行第9列  显示低位农历月份

break;



//日期高位为3,则前位显“三”,低位显“十”

case 3:  Lcd12864_DispWord(6,6,3,0);      //第7行第7列  显示”三”字

Lcd12864_DispWord(6,6,temp2,0); //第7行第9列  显示低位农历月份

break;

    }

}



/*主程序*/

void main(void)

{

    bl=0;

    lcd12864_Init();                  //液晶初始化,此函数只起清屏的作用

    century=0;                       //对世纪赋初值

    Conversion(century,year,month,day);

        DS1302_flag=Read_DS1302(0xc0); //读取首地址中的值,0xc0为DS1302RAM的首地址,

                                  //偶数为写,奇数读

    if(DS1302_flag==0)

        {

       Init_DS1302();          //时间初始化,起决于当前显示的时间

       Write_DS1302(0xc0,1);  

    }

    while(1)

    {

        ReadTime_DS1302();        //读出时钟数据

            GetTime_DS1302(); //将BCD时钟数据转换为可以计算的HEX数据

                GetTemp();

        Lcd12864_DispTemp();

        KeyScan();

        if(setflag==0)

                {

               

        Lcd12864_DispTime(); //这里调用显示时间程序

           

                }

    }

}
展开阅读全文

页面更新:2024-03-07

标签:农历   公历   低位   天数   单片机   高位   万年历   函数   属性   温度   参数   日期   数字   世纪   数据

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top