这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » MCU » 万年历

共12条 1/2 1 2 跳转至

万年历

菜鸟
2014-08-10 12:12:58     打赏
显示日期


显示时间


显示星期


消隐之后的效果


原理图

74ls138


ds1302

key

数码管

单片机


我这次采用的是STC89C52RC的单片机


代码如下:
main.c
#include #include #include #include sbit P10=P1^0;sbit P11=P1^1;sbit P12=P1^2;sbit P13=P1^3; sbit P20=P2^0;sbit P21=P2^1;sbit P22=P2^2;sbit P23=P2^3;sbit P24=P2^4;sbit P25=P2^5;sbit P26=P2^6;sbit P27=P2^7; code unsigned char table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40,0x00};  code unsigned char write_rtc_address[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c}; //秒分时日月周年 最低位读写位 code unsigned char read_rtc_address[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d}; unsigned char l_tmpdate[7]={30,43,21,15,12,2,14};//初始化ds1302的值 unsigned char Result[7]={0x00,0x00,0x00,0x00,0x00,0x00,0x00};//读取ds1302的结果 unsigned char SetValue[7]={0x00,0x00,0x00,0x00,0x00,0x00,0x00};//存储已经设置好的值,该值最后要写入ds1302 unsigned char LS138; unsigned char SetKey;//0x00表示没有按设置键,0x01设置年,0x02设置月,0x03设置日,0x04设置小时,0x05设置分,0x06设置秒 unsigned char Flash,flashTime; unsigned char HexYear; void Delay250ms() //@12.000MHz { unsigned char i, j, k;
_nop_(); i = 2; j = 231; k = 91; do { do { while (--k); } while (--j); } while (--i); } //设置时间、日期、星期 void SetDateTime() { Set_RTC(write_rtc_address,l_tmpdate); } void SetTimer0()//用于控制138扫描数码管的时间 { TL0 = 0x78; //设置定时初值 TH0 = 0xCC; //设置定时初值 TF0 = 0; //清除TF0标志 } void tm1_isr() interrupt 3 using 1 { flashTime++; if(flashTime>50) { if(Flash==0x00) { Flash=0x01; } else { Flash=0x00; } flashTime=0x00; } TL1 = 0xB0; //设置定时初值 TH1 = 0x3C; //设置定时初值 TF1 = 0; //清除TF1标志 } void tm0_isr() interrupt 1 using 1 { SetTimer0(); //用于日期显示,因为显示时只用Result[0..2],所以需要将对应的年、月、日赋值到Result[0..2] if((P21==0)||((SetKey>0x00)&&(SetKey<0x04))) { Result[2]=Result[6]; Result[1]=Result[4]; Result[0]=Result[3]; } //显示星期时不需要数码管轮流显示。 if(P22==0) { P0=table[Result[5]&0x0f]; } else { //数码管轮流显示 switch(LS138) { case 0: P10=0;P11=0;P12=0; P0=table[Result[2]/16]; break; case 1: P10=1;P11=0;P12=0; P0=table[Result[2]&0x0f]; break; case 2: P10=0;P11=1;P12=0; P0=0x40; break; case 3: P10=1;P11=1;P12=0; P0=table[Result[1]/16]; break; case 4: P10=0;P11=0;P12=1; P0=table[Result[1]&0x0f]; break; case 5: P10=1;P11=0;P12=1; P0=0x40; break; case 6: P10=0;P11=1;P12=1; P0=table[Result[0]/16]; break; case 7: P10=1;P11=1;P12=1; P0=table[Result[0]&0x0f]; break; }    } //当按设置键时,对应的数码管进行闪烁。 switch(SetKey) { case 0x01: case 0x04: if((Flash==0x01)&&((LS138==0x01)||(LS138==0x00))) { P0=0x00; } break; case 0x02:case 0x05: if((Flash==0x01)&&((LS138==0x03)||(LS138==0x04))) { P0=0x00; } break; case 0x03:case 0x06: if((Flash==0x01)&&((LS138==0x06)||(LS138==0x07))) { P0=0x00; } break; } LS138++; if(LS138>0x07) { LS138=0x00; } SetTimer0(); } //定时器1,初始化,用于控制按设置键后数码管闪烁的频率 void Timer1Init(void) //50毫秒@12.000MHz { AUXR &= 0xBF; //定时器时钟12T模式 TMOD &= 0x0F; //设置定时器模式 TL1 = 0xB0; //设置定时初值 TH1 = 0x3C; //设置定时初值 TF1 = 0; //清除TF1标志 TR1 = 1; //定时器1开始计时 }
void Timer0Init() { AUXR &= 0x7F; //定时器时钟12T模式 TMOD &= 0xF0; //设置定时器模式 SetTimer0(); TR0 = 1; //定时器0开始计时 ET0 = 1;  }
main() { unsigned char i; int Year,Month,Day,Week; P13=0;SetKey=0x00;Flash=0x00;flashTime=0x00; SetDateTime(); LS138=0x00; Timer0Init();Timer1Init(); EA=1; while(1) { if((LS138==0x00)&&(P13==0)) { if(SetKey==0x00) { Read_RTC(read_rtc_address,Result); for (i=0;i<0x07;i++) { SetValue[i]=Result[i]; } } } //关闭数码管 if(P20==0) { Delay250ms(); P13=!P13; } //按设置键 if(P24==0) { SetKey++; Delay250ms(); if(SetKey>0x06)SetKey=0x01; TR1=1; ET1=1; } if(SetKey!=0x00) { //按+键 if(P25==0) { Plus(SetValue, SetKey); Delay250ms(); } //按-键 if(P26==0) { Sub(SetValue, SetKey); Delay250ms(); } for(i=0;i<0x07;i++) { Result[i]=SetValue[i]; } } //保存结果 if(P27==0) { if(SetKey==0x00) continue; Delay250ms(); SetKey=0x00;TR1=0;ET1=0; for(i=0;i<7;i++) { l_tmpdate[i]=Hex2Bcd(SetValue[i]); } //*******************自动获得星期——开始*************************** //获得星期结果如下: //  0       1      2      3      4      5       6 //星期一,星期二,星期三,星期四,星期五,星期六,星期天 Year=Hex2Bcd(SetValue[6])+2000; Month=Hex2Bcd(SetValue[4]); if((Month==1)||(Month==2)) { Year--; Month=12+Month; } Day=Hex2Bcd(SetValue[3]); Month=2*Month+3*(Month+1)/5; Year=Year+Year/4-Year/100+Year/400; Week=(Day+Month+Year) % 7; //*******************自动获得星期——开始*************************** l_tmpdate[5]=((unsigned char)(Week+1));//根据获得星期的结果,所以要+1; SetDateTime(); } } }

ds1302.c

#include #include #include #include
sbit SCK=P1^4; //时钟 sbit SDA=P3^4; //数据 sbit RST = P1^6;// DS1302复位 sbit P13=P1^3; sbit LS138A=P1^0;  sbit LS138B=P1^1;sbit LS138C=P1^2; 
bit ReadRTC_Flag;//定义读DS1302标志 unsigned char l_tmpdisplay[8]; unsigned char tmpdate[7]={0x00,0x00,0x00,0x00,0x00,0x00,0x00};//秒分时日月周年08-05-15 12:00:00
   /******************************************************************/ /*                    函数声明                                    */ /******************************************************************/ void Write_Ds1302_byte(unsigned char temp);  void Write_Ds1302( unsigned char address,unsigned char dat ); unsigned char Read_Ds1302 ( unsigned char address );

/******************************************************************/ /*                   写一个字节                                   */ /******************************************************************/ void Write_Ds1302_Byte(unsigned  char temp)  {  unsigned char i;  for (i=0;i<8;i++)      //循环8次 写入数据   {     SCK=0;      SDA=temp&0x01;     //每次传输低字节       temp>>=1;   //右移一位      SCK=1;    } }    /******************************************************************/ /*                  写入DS1302                                    */ /******************************************************************/ void Write_Ds1302( unsigned char address,unsigned char dat )      {   RST=0; _nop_();   SCK=0; _nop_();   RST=1;     _nop_();                    //启动   Write_Ds1302_Byte(address); //发送地址   Write_Ds1302_Byte(dat); //发送数据   RST=0;               //恢复 } /******************************************************************/ /*                   读出DS1302数据                               */ /******************************************************************/ unsigned char Read_Ds1302 ( unsigned char address ) {   unsigned char i,temp=0x00;   RST=0; _nop_(); _nop_();   SCK=0; _nop_(); _nop_();   RST=1; _nop_(); _nop_();   Write_Ds1302_Byte(address);   for (i=0;i<8;i++)  //循环8次 读取数据   {   if(SDA)   temp|=0x80; //每次传输低字节 SCK=0; temp>>=1; //右移一位 _nop_();    _nop_();    _nop_();   SCK=1; }    RST=0; _nop_();            //以下为DS1302复位的稳定时间   _nop_(); RST=0; SCK=0; _nop_(); _nop_(); _nop_(); _nop_(); SCK=1; _nop_(); _nop_(); SDA=0; _nop_(); _nop_(); SDA=1; _nop_(); _nop_(); return (temp); //返回 } /******************************************************************/ /*                   读时钟数据                                   */ /******************************************************************/ extern void Read_RTC(unsigned char *address,unsigned char *Rst)         //读取 日历 {  unsigned char i;  for(i=0;i<7;i++)     //分7次读取 秒分时日月周年  {   *Rst=Read_Ds1302(*address);   address++;Rst++;  } } /******************************************************************/ /*                  设定时钟数据                                  */ /******************************************************************/ extern void Set_RTC(unsigned char *address,unsigned char *value)    //设定 日历 { unsigned char i; for(i=0;i<7;i++) { tmpdate[i]=BCD2Hex(*value); value++; }   Write_Ds1302(0x8E,0X00); for(i=0;i<7;i++) //7次写入 秒分时日月周年 { Write_Ds1302(*address,tmpdate[i]); address++; } Write_Ds1302(0x8E,0x80); }

function.c 



 
#include #include #include extern unsigned char Hex2Bcd(unsigned char Hex) { unsigned char L,H,Result; H=(Hex&0xf0)>>0x04; L=Hex&0x0f; Result=H*0x0a+L; return Result; } extern unsigned char BCD2Hex(unsigned char bcd) { unsigned char Result,tmp; tmp=bcd/10; Result=bcd%10; tmp=tmp*16; Result=Result+tmp; return Result; } extern void  Plus(unsigned char *Val,unsigned char SetKey) { int i=0; unsigned char Tmp[7]={0x00,0x00,0x00,0x00,0x00,0x00,0x00}; for(i=0;i<7;i++) { Tmp[i]=Hex2Bcd(Val[i]); } switch(SetKey) { case 0x01: Tmp[6]++;if(Tmp[6]>0x19)Tmp[6]=0x0e; break; case 0x02: Tmp[4]++;if(Tmp[4]>0x0c)Tmp[4]=0x01; break; case 0x03: Tmp[3]++;if(Tmp[3]>0x1f)Tmp[3]=0x01; switch(Tmp[4]) { case 0x02: if((Tmp[6]%0x04)==0x00) { if(Tmp[3]>0x1d) { Tmp[3]=0x01; } } else { if(Tmp[3]>0x1c) { Tmp[3]=0x01; } } break; case 0x04: case 0x06: case 0x09: case 0x0b: if(Tmp[3]>0x1E)Tmp[3]=0x01; break; } break; case 0x04: Tmp[2]++;if(Tmp[2]>0x17)Tmp[2]=0x00; break; case 0x05: Tmp[1]++;if(Tmp[1]>0x3b)Tmp[1]=0x00; break; case 0x06: Tmp[0]++;if(Tmp[0]>0x3b)Tmp[0]=0x00; break; } for(i=0;i<7;i++) { Val[i]=BCD2Hex(Tmp[i]); } } extern void Sub(unsigned char *Val,unsigned char SetKey) { int i; unsigned char Tmp[7]={0x00,0x00,0x00,0x00,0x00,0x00,0x00}; for(i=0;i<7;i++) { Tmp[i]=Hex2Bcd(Val[i]); } switch(SetKey) { case 0x01: Tmp[6]--;if(Tmp[6]<0x0e)Tmp[6]=0x19; break; case 0x02: Tmp[4]--;if(Tmp[4]<0x01)Tmp[4]=0x0c; break; case 0x03: Tmp[3]--; switch(Tmp[4]) { case 0x02: if(Tmp[3]==0x01) { if((Tmp[6]%0x04)==0x00) { Tmp[3]=0x1d; } else { Tmp[3]=0x1c; } } break; case 0x04: case 0x06: case 0x09: case 0x0b: if(Tmp[3]<0x01)Tmp[3]=0x1e; break; case 0x01: case 0x03: case 0x07: case 0x08: case 0x0a: case 0x0c: if(Tmp[3]<0x01)Tmp[3]=0x1f; break; } break; case 0x04: Tmp[2]--;if(Tmp[2]>0x17)Tmp[2]=0x00; break; case 0x05: Tmp[1]--;if(Tmp[0]>0x3b)Tmp[0]=0x00; break; case 0x06: Tmp[0]--;if(Tmp[0]>0x3b)Tmp[0]=0x00; break; }
for(i=0;i<7;i++) { Val[i]=BCD2Hex(Tmp[i]); } }



关键词: STC     51     DS1302    

院士
2014-08-10 21:18:38     打赏
2楼
怎么图基本都挂了?都没有经过上传哦~~~

高工
2014-08-10 21:51:36     打赏
3楼
楼主搭电路的工程浩大哦,哈哈哈

高工
2014-08-11 06:26:12     打赏
4楼
一般说万年历主要指夏历。与太阳、月亮的运行都有关;而不像西历,月份是教皇人为规定的。

菜鸟
2014-08-11 11:00:58     打赏
5楼
……

菜鸟
2014-08-11 11:02:00     打赏
6楼
可能是因为我的图片传到我的QQ空间,然后我的空间有权限限制所以看不见。郁闷ING。

院士
2014-08-12 20:16:12     打赏
7楼

这有什么可郁闷的啊~~

把图片上传过来不就得了嘛


菜鸟
2014-08-13 10:42:45     打赏
8楼
上传了,看看这次能行不。

菜鸟
2014-08-14 16:01:20     打赏
9楼
的确是好东西,多谢楼主分享

菜鸟
2014-08-15 15:16:10     打赏
10楼
客气,客气。

共12条 1/2 1 2 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]