单片机大数字万年历电子钟制作带农历年属性温度
介绍
LCD12864大数字万年历电子钟设计,用了一个多星期时间,经过实物实测,每月时间相差几分钟,这是时钟走时芯片决定的,温度显示还算正常。
图片
万年历图片
单片机板子
代码includereg51。hincludeintrins。hincludestdio。hincludestring。hdefineucharunsignedchardefineuintunsignedintLCD12864通讯端口sbitRSLCD12864P27;定义选择显示类型,定义数据或指令,1数据,0指令sbitRWLCD12864P26;定义读写信号控制端,定义读或写??1读,??0写sbitENLCD12864P25;定义数据锁存信号,定义使能操作,1能,??0否defineLCD12864DatabusP0定义数据端definesc00definesc11ucharDS1302flag;定义DS1302RAM中是否写数的标志位,第一次开机初始化后RAM中写1sbitCS1P24;定义选择芯片右半屏信号sbitCS2P23;定义选择芯片左半屏信号DS1302时钟端口sbitSCLKP20;DS1302时钟口sbitDATAP21;DS1302串口数据sbitRSTP22;DS1302的复位口ucharcodeWriteRTCADDR〔7〕{0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};ucharcodeREADRTCADDR〔7〕{0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};ucharTIME〔7〕{0,0x38,0x15,0x25,0x05,0x03,0x22};2022年5月25星期3,15:38:00DS18B20sbitDQP37;温度探测口ucharfb;文字反白标示uinttempvalue;温度值,此变量若为uchar则温度不正常ucharTempFlag;温度正负标志按键端口sbitsetP10;设置sbitkey1P11;加sbitkey2P12;减sbitkey3P13;蜂鸣开关sbitkey4P14;背光开关ucharsetflag0;按键计数,决定调节的日期和时间sbitblP35;背光控制端sbitbzP36;蜂鸣控制端uchartempa;调时农历部分defineuintunsignedintcharsec,min,hour,day,month,year,week;定义全局变量,秒,分,时,日,月,年和星期bitcentury;世纪位标志,0为20世纪,1为19世纪ucharseccount0;定义定时计数,当seccount20时,秒加一codeuchartableweek〔12〕{0,3,3,6,1,4,6,2,5,0,3,5};月修正数据表codeuchardaycode1〔9〕{0x0,0x1f,0x3b,0x5a,0x78,0x97,0xb5,0xd4,0xf3};月份数据表codeuintdaycode2〔3〕{0x111,0x130,0x14e};bitcmoon;dataucharyearmoon,monthmoon,daymoon;函数声明读取数据表中农历月的大月或小月,如果该月为大返回1,为小返回0bitgetmoonday(ucharmonthp,uinttableaddr);voidConversion(bitc,charyear,charmonth,charday);输入阳历数据,输出阴历数据voidConverweek();输入BCD阳历数据,输出BCD星期数据voiddelayms(uintx);voidLcd12864BusyChk();voidsetxy(unsignedcharx,unsignedchary);函数名称:Conversion功能描述:输入阳历数据,输出阴历数据(只允许19012099年)参数:参数名称voidConversion(bitc,charyear,charmonth,charday){c0为21世纪,c1为19世纪输入输出数据均为BCD数据uchartemp1,temp2,temp3,monthp;uinttemp4,tableaddr;bitflag2,flagy;定位数据表地址if(c0){tableaddr(year0x641)0x3;}else{tableaddr(year1)0x3;}定位数据表地址完成取当年节日所在的公历月份temp1yearcode〔tableaddr2〕0x60;temp1cror(temp1,5);取当年节日所在的公历月份完成取当年节日所在的公历日temp2yearcode〔tableaddr2〕0x1f;取当年节日所在的公历日完成计算当年春年离当年元旦的天数,节日只会在公历1月或2月if(temp10x1){temp3temp21;}else{temp3temp20x1f1;}计算当年春年离当年元旦的天数完成计算公历日离当年元旦的天数,为了减少运算,用了两个表daycode1〔9〕,daycode2〔3〕如果公历月在九月或前,天数会少于0xff,用表daycode1〔9〕,在九月后,天数大于0xff,用表daycode2〔3〕如输入公历日为8月10日,则公历日离元旦天数为daycode1〔81〕101如输入公历日为11月10日,则公历日离元旦天数为daycode2〔1110〕101if(month10){temp4daycode1〔month1〕day1;}else{temp4daycode2〔month10〕day1;}if((month0x2)(year0x40)(year!0))temp41;如果公历月大于2月并且该年的2月为闰月,天数加1计算公历日离当年元旦的天数完成判断公历日在节日前还是节日后if(temp4temp3){公历日在节日后或就是节日当日使用下面代码进行运算temp4temp3;month0x1;monthp0x1;monthp为月份指向,公历日在节日前或就是节日当日monthp指向首月flag2getmoonday(monthp,tableaddr);检查该农历月为大小还是小月,大月返回1,小月返回0flagy0;if(flag20)temp10x1d;小月29天elsetemp10x1e;大小30天temp2yearcode〔tableaddr〕0xf0;temp2cror(temp2,4);从数据表中取该年的闰月月份,如为0则该年无闰月while(temp4temp1){temp4temp1;monthp1;if(monthtemp2){flagyflagy;if(flagy0)month1;}elsemonth1;flag2getmoonday(monthp,tableaddr);if(flag20)temp10x1d;elsetemp10x1e;}daytemp41;}else{公历日在节日前使用下面代码进行运算temp3temp4;if(year0x0){year0x63;c1;}elseyear1;tableaddr0x3;month0xc;temp2yearcode〔tableaddr〕0xf0;temp2cror(temp2,4);if(temp20)monthp0xc;elsemonthp0xd;monthp为月份指向,如果当年有闰月,一年有十三个月,月指向13,无闰月指向12flagy0;flag2getmoonday(monthp,tableaddr);if(flag20)temp10x1d;elsetemp10x1e;while(temp3temp1){temp3temp1;monthp1;if(flagy0)month1;if(monthtemp2)flagyflagy;flag2getmoonday(monthp,tableaddr);if(flag20)temp10x1d;elsetemp10x1e;}daytemp1temp31;}cmoonc;原程序这里又把这得出的值变回BCD码。但根据我后面的程序,我不需要。后面用来显示的农历信息的程序分别是dispt3()和dispt4()yearmoonyear;monthmoonmonth;daymoonday;}函数名称:Converweek功能描述:输入BCD阳历数据,输出BCD星期数据(只允许19012099年)参数:参数名称:输入输出?类型描述算法:日期年份所过闰年数月较正数之和除7的余数就是星期,但如果是在闰年又不到3月份上述之和要减一天再除7星期数。余数为0时,为星期天。voidConverweek(){century0为21世纪,c1为19世纪输入输出数据均为BCD数据uchartemp1,temp2;temp1year;if(century0){temp1temp1100;}如果为21世纪,年份数加100temp2temp14;所过闰年数只算1900年之后的temp2temp1temp2;temp2temp27;为节省资源,先进行一次取余,避免数大于255temp2temp2daytableweek〔month1〕;if(year0x40month3)temp21;weektemp27;}LCD12864部分端口说明:ENLCD12864:使能端锁存信号。RSLCD12864:DI命令数据寄存器选择端RWLCD12864:读写信号控制端。defineLCDDataP0RS(DI)1,表示DB0DB7显示数据;RS(DI)0,表示DB0DB7显示指令数据RW1,E1,数据被读到DB7DB0;RW0,E10,数据被读到DB7DB0;数据被写到IR或DR。(定义数据端口为LCDData为P0口)RSTLCD12864复位端口,不接或接高电平,低电平会导致复位函数名称:voidLcd12864BusyChk()函数功能:忙检测,若忙则等待,最长等待时间为60MS(此判忙函数经过仿真已OK)入口参数:无出口参数:无voidLcd12864BusyChk(){LCD12864Databus0x00;ENLCD128640;RSLCD128640;RWLCD128641;ENLCD128641;while(LCD12864Databus0x80);判断P0。7口nop();ENLCD128640;}函数名称:voidsetxy(unsignedcharx,unsignedchary)(仿真时的函数,已OK)功能描述:设置显示位置!X,Y分别代表横纵坐标!输入参数?:unsignedcharx,unsignedchary输出参数:无??参数名称:??列地址赋值,?x取值064,页面地址赋值,y取值08voidsetxy(unsignedcharx,unsignedchary){if(x64){CS11;CS20;}选择右半屏else{CS10;CS21;}选择左半屏Lcd12864BusyChk();RSLCD128640;RWLCD128640;LCD12864Databus0x40x;列地址赋值,x取值064ENLCD128641;ENLCD128640;Lcd12864BusyChk();RSLCD128640;RWLCD128640;LCD12864Databus0xb8y;页面地址赋值,y取值08ENLCD128641;ENLCD128640;LCD12864Databus0xff;}函数名称:voidsetxy(unsignedcharx,unsignedchary)(实物时的函数,已OK)功能描述:设置显示位置!X,Y分别代表横纵坐标!输入参数?:unsignedcharx,unsignedchary输出参数:无??参数名称:??列地址赋值,?x取值064,页面地址赋值,y取值08函数名称:voidLCD12864DispYanYueRi(fb)函数功能:设置日期的时候,选中的参数可以反白显示,右屏第一行显示程序,由which决定第几个参数黑显,如which1时,年份黑显。入口参数:无出口参数:无voidLCD12864DispYanYueRi(fb)显示年月日{if(century)如果世纪为1{Lcd12864DispChar(0,0,1,0);则第1行第1列显示’1Lcd12864DispChar(1,0,9,0);则第1行第2列显示’9}else{Lcd12864DispChar(0,0,2,0);则第1行第1列显示’2Lcd12864DispChar(1,0,0,0);则第1行第2列显示’0}Lcd12864DispChar(2,0,year10,fb);第1行第3列显示年十位数Lcd12864DispChar(3,0,year10,fb);第1行第4列显示年个位数Lcd12864DispChar(4,0,11,0);第1行第5列显示第11个数据Lcd12864DispChar(5,0,month10,fb);第1行第6列显示月十位数Lcd12864DispChar(6,0,month10,fb);第1行第7列显示月个位数Lcd12864DispChar(7,0,11,0);第1行第8列显示第11个数据Lcd12864DispChar(8,0,day10,fb);第1行第9列显示日十位数Lcd12864DispChar(9,0,day10,fb);第1行第10列显示日个位数}函数名称:voidLCD12864DispShiFenMiao(fb)显示时分秒函数功能:设置时间的时候,选中的参数可以反白显示,右屏第二行显示程序,由which决定第几个参数黑显,如which1时,年份黑显。入口参数:无出口参数:无voidLCD12864DispShiFenMiao(fb){Lcd12864DispDaShuZi(0,2,hour10,fb);第2行第1列显示小时十位数Lcd12864DispDaShuZi(2,2,hour10,fb);第2行第3列显示小时个位数if(sec20)如果秒为奇数则显示冒号,否则显示空Lcd12864DispDaShuZi(4,2,10,0);第2行第4列第10个大数字为显示冒号,不反白elseLcd12864DispDaShuZi(4,2,11,0);第2行第4列第11个大数字为显示空,不反白Lcd12864DispDaShuZi(6,2,min10,fb);第2行第6列显示分钟的十位数Lcd12864DispDaShuZi(8,2,min10,fb);第2行第8列显示分钟的个位数if(sec20)Lcd12864DispDaShuZi(10,2,10,0);第2行第10列第10个大数字为显示冒号,不反白elseLcd12864DispDaShuZi(10,2,11,0);第2行第10列第11个大数字为显示空,不反白Lcd12864DispDaShuZi(12,2,sec10,fb);第2行第10列显示秒钟的十位数Lcd12864DispDaShuZi(14,2,sec10,fb);显示秒钟}函数名称:voidLCD12864DispWeek(fb)显示周函数功能:设置时间的时候,选中的参数可以反白显示,右屏第一行显示程序,由which决定第几个参数黑显,如which1时,年份黑显。入口参数:无出口参数:无voidLCD12864DispWeek(){uchartemp;Lcd12864DispWord(12,0,27,0);第1行第13列第27个汉字为显示周字Converweek();调用星期阳历数据if(week)tempweek;赋week值为16,用来显示一六elseweek26;赋week值为0时,赋值26用来显示日Lcd12864DispWord(14,0,week,0);第1行第14列第26个汉字为显示日verifytime();此函数加上才能得到十二生肖后的农历日期ReadTimeDS1302();GetTimeDS1302();Conversion(century,year,month,day);得到农历日期if(cmoon)tempyearmoon1212;如果是19世纪,则可直接得出年的属性elsetemp(yearmoon100)1212;农历年也过了世纪,则农历年加100再求属性Lcd12864DispWord(0,6,temp,1);第7行第1列显示十二生肖属性}函数名称:voidLCD12864DispNongLiRiQi(fb)显示农历日期函数功能:第4行农历显示由which决定第几个参数黑显,如which1时,年份黑显。入口参数:无出口参数:无voidLCD12864DispNongLiRiQi(){uchartemp1,temp2;verifytime();Conversion(century,year,month,day);得到农历日期,世纪年月日temp1monthmoon10;temp2monthmoon10;月份高位为0,低位为1,则月份前位显正,后位显示月字if(temp10temp21)如果农历日期,月的十位为0,个位为1,则为正月{Lcd12864DispWord(2,6,39,0);第7行第3列显示正字Lcd12864DispWord(4,6,25,0);第7行第5列显示月字}月份高位为0,低位都大于等于2,则月份高位显月份,后位显月。elseif(temp10temp22){Lcd12864DispWord(2,6,temp2,0);第7行第3列显示月份Lcd12864DispWord(4,6,25,0);第7行第5列显示月字}月份高位为1,低位为0,则月份高位显十,后位显月。elseif(temp11temp20){Lcd12864DispWord(2,6,0,0);第7行第3列显示十字Lcd12864DispWord(4,6,25,0);第7行第5列显示月字}月份高位为1,低位为1,则月份高位显冬,后位显月。elseif(temp11temp21){Lcd12864DispWord(2,6,29,0);第7行第3列显示冬字Lcd12864DispWord(4,6,25,0);第7行第5列显示月字}else{Lcd12864DispWord(2,6,30,0);第7行第3列显示腊字Lcd12864DispWord(4,6,25,0);第7行第5列显示月字}temp1daymoon10;temp2daymoon10;switch(temp1){日期高位为0,则前位显初case0:Lcd12864DispWord(6,6,10,0);第7行第7列显示初字Lcd12864DispWord(8,6,temp2,0);第7行第9列显示低位字break;日期高位为1且低位不为0,则前位显十case1:if(temp2){Lcd12864DispWord(6,6,0,0);第7行第7列显示十字Lcd12864DispWord(8,6,temp2,0);第7行第9列显示低位农历月份break;}else日期高位为1且低位为0,则显初十{Lcd12864DispWord(6,6,10,0);第7行第7列显示初字Lcd12864DispWord(8,6,0,0);第7行第9列显示十字break;}日期高位为2,则前位显廿case2:Lcd12864DispWord(6,6,11,0);第7行第7列显示廿字Lcd12864DispWord(8,6,temp2,0);第7行第9列显示低位农历月份break;日期高位为3,则前位显三,低位显十case3:Lcd12864DispWord(6,6,3,0);第7行第7列显示三字Lcd12864DispWord(6,6,temp2,0);第7行第9列显示低位农历月份break;}}主程序voidmain(void){bl0;lcd12864Init();液晶初始化,此函数只起清屏的作用century0;对世纪赋初值Conversion(century,year,month,day);DS1302flagReadDS1302(0xc0);读取首地址中的值,0xc0为DS1302RAM的首地址,偶数为写,奇数读if(DS1302flag0){InitDS1302();时间初始化,起决于当前显示的时间WriteDS1302(0xc0,1);}while(1){ReadTimeDS1302();读出时钟数据GetTimeDS1302();将BCD时钟数据转换为可以计算的HEX数据GetTemp();Lcd12864DispTemp();KeyScan();if(setflag0){Lcd12864DispTime();这里调用显示时间程序}}}