| #include <reg52.h> #include <intrins.h> #define uchar unsigned char #define uint unsigned int uchar sec,min,hour,day,month,year,week; bit w; uchar next; void DelayUs2x(unsigned char t) { while(--t); } void DelayMs(unsigned char t) { while(t--) { //大致延时1mS DelayUs2x(245); DelayUs2x(245); } } void delay(uint ms) // 延时子程序 { uint a,b,c; //ms=1000为1.015s for(a=2;a>0;a--) for(b=46;b>0;b--) for(c=ms;c>0;c--); } sbit RS = P2^4; sbit RW = P2^5; sbit E = P2^6; sbit RES = P2^1; sbit PSB = P2^0; sbit sclk=P1^0; //1302串行时钟 sbit I_O=P1^1; //1302数据端口 sbit rst=P1^2; //1302复位 sbit k1=P3^4; //功能健 sbit k2=P3^5; //时间加 sbit k3=P3^6; //时间减 sbit k4=P3^7; //确定键 #define DataPort P0 //单片机 P0<------> 液晶DB0-DB7 uchar code DayCode1[9]={0x00,0x1f,0x3b,0x5a,0x78,0x97,0xb5,0xd4,0xf3}; uint code DayCode2[3]={0x111,0x130,0x14e}; uchar LunarMonth,LunarDay,LunarYear; bit c_moon; uchar code YearCode[300]= { 0x0C,0x96,0x45, //2000 297 0x4d,0x4A,0xB8, //2001 300 0x0d,0x4A,0x4C, //2002 303 0x0d,0xA5,0x41, //2003 306 0x25,0xAA,0xB6, //2004 309 0x05,0x6A,0x49, //2005 312 0x7A,0xAd,0xBd, //2006 315 0x02,0x5d,0x52, //2007 318 0x09,0x2d,0x47, //2008 321 0x5C,0x95,0xBA, //2009 324 0x0A,0x95,0x4e, //2010 327 0x0B,0x4A,0x43, //2011 0x4B,0x55,0x37, //2012 0x0A,0xd5,0x4A, //2013 0x95,0x5A,0xBf, //2014 0x04,0xBA,0x53, //2015 0x0A,0x5B,0x48, //2016 0x65,0x2B,0xBC, //2017 0x05,0x2B,0x50, //2018 0x0A,0x93,0x45, //2019 0x47,0x4A,0xB9, //2020 0x06,0xAA,0x4C, //2021 0x0A,0xd5,0x41, //2022 0x24,0xdA,0xB6, //2023 0x04,0xB6,0x4A, //2024 0x69,0x57,0x3d, //2025 0x0A,0x4e,0x51, //2026 0x0d,0x26,0x46, //2027 0x5e,0x93,0x3A, //2028 0x0d,0x53,0x4d, //2029 0x05,0xAA,0x43, //2030 0x36,0xB5,0x37, //2031 0x09,0x6d,0x4B, //2032 0xB4,0xAe,0xBf, //2033 0x04,0xAd,0x53, //2034 0x0A,0x4d,0x48, //2035 0x6d,0x25,0xBC, //2036 0x0d,0x25,0x4f, //2037 0x0d,0x52,0x44, //2038 0x5d,0xAA,0x38, //2039 0x0B,0x5A,0x4C, //2040 0x05,0x6d,0x41, //2041 0x24,0xAd,0xB6, //2042 0x04,0x9B,0x4A, //2043 0x7A,0x4B,0xBe, //2044 0x0A,0x4B,0x51, //2045 0x0A,0xA5,0x46, //2046 0x5B,0x52,0xBA, //2047 0x06,0xd2,0x4e, //2048 0x0A,0xdA,0x42, //2049 0x35,0x5B,0x37, //2050 0x09,0x37,0x4B, //2051 0x84,0x97,0xC1, //2052 0x04,0x97,0x53, //2053 0x06,0x4B,0x48, //2054 0x66,0xA5,0x3C, //2055 0x0e,0xA5,0x4f, //2056 0x06,0xB2,0x44, //2057 0x4A,0xB6,0x38, //2058 0x0A,0xAe,0x4C, //2059 0x09,0x2e,0x42, //2060 0x3C,0x97,0x35, //2061 0x0C,0x96,0x49, //2062 0x7d,0x4A,0xBd, //2063 0x0d,0x4A,0x51, //2064 0x0d,0xA5,0x45, //2065 0x55,0xAA,0xBA, //2066 0x05,0x6A,0x4e, //2067 0x0A,0x6d,0x43, //2068 0x45,0x2e,0xB7, //2069 0x05,0x2d,0x4B, //2070 0x8A,0x95,0xBf, //2071 0x0A,0x95,0x53, //2072 0x0B,0x4A,0x47, //2073 0x6B,0x55,0x3B, //2074 0x0A,0xd5,0x4f, //2075 0x05,0x5A,0x45, //2076 0x4A,0x5d,0x38, //2077 0x0A,0x5B,0x4C, //2078 0x05,0x2B,0x42, //2079 0x3A,0x93,0xB6, //2080 0x06,0x93,0x49, //2081 0x77,0x29,0xBd, //2082 0x06,0xAA,0x51, //2083 0x0A,0xd5,0x46, //2084 0x54,0xdA,0xBA, //2085 0x04,0xB6,0x4e, //2086 0x0A,0x57,0x43, //2087 0x45,0x27,0x38, //2088 0x0d,0x26,0x4A, //2089 0x8e,0x93,0x3e, //2090 0x0d,0x52,0x52, //2091 0x0d,0xAA,0x47, //2092 0x66,0xB5,0x3B, //2093 0x05,0x6d,0x4f, //2094 0x04,0xAe,0x45, //2095 0x4A,0x4e,0xB9, //2096 0x0A,0x4d,0x4C, //2097 0x0d,0x15,0x41, //2098 0x2d,0x92,0xB5, //2099 }; /***复位1302***/ void reset1302() { sclk=0; rst=0; rst=1; } /***向1302写入1字节***/ void wrieteByte1302(uchar add) { uchar i; for(i=0;i<8;i++) { I_O=0; if(add&0x01)I_O=1; sclk=0; sclk=1; add>>=1; } } void writeClkBye(uchar add,uchar num) { reset1302(); wrieteByte1302(add); wrieteByte1302(num); } /***1302初始化***/ void init1302() { reset1302(); writeClkBye(0x8e,0); //允许写入 reset1302(); writeClkBye(0x90,0xaa); //慢充电 reset1302(); writeClkBye(0x80,00); //秒初值 reset1302(); writeClkBye(0x82,0x12); //分 reset1302(); writeClkBye(0x84,0x12); // 时 reset1302(); writeClkBye(0x86,0x04); // 日 reset1302(); writeClkBye(0x88,0x03); // 月 reset1302(); writeClkBye(0x8a,0x07); // 星期 reset1302(); writeClkBye(0x8c,0x12); // 年 reset1302(); } /***检测忙位***/ void Check_Busy() { RS=0; RW=1; E=1; DataPort=0xff; while((DataPort&0x80)==0x80);//忙则等待 E=0; } /***写命令***/ void Write_Cmd(unsigned char Cmd) { Check_Busy(); RS=0; RW=0; E=1; DataPort=Cmd; DelayUs2x(5); E=0; DelayUs2x(5); } /****写数据***/ void Write_Data(unsigned char Data) { Check_Busy(); RS=1; RW=0; E=1; DataPort=Data; DelayUs2x(5); E=0; DelayUs2x(5); } /****液晶屏初始化***/ void Init_ST7920() { DelayMs(40); //大于40MS的延时程序 PSB=1; //设置为8BIT并口工作模式 DelayMs(1); //延时 RES=0; //复位 DelayMs(1); //延时 RES=1; //复位置高 DelayMs(10); Write_Cmd(0x30); //选择基本指令集 DelayUs2x(50); //延时大于100us Write_Cmd(0x30); //选择8bit数据流 DelayUs2x(20); //延时大于37us Write_Cmd(0x0c); //开显示(无游标、不反白) DelayUs2x(50); //延时大于100us Write_Cmd(0x01); //清除显示,并且设定地址指针为00H DelayMs(15); //延时大于10ms Write_Cmd(0x06); //指定在资料的读取及写入时,设定游标的移动方向及指定显示的移位,光标从右向左加1位移动 DelayUs2x(50); //延时大于100us } /****从1302读取***/ uchar ReadByte1302() { uchar i; uchar RByte; uchar TempByte; RByte=0x00; I_O=1; for(i=0;i<8;i++) { sclk=1; sclk=0; TempByte=(uchar)I_O; TempByte<<=7; RByte>>=1; RByte|=TempByte; } return RByte; } uchar read1302(uchar add) { uchar num; reset1302(); wrieteByte1302(add); ReadByte1302(); num=ReadByte1302(); return num; } void LCDTestWord(bit i, uchar word) { if(i==0) { Write_Cmd(word); //i=0;则写入指令 } else { Write_Data(word); //i=1;则写入数据 } } /***向LCD发送一个字符串即写汉字***/ void LCDSendWord(uchar *p) { while(*p>0) { Write_Data(*p); p++; } } /***往LCD上填写 年 月 日 小时 分钟 秒 星期以及它们的 数据***/ void DisplayYear() { year=read1302(0x8d); //从1302的0X8D处读出年数据 LCDTestWord(0,0x81); //写指令 在第一行第二个字符位置显示 年 LCDTestWord(1,(year/16)+0x30); //写数据 LCDTestWord(1,year%16+0x30); //写数据 LCDTestWord(0,0x82); //写指令 第一行第三个字符位置 LCDSendWord("年"); //显示 年 LCD DDRAM第一行地址为80-87, //第二行为90-97,第三行为88-8F,第四行为98-9F } void DisplayMonth() { month=read1302(0x89); //从1302中读取月份数据 LCDTestWord(0,0x83); //写命令 if(month/16!=0) { LCDTestWord(1,(month/16)+0x30); //写数据 } else { LCDTestWord(1,0x20); //写数据 } LCDTestWord(1,month%16+0x30); //写数据 LCDTestWord(0,0x84); //写指令 LCDSendWord("月"); //显示 月 } void DisplayDay() { day=read1302(0x87); //从1302中读取日期数据 LCDTestWord(0,0x85); if(day/16!=0) { LCDTestWord(1,(day/16)+0x30); } else { LCDTestWord(1,0x20); } LCDTestWord(1,day%16+0x30); LCDTestWord(0,0x86); LCDSendWord("日"); } void DisplayWeek() { week=(read1302(0x8b))%16; //从1302中读取星期数据 LCDTestWord(0,0x95); LCDSendWord("星期"); LCDTestWord(0,0x97); if(week==7) {LCDSendWord("日");} if(week==6) {LCDSendWord("六");} if(week==5) {LCDSendWord("五");} if(week==4) {LCDSendWord("四");} if(week==3) {LCDSendWord("三");} if(week==2) {LCDSendWord("二");} if(week==1) {LCDSendWord("一");} //显示星期一到星期日 } void DisplayHour() { hour=read1302(0x85); LCDTestWord(0,0x90); LCDTestWord(1,(hour/16)+0x30); LCDTestWord(1,hour%16+0x30); } void DisplayMin() { min=read1302(0x83); LCDTestWord(0,0x91); LCDTestWord(1,0x3a); //写入分割号 : LCDTestWord(1,(min/16)+0x30); LCDTestWord(1,min%16+0x30); LCDTestWord(1,0x3a); //写入分割号 : } void DisplaySec() { sec=read1302(0x81); LCDTestWord(0,0x93); LCDTestWord(1,(sec/16)+0x30); LCDTestWord(1,sec%16+0x30); } void UpDate() { DisplayYear(); //显示年 DisplayMonth(); //显示月 DisplayDay(); //显示日 DisplayWeek(); //显示星期 DisplayHour(); //显示时 DisplayMin(); //显示分 DisplaySec(); //显示秒 } void SetTime(uchar count) { unsigned char address,item; unsigned char max,mini; LCDTestWord(0,0x98); LCDSendWord("设置"); if(count==5) {LCDSendWord("秒钟 ");address=0x81; max=59;mini=0;} if(count==4) {LCDSendWord("分钟 ");address=0x83; max=59;mini=0;} if(count==3) {LCDSendWord("小时 ");address=0x85; max=23;mini=0;} if(count==6) {LCDSendWord("星期 ");address=0x8b; max=7;mini=1;} if(count==2) {LCDSendWord("日期 ");address=0x87; max=31; mini=1;} if(count==1) {LCDSendWord("月份 ");address=0x89; max=12;mini=1;} if(count==0) {LCDSendWord("年份 ");address=0x8d; max=99;mini=0;} item=read1302(address);//读取DS1302某地址上的数值赋给item item=(item/16)*10+item%16; if(k2==0) //加 item++; //数加 1 if(k3==0) //-减 item--; //数减 1 if(item>max) item=mini; //查看数值有效范围 if(item<mini) item=max; writeClkBye(0x8e,0x00); item=(item/10)*16+item%10; writeClkBye(address-1,item); //将调整好的item值写入DS1302 UpDate(); } /*键盘扫描*/ void keyscan () { if (k1==0) // 设置时间 { DelayMs(10); //按键消抖 if(k1==0&&w==0) //当是正常状态时就进入调时状态 { w=1; //进入调时 SetTime(next); //调整 } if(k1==0&&w==1) //当是调时状态 本键用于调整下一项 { next++; if(next>=7) {next= 0;} SetTime(next); //调整 } while(k1==0); //等待键松开 } if(k4==0) // 当在调时状态时就退出调时 { DelayMs(10); //按键消抖 if(k4==0&&w==1) { w=0;next=0; Write_Cmd(0x01); //清除LCD的显示内容 } while(k4==0); //等待键松开 } if (k2==0) //加调整 { DelayMs(10); //按键消抖 if(k2==0&&w==1) { SetTime(next); //调整 } while(k2==0); //等待键松开 } if (k3==0) //减调整 { DelayMs(10); //按键消抖 if(k3==0&&w==1) { SetTime(next); //调整 } while(k3==0); //等待键松开 } } /***开机画面***/ void welcome() { LCDTestWord(0,0x81); LCDSendWord("万年历设计"); LCDTestWord(0,0x91); LCDSendWord("指导:…"); LCDTestWord(0,0x89); LCDSendWord("制作:…"); LCDTestWord(0,0x99); LCDSendWord("阳光总在风雨后"); } bit GetMoonDay(uchar LunarMonth,uint TableAddr) { uchar temp; switch (LunarMonth) //LunarMonth指向农历月份 { case 1: { temp=YearCode[TableAddr]&0x08; //1月,对应年份表里第一字节的BIT3位 if (temp==0) return(0); //为0,月小 else return(1); //为1,月大 } case 2: { temp=YearCode[TableAddr]&0x04; //2月,对应年份表里第一字节的BIT2位 if (temp==0) return(0); //为0,月小 else return(1); //为1,月大 } case 3: { temp=YearCode[TableAddr]&0x02; //3月,对应第一字节的BIT1位 if (temp==0) return(0); //为0,月小 else return(1); //为1,月大 } case 4: { temp=YearCode[TableAddr]&0x01; //1月,对应第一字节的BIT0位 if (temp==0) return(0); //为0,月小 else return(1); //为1,月大 } case 5: { temp=YearCode[TableAddr+1]&0x80; //5月,对应第二字节的BIT7位 if (temp==0) return(0); //为0,月小 else return(1); //为1,月大 } case 6: { temp=YearCode[TableAddr+1]&0x40; //6月,对应第二字节的BIT6位 if (temp==0) return(0); //为0,月小 else return(1); //为1,月大 } case 7: { temp=YearCode[TableAddr+1]&0x20; //7月,对应第二字节的BIT5位 if (temp==0) return(0); //为0,月小 else return(1); //为1,月大 } case 8: { temp=YearCode[TableAddr+1]&0x10; //8月,对应第二字节的BIT4位 if (temp==0) return(0); //为0,月小 else return(1); //为1,月大 } case 9: { temp=YearCode[TableAddr+1]&0x08; //9月,对应第二字节的BIT3位 if (temp==0) return(0); //为0,月小 else return(1); //为1,月大 } case 10: { temp=YearCode[TableAddr+1]&0x04; //10月,对应第二字节的BIT2位 if (temp==0) return(0); //为0,月小 else return(1); //为1,月大 } case 11: { temp=YearCode[TableAddr+1]&0x02; //11月,对应第二字节的BIT1位 if (temp==0) return(0); //为0,月小 else return(1); //为1,月大 } case 12: { temp=YearCode[TableAddr+1]&0x01; //12月,对应第二字节的BIT0位 if (temp==0) return(0); //为0,月小 else return(1); //为1,月大 } case 13: { temp=YearCode[TableAddr+2]&0x80; //13月,对应第三字节的BIT7位 if (temp==0) return(0); //为0,月小 else return(1); //为1,月大 } } } void Conversion(uchar year,uchar month,uchar day) { uchar temp1,temp2,temp3,MonthP;//temp3,temp4分别表示春节距元旦的天数 uint temp4,TableAddr; //公历日离元旦的天数 bit flag2,flag_y; temp1=year/16; //BCD->hex 先把数据转换为十六进制 高位 temp2=year%16; //低位 year=temp1*10+temp2; //把 年 数据 转换成16进制 temp1=month/16; //月份 高位 temp2=month%16; //月份 低位 month=temp1*10+temp2; //把 月 数据 转换成16进制 temp1=day/16; //日期 高位 temp2=day%16; //日期 低位 day=temp1*10+temp2; //把 日 数据 转换成16进制 TableAddr=year*0x03; //定位数据表地址 LCDTestWord(0,0x80); LCDSendWord("20"); temp1=YearCode[TableAddr+2]&0x60; //取当年春节所在的公历月份 年份表中第三字节BIT6-5表示春节的公历月份 temp1=_cror_(temp1,5); //循环右移5位,得到 春节所在的公历月份 temp2=YearCode[TableAddr+2]&0x1f; //取当年春节所在的公历日 年份表中第三字节BIT4-0表示当年春节所在的公历日 if(temp1==0x01) // 计算当年春年离当年元旦的天数,春节只会在公历1月或2月 temp3=temp2-1; //假如春节在公历1月,则元旦离春节的天数为 temp2-1 天 else temp3=temp2+0x1f-1; //假如春节在公历2月,则无旦离春节的天数为 temp2+0x1f-1 天 if (month<10) temp4=DayCode1[month-1]+day-1; //0到8月某日距元旦的天数 else temp4=DayCode2[month-10]+day-1; //9月开始的某一天距元旦的天数 if ((month>0x02)&&(year%0x04==0)) //如果公历月大于2月并且该年的2月为闰月,天数加1 temp4+=1; //计算机出公历日距元旦的天数和春节距元旦的天数,则是为了比较公历日是在春节前还是春节后 //如果temp3>temp4 则 公历日在春节之前 if (temp4>=temp3) //公历日在春节后或就是春节当日使用下面代码进行运算 { temp4-=temp3; //公历日离春节的天数 因为公历日在春节后 所以为temp4-temp3 month=0x01; MonthP=0x01; //LunarMonth为月份指向,公历日在春节前或就是春节当日LunarMonth指向首月 flag2=GetMoonDay(MonthP,TableAddr); //检查该农历月为大小还是小月,大月返回1,小月返回0 flag_y=0; if(flag2==0) //GetMoonDay()函数返回的是0 {temp1=0x1d;} //小月29天 else //GetMoonDay()函数返回的是1 {temp1=0x1e;} //大月30天 temp2=YearCode[TableAddr]&0xf0; //年份数据表中第1字节BIT7-4为闰月,为0则这年无闰月,如为1,表示有闰月 temp2=_cror_(temp2,4); //从数据表中取该年的闰月月份,如为0,则该年无闰月 BIT3-0表示阴历1到4月的大小 1为大 0 为小 while(temp4>=temp1) { temp4-=temp1; MonthP+=1; if(month==temp2) { flag_y=~flag_y; if(flag_y==0)month+=1; } else month+=1; flag2=GetMoonDay(MonthP,TableAddr); if(flag2==0)temp1=0x1d; else temp1=0x1e; } day=temp4+1; } else { //公历日在春节前使用下面代码进行运算 temp3-=temp4; //公历日离春节的天数 因为公历日在春节前 所以为temp3-temp4 if (year==0x00){year=0x63;} else year-=1; TableAddr-=0x03; month=0x0c; temp2=YearCode[TableAddr]&0xf0; //格式第一字节BIT7-4位表示闰月月份,为0,则无闰月,BIT3-0对应阴历第1-4月的大小, temp2=_cror_(temp2,4); if (temp2==0)MonthP=0x0c; else MonthP=0x0d; // /* MonthP为月份指向,如果当年有闰月,一年有十三个月,月指向13,无闰月指向12*/ flag_y=0; flag2=GetMoonDay(MonthP,TableAddr); if(flag2==0)temp1=0x1d; else temp1=0x1e; while(temp3>temp1) { temp3-=temp1; MonthP-=1; if(flag_y==0)month-=1; if(month==temp2)flag_y=~flag_y; flag2=GetMoonDay(MonthP,TableAddr); if(flag2==0)temp1=0x1d; else temp1=0x1e; } day=temp1-temp3+1; } c_moon=1; temp1=year/10; temp1=_crol_(temp1,4); temp2=year%10; LunarYear=temp1|temp2; temp1=month/10; temp1=_crol_(temp1,4); temp2=month%10; LunarMonth=temp1|temp2; temp1=day/10; temp1=_crol_(temp1,4); temp2=day%10; LunarDay=temp1|temp2; } void Displaynongli() { uchar LunarYearD,ReYear; Conversion(year,month,day); LCDTestWord(0,0x88); //显示在LCD的0X94位置上 LCDSendWord("农历"); LCDTestWord(1,LunarMonth/16+0x30); //农历月十位 LCDTestWord(1,LunarMonth%16+0x30); //农历月个位 LCDSendWord("月"); LCDTestWord(1,LunarDay/16+0x30); //农历日十位 LCDTestWord(1,LunarDay%16+0x30); //农历日个位 LunarYearD=(LunarYear/16)*10+LunarYear%16; //农历年转换成10进制数 ReYear=LunarYearD%12; //农历年模12,取余运算 switch(ReYear) { case 0: LCDTestWord(0,0x8e);LCDSendWord("龙年");break; //余0即整除 农历 龙年 case 1: LCDTestWord(0,0x8e);LCDSendWord("蛇年");break; //蛇年 case 2: LCDTestWord(0,0x8e);LCDSendWord("马年");break; case 3: LCDTestWord(0,0x8e);LCDSendWord("羊年");break; case 4: LCDTestWord(0,0x8e);LCDSendWord("猴年");break; case 5: LCDTestWord(0,0x8e);LCDSendWord("鸡年");break; case 6: LCDTestWord(0,0x8e);LCDSendWord("狗年");break; case 7: LCDTestWord(0,0x8e);LCDSendWord("猪年");break; case 8: LCDTestWord(0,0x8e);LCDSendWord("鼠年");break; case 9: LCDTestWord(0,0x8e);LCDSendWord("牛年");break; case 10 CDTestWord(0,0x8e);LCDSendWord("虎年");break;case 11 CDTestWord(0,0x8e);LCDSendWord("兔年");break;} } /***主程序***/ main() { k1=1; k2=1; k3=1; k4=1; Init_ST7920(); welcome(); delay(3000); init1302(); Init_ST7920(); while(1) { DisplayYear(); //显示年 DisplayMonth(); //显示月 DisplayDay(); //显示日 DisplayWeek(); //显示星期 DisplayHour(); //显示时 DisplayMin(); //显示分 DisplaySec(); //显示秒 Displaynongli(); //显示农历 keyscan(); //键盘扫描 } |
| 欢迎光临 迅维网 (https://www.chinafix.com/) | Powered by Discuz! X3.4 |