单片机大数字万年历电子钟制作带农历年属性温度
介绍
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(); //这里调用显示时间程序 } } }
聪明人,从不帮这5个忙特别喜欢一句话聪明是一种天赋,善良是一种选择。选择善良是一件好事,有选择性地与人为善,则是一件又好又正确的事。心存良善,更应懂得自保择善而行,更应懂得把善良用对事给对人。生活中,有
生活终究把自己逼成了自己最讨厌的人小时候,在菜市场看到有人为了一两元这种小钱发生很大的争执,觉得他们真是,我以后绝对不这样。于是,这一路,努力学习,认真读书,时刻提醒自己要做一个有格局的有见识大气的人,不要为了鸡毛
五砍柴人家五砍柴人家我是水边长大的孩子,更可以说是山里长大的孩子,工厂的家属区依山傍水,一出门就可以看见满眼青山。往远处,是更高和更深的山,那里蕴藏着我更多的儿时印迹。这么多年过去了,小时候
守财奴的悲哀,你还在守吗?头条创作挑战赛你是守财奴吗?你身边有守财奴吗?看了这篇文章你会改变消费理念吗?从前有一个守财奴祖上传下来一些产业,他舍不得吃舍不得喝又怕别人算计他,所以就把所有的家当变卖了,换成了
35岁觉醒的人生,爆发式的成长到底有多爽?你们有过35岁生活被自己弄得一团糟的焦虑吗?我有,在很多人眼中,这个年龄是人生中得意有面儿又有钱的的年纪。但是,对我来说,35岁的年纪是我人生中遇到了的一次尴尬场景。2021年下半
你对人生有什么感悟,人生如戏能否发表一句人生的感悟生活可以无所谓,因为无所谓所以你快乐。没有人会帮你一辈子,所以你必须得靠自己。如果你不去付出大量的心血和劳动,就做不成什么大事的。生活没有亏欠我们什么,至少他
散文慢慢行,内心安静,走过人生岁月作者子墨一缕阳光,寂静了时光,一缕晚风,吹薄了季节。阳光隐去,季节的风有点轻寒,悄悄而来,却让寒意漫过岁月的河岸,凋零了几片落叶,随风穿过时光的缝隙,落下几点沧桑。风带走了秋天的风
2022。11。11早安心语,光棍节,正能量语录激励人心的说说图片早上好,今天是2022年11月11日,星期五,农历十月十八,壬寅年虎年辛亥月戊辰日。光棍节。今日为光棍节,给自己一点时间,让旧的过去,给自己一个机会,让新的开始。茶,要喝浓的,直到
清荷感悟人生修行,懂得留白作者清荷札记人生的修行,就是学会用智慧看世间的各种繁杂,在黑白相间的风景里,寻找一种平衡,并用一颗平常心对待日升月落。人要过得好,就要通过修行,精进自己,才能,行稳致远。人生无常,
11月11日早上好问候动态图片最新版周五最美早安祝福图片带字温馨1真诚的友谊不会忘记,执着的感情不会放弃,贴心的朋友不会分离,热情的关怀不分四季。让清晨的阳光温暖你,让温暖的风伴随着你,让我的短信问候你,让幸福快乐永远伴着你,早安!2遇到你真正
11月11日早上好问候图片丨最新周五早安祝福图片丨早上温馨的问候每天早上问候语图片,今天最新发布早上好问候祝福,早安美图集合。用快乐带动心情,用覌念导航人生,用真诚对待朋友,用平淡对待磨难,用努力追求幸福,用感恩对待生活,心有多善,福有多深,早