多功能万年历的设计.docx
《多功能万年历的设计.docx》由会员分享,可在线阅读,更多相关《多功能万年历的设计.docx(61页珍藏版)》请在冰点文库上搜索。
多功能万年历的设计
多功能万年历的设计
电子万年历主要采用时钟芯片DSl302设计。
通过LCDl602显示年、月、日、星期、时、分、秒和阴历月、日,并且能标明是否为闰月。
此外还具有调时功能。
一、方案实现
1.阳历程序设计
因为使用了时钟芯片Dsl302,阳历程序只需从I)S1302各寄存器中读出年、周、月、日、小时、分、秒等数据,再处理即可。
在首次对DSl302进行操作之前,必须对它初始化,然后从DSl302中读出数据,再经过处理后,送给显示缓冲单元。
2.阴历程序设计
阴历程序的实现是要靠阳历时间来推算的。
要根据阳历来推算阴历日期,首先要设计算法。
推算方法是,根据阳历当前时期在一年中的天数来计算阴历日期。
阳历一个月不是30天就是31天(2月除外,闰年2月为29天,平年2月为28天)。
阴历一年是12个月或是13个月(含闰年),一个月为30天或29天。
如果把一个只有29天的月称为小月,用1为标志,把30天的月称为大月,用0为标志,那么12位二进制就能表示一年12个月的大小。
如果有闰月则把闰月的月份作为一个字节的高4位,低4位表示闰月的大小。
大月为0,小月为1,这样一个字节就包含了所有闰月信息。
阴历春节和阳历元旦相差的天数也用一个字节表示。
总共用4个字节就可以存储一年中任何一天阳历和阴历的对应关系的有关数据。
例如2006年的阴历和阳历对应关系如表1所示。
表12006年的阴历和阳历对应关系表
2006年的春节和元旦差28天,这样2006年的信息表示为:
28,25H,04H,71H。
其中表示12个月大小信息的字节,第4位和第7位不用。
第1个字节为十进制,其他的都为十六进制。
按此方法,50年的阳历和阴历对应关系总共使用200个字节,如下所示。
2000~2050年的关系表:
35.15H,51H,00H(2000)23,11H,52H,41H(2001)42,12H,65H,00H(2002)
31.1lH.32H,00H(2003)21,42H,52H,21H(2004)39,52H,25H,00H(2005)
28.25H。
04H,7lH(2006)48,66H,42H,00H(2007)37,33H,22H,00H(2008)
25.15H.24H,51H(2009)44,25H,52H,00H(2010)33,22H,65H,00H(2011)
22。
2lH,25H,41H(2012)40,24H,52H,00H(2013)30,52H,42H,91H(2014)
49.55H.05H,00H(2015)38,26H,44H,00H(2016)27,53H,50H,60H(2017)
46.53H,24H,00H(2018)35,25H,54H,00H(2019)24,41H,52H,41H(2020)
42.45H,25H,00H(2021)31,24H,52H,00H(2022)21,51H,12H,21H(2023)
40.55H.11H。
00H(2024)28,26H,21H,61H(2025)47,26H,61H,00H(2026)
36.13H。
31H,00H(2027)25,05H,31H,51H(2028)43,12H,54H,00H(2029)
33.5lH,25H,00H(2030)22,42H,25H,31H(2031)41,32H,22H,00H(2032)
30.55H。
02H,71H(2033)49,55H,22H,00H(2034)38,26H,62H,00H(2035)
27.13H,64H,60H(2036)45,13H,32H,00H(2037)34,12H,55H,00H(2038)
23.10H,53H,5lH(2039)42,22H,45H,00H(2040)31,52H,22H,00H(2041)
21.52H。
44H,21H(2042)40,55H,44H,00H(2043)29,26H,50H,71H(2044)
47.26H,64H,00H(2045)36,25H,32H,00H(2046)25,23H,32H,50H(2047)
44.44H,55H,00H(2048)32,24H,45H,00H(2049)22,55H,11H,30H(2050)
有了算法和数据以后,就可以设计软件了。
先要根据当前阳历的日期,算出阳历为该年中的第几天。
图1为计算阳历任何一天在该年中为第几天的程序流程图。
计算出当前阳历日期为该年中的第几天后,再减去阳历该年春节和元旦的日差。
如果够减则相减的结果就是阴历在该年中的第几天了。
根据该数据就可以推算出具体的当前阴历日期。
图1计算阳历天数程序流程图
如果不够减,则表示当前阴历年为阳历的前一年。
这种情况下,当前阴历日期会处于阴历11月或12月。
此时春节和元旦日差减去前面计算出的当前阳历日期在阳历年为第几天的数据,其结果表示当前阴历日期离春节的天数。
计算出的阳历天数为该年的第几天,存放在寄存器R2和R3中。
计算出天数后,如果大于FFH,则把FFH存放在R2中,余值存放在R3中。
也就是说在用寄存器R2和R3表示的天数信息中,R2充当主寄存器,数据先存满R2,再存R3。
在整个转换过程中,这里面的数据不能被覆盖。
计算出阳历总天数后,就可以用它来推算阴历日期。
推算方法是,先用总天数减去春节
和元旦的日差,如果结果为1,则该天正好是春节(因为春节在元旦之后,在计算春节和元旦日差时,假设元旦为0天,春节为n天,则日差为n。
而前面计算的阳历总天数是该天在该年中的第几天,是以元旦为1而得到的,与计算春节和元旦日差的这种方法相比,其数值少了1,所以要在原来应该以0作为该天就是春节的依据的基础上加1,所以以1作为该天是春节的标志);如果结果小于l,则阴历为阳历的前一年;如果结果大于1,说明阳历和阴历为同一年。
再根据查表所得的该年的阴历的闰月和大小月的信息,就可以推算出该天的阴历日期了。
图2为由总天数推算出阴历日期的程序流程图。
图2推算阴历日期程序流程图
3.调时设计
程序共设置了6个按键,采用查询方式的独立式键盘,分别为年加1、月加1、天数加
1、星期加l、小时加1、分钟加l。
二、硬件电路设计
图3电路设计原理图
三、参考程序设计:
#include
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
sbityun_lamp=P0^7;//闰月指示灯
ucharyear,month,week,day,hour,mintue,second;
uchartime=0,temp_yun;
ucharcodeweek_dis[]="7123456";
ucharcodelookdis[]="0123456789";
uchardatadisplay[]="2000.00.000";//LCD第一行显示缓存数组
uchardataxiaohui[]="00:
00:
0000.00";//LCD第二行显示缓存数组
ucharcodedate_data[]={35,0x15,0x51,0x00,23,0x11,0x52,0x41,42,0x12,0x65,0x00,
31,0x11,0x32,0x00,21,0x42,0x52,0x21,39,0x52,0x25,0x00,
28,0x25,0x04,0x71,48,0x66,0x42,0x00,37,0x33,0x22,0x00,
25,0x15,0x24,0x51,44,0x25,0x52,0x00,33,0x22,0x65,0x00,
22,0x21,0x25,0x41,40,0x24,0x52,0x00,30,0x52,0x42,0x91,
49,0x55,0x05,0x00,38,0x26,0x44,0x00,27,0x53,0x50,0x60,
46,0x53,0x24,0x00,35,0x25,0x54,0x00,24,0x41,0x52,0x41,
42,0x45,0x25,0x00,31,0x24,0x52,0x00,21,0x51,0x12,0x21,
40,0x55,0x11,0x00,28,0x26,0x21,0x61,47,0x26,0x61,0x00,
36,0x13,0x31,0x00,25,0x05,0x31,0x51,43,0x12,0x54,0x00,
33,0x51,0x25,0x00,22,0x42,0x25,0x31,41,0x32,0x22,0x00,
30,0x55,0x02,0x71,49,0x55,0x22,0x00,38,0x26,0x62,0x00,
27,0x13,0x64,0x60,45,0x13,0x32,0x00,34,0x12,0x55,0x00,
23,0x10,0x53,0x51,42,0x22,0x45,0x00,31,0x52,0x22,0x00,
21,0x52,0x44,0x21,40,0x55,0x44,0x00,29,0x26,0x50,0x71,
47,0x26,0x64,0x00,36,0x25,0x32,0x00,25,0x23,0x32,0x50,
44,0x44,0x55,0x00,32,0x24,0x45,0x00,22,0x55,0x11,0x30};//2000-2005年的数据表
#include"chu_li.c"
#include"ds1302.c"
#include"lcd1602.c"
#include"key_board.c"
voidmain()
{
TMOD=0x01;//定时器初始化
TH0=0x3c;
TL0=0xb0;
IE=0x82;
init_lcd1602();//初始化显示器
init_ds1302();//初始化DS1302
while
(1)
{
ds1302();
display1602();
gengxin();
display1602();
key_scan();
}
}
voidt0_time()interrupt1
{
TH0=0x3c;
TL0=0xb0;
time++;
if(time==15)
time=0;
//***********************************
//BCD码转为十进制
//***********************************
uintbcd_10(uinttemp)
{
uinttemp1;
temp1=temp&0x0f;
temp=temp>>4;
temp=((temp&0x0f)*10)+temp1;
return(temp);
}
//***********************************
//查是否是闰月
//***********************************
ucharcheck_yun()
{
uchartemp;
temp=temp_yun;
temp=temp>>4;
temp=temp&0x0f;
return(temp);
}
//******************************************
//农历与公历为同一年,计算农历
//******************************************
voidnew(uchartemp_shang,uchartemp_xia,uinttian_shu)
{
uchartemp,flag,yue;
temp=check_yun();
xiaohui[11]='0';//首先置01月,农历月的高位
xiaohui[12]='1';//农历月的低位
if(tian_shu>30)//天数是否大于30,
{//大于30则减去一月的天数
if((temp_shang&0x40)==0x40)//月小减去29
{
tian_shu=tian_shu-29;
xiaohui[11]='0';
xiaohui[12]='2';//减去了第一个月的天数,则为二月
}
else//月大减去30
{
tian_shu=tian_shu-30;
xiaohui[11]='0';
xiaohui[12]='2';
}
}
elseif(tian_shu>29)//天数等于30
{
if((temp_shang&0x40)==0x40)//月小减去29
{
tian_shu=tian_shu-29;
xiaohui[11]='0';
xiaohui[12]='2';
}
else//月大减去30
{
tian_shu=tian_shu-30;
xiaohui[11]='0';
xiaohui[12]='2';
if(tian_shu==0)//天数等于0,就是前一个月的最后一天
{
tian_shu=30;
flag=0x01;
xiaohui[11]='0';
xiaohui[12]='1';
}
}
}
//****************减去二月的天数*******
if(tian_shu>30)//天数是否大于30,
{//大于30则减去二月的天数
if((temp_shang&0x20)==0x20)//月小减去29
{
tian_shu=tian_shu-29;
xiaohui[11]='0';
xiaohui[12]='3';
yue=0x03;//标志位,表示为三月
}
else//月大减去30
{
tian_shu=tian_shu-30;
xiaohui[11]='0';
xiaohui[12]='3';
yue=0x03;
}
}
elseif((tian_shu>29)&&(flag!
=0x01))//flag标志位,flag=0x01为上一个月的最后天
{//不能再去减其他月的天数
if((temp_shang&0x20)==0x20)//月小减去29
{
tian_shu=tian_shu-29;
xiaohui[11]='0';
xiaohui[12]='3';
yue=0x03;
}
else//月大减去30
{
tian_shu=tian_shu-30;
xiaohui[11]='0';
xiaohui[12]='3';
if(tian_shu==0)//天数等于0,就是前一个月的最后一天
{
tian_shu=30;
flag=0x01;
xiaohui[11]='0';
xiaohui[12]='2';
}
}
}
//*************减去闰二月的天数***********
if((temp==0x02)&&(yue==0x03))//2月为闰月,标志位yue为0x03
{
yun_lamp=0;//闰月指示灯亮
xiaohui[11]='0';
xiaohui[12]='2';
if(tian_shu>30)
{
if((temp_yun&0x0f)==0x01)//月小减去29
{
tian_shu=tian_shu-29;
xiaohui[11]='0';
xiaohui[12]='3';
yun_lamp=1;//闰月结束了,指示灯灭
}
else//月大减去30
{
tian_shu=tian_shu-30;
xiaohui[11]='0';
xiaohui[12]='3';
yun_lamp=1;//闰月结束了,指示灯灭
}
}
elseif((tian_shu>29)&&(flag!
=0x01))//天数等于30,并且不为某月的最后一天
{
if((temp_yun&0x0f)==0x01)
{
tian_shu=tian_shu-29;
xiaohui[11]='0';
xiaohui[12]='3';
yun_lamp=1;
}
else
{
tian_shu=tian_shu-30;
xiaohui[11]='0';
xiaohui[12]='3';
yun_lamp=1;
if(tian_shu==0)
{
tian_shu=30;
flag=0x01;
xiaohui[11]='0';
xiaohui[12]='2';
}
}
}
}
//**********************减去三月的天数**************
if(tian_shu>30)
{
if((temp_shang&0x10)==0x10)
{
tian_shu=tian_shu-29;
xiaohui[11]='0';
xiaohui[12]='4';
yue=0x04;
}
else
{
tian_shu=tian_shu-30;
xiaohui[11]='0';
xiaohui[12]='4';
yue=0x04;
}
}
elseif((tian_shu>29)&&(flag!
=0x01))
{
if((temp_shang&0x10)==0x10)
{
tian_shu=tian_shu-29;
xiaohui[11]='0';
xiaohui[12]='4';
yue=0x04;
}
else//if((temp_shang&0x10)!
=0x10)
{
tian_shu=tian_shu-30;
xiaohui[11]='0';
xiaohui[12]='4';
if(tian_shu==0)
{
tian_shu=30;
flag=0x01;
xiaohui[11]='0';
xiaohui[12]='3';
}
}
}
//****************减去闰三月的天数************
if((temp==0x03)&&(yue==0x04))
{
yun_lamp=0;
xiaohui[11]='0';
xiaohui[12]='3';
if(tian_shu>30)
{
if((temp_yun&0x0f)==0x01)
{
tian_shu=tian_shu-29;
xiaohui[11]='0';
xiaohui[12]='4';
yun_lamp=1;
}
else
{
tian_shu=tian_shu-30;
xiaohui[11]='0';
xiaohui[12]='4';
yun_lamp=1;
}
}
elseif((tian_shu>29)&&(flag!
=0x01))
{
if((temp_yun&0x0f)==0x01)
{
tian_shu=tian_shu-29;
xiaohui[11]='0';
xiaohui[12]='4';
yun_lamp=1;
}
else
{
tian_shu=tian_shu-30;
xiaohui[11]='0';
xiaohui[12]='4';
yun_lamp=1;
if(tian_shu==0)
{
tian_shu=30;
flag=0x01;
xiaohui[11]='0';
xiaohui[12]='3';
}
}
}
}
//**************减去四月的天数*************
if(tian_shu>30)
{
if((temp_shang&0x04)==0x04)
{
tian_shu=tian_shu-29;
xiaohui[11]='0';
xiaohui[12]='5';
yue=0x05;
}
else
{
tian_shu=tian_shu-30;
xiaohui[11]='0';
xiaohui[12]='5';
yue=0x05;
}
}
elseif((tian_shu>29)&&(flag!
=0x01))
{
if((temp_shang&0x04)==0x04)
{
tian_shu=tian_shu-29;
xiaohui[11]='0';
xiaohui[12]='5';
yue=0x05;
}
else
{
tian_shu=tian_shu-30;
xiaohui[11]='0';
xiaohui[12]='5';
if(tian_shu==0)
{
tian_shu=30;
flag=0x01;
xiaohui[11]='0';
xiaohui[12]='4';
}
}
}
//**************减去闰四月的天数************
if((temp==0x04)&&(yue==0x05))
{
yun_lamp=0;
xiaohui[11]='0';
xiaohui[12]='4';
if(tian_shu>30)
{
if((temp_yun&0x0f)==0x01)
{
tian_shu=tian_shu-29;
xiaohui[11]='0';
xiaohui[12]='5';
yun_lamp=1;
}
else
{
tian_shu=tian_shu-30;
xiaohui[11]='0';
xiaohui[12]='5';
yun_lamp=1;
}
}
els