《DS1302万年历.docx》由会员分享,可在线阅读,更多相关《DS1302万年历.docx(47页珍藏版)》请在三一办公上搜索。
1、DS1302万年历/*功能:显示时间日期万年历。上电显示时间,格式:小时-分钟-秒。按下key1显示日期,格式:月-天-星期按下key2调节闪烁位置,进行更改时间操作按下key3时间或日期增加按下key4时间或日期减少按下key5返回,也可以按key2返回显示时间画面调整时间或日期时,要调节的那个变量会闪烁此程序重新上电后,时间会恢复初始值。如果不想重新输入时间,可将初始化中设置时间去掉晶振:11.0592MHz注:DS1302显示85、45、40和问号等问题时,在读操作结束后将数据端IO拉低即可解决*/#include<reg51.h>#define uchar unsigned c
2、har#define uint8 unsigned intsbit io_DS1302_RST = P25 ; sbit io_DS1302_IO = P26 ; sbit io_DS1302_SCLK = P27 ; char shi,fen,miao,day,month,year,week,tiaoshijian,tiaoriqi;uchar table12= 0xc0,0xf9,0xa4,0xb0, /0 1 2 30x99,0x92,0x82,0xf8, /4 5 6 70x80,0x90,0xbf,0xbf; /8 9 - - #define KEY_1 0x0e /0000 111
3、0 #define KEY_2 0x0d /0000 1101 #define KEY_3 0x0b /0000 1011 #define KEY_4 0x07 /0000 0111 #define KEY_5 0x10 /0001 0000 #define KEY_NULL 0x1f /0001 1111#define KEY_PRESS 0x80 /1000 0000#define KEY_LONG 0x40 /0100 0000#define KEY_STATE_INIT 0 #define KEY_STATE_PRESS 1#define KEY_STATE_LONG 2#define
4、 KEY_STATE_UP 3#define KEY_LONG_PERIOD 20 #define KEY_CONTINUE_PERIOD 10bit set;bit dao1S=0; /1s时间到标志位bit dao2MS=0;/2ms时间到标志位bit dao10MS;/10ms时间到标志位bit ss,mm,ff,yue,tian,xq; /时,秒,分,月,天,星期sbit key1=P30; /切换时间,日期显示sbit key2=P31; /调节调整位置,按一次变化一个位置sbit key3=P32; /加sbit key4=P33; /减sbit key5=P34; /返回int
5、main_flag=0;/,exit_flag,up_flag,down_flag; void Time0_int TMOD=0X01;TH0=0XF8; /11.0592MHz 定时2msTL0=0XCC; TR0=1;ET0=1;uchar KeyScan if(key1=0) return KEY_1; if(key2=0) return KEY_2; if(key3=0) return KEY_3; if(key4=0) return KEY_4;if(key5=0) return KEY_5; return KEY_NULL;uchar GetKeyuchar keyRetu=0,k
6、eyTemp=KEY_NULL; static uchar s_keyState=KEY_STATE_INIT,keyTime=0,keyLast=KEY_NULL; keyTemp=KeyScan;switch (s_keyState)case KEY_STATE_INIT: / 0if(keyTemp!=KEY_NULL) s_keyState=KEY_STATE_PRESS; break;case KEY_STATE_PRESS:/ 1if(keyTemp!=KEY_NULL) s_keyState=KEY_STATE_LONG;keyTime=0; keyLast=keyTemp; e
7、lses_keyState=KEY_STATE_INIT; break;case KEY_STATE_LONG: / 2if(keyTemp=KEY_NULL) s_keyState=KEY_STATE_INIT; keyRetu=(keyLast|KEY_PRESS); elseif(+keyTime>=KEY_LONG_PERIOD) s_keyState=KEY_STATE_UP; keyTime=0; break;case KEY_STATE_UP: / 3if(keyTemp=KEY_NULL) s_keyState=KEY_STATE_INIT; elseif(+keyTime
8、>=KEY_CONTINUE_PERIOD) keyTime=0; keyRetu=(keyLast|KEY_LONG); break;return keyRetu;uchar bcdtoasc(uchar cha) /16进制转换成10进制return (cha/16)*10+(cha%16);uchar asctobcd(uchar cha) /10进制转换成16进制return (cha/10)*16+(cha%10);void timer interrupt 1 static count=0;static count1=0;TH0=0XF8;TL0=0XCC;dao2MS=1; /
9、定时2mscount+;if(+count1=5) /定时10ms时间到count1=0;dao10MS=1;if(!(count%25) set = !set; /50ms取反一次,产生闪烁效果if(count=500) /定时1s时间到count=0;dao1S=1; /-常数宏-/ #define DS1302_SECOND_WRITE 0x80 /写时钟芯片的寄存器位置 #define DS1302_MINUTE_WRITE 0x82 #define DS1302_HOUR_WRITE 0x84 #define DS1302_WEEK_WRITE 0x8A #define DS1302
10、_DAY_WRITE 0x86 #define DS1302_MONTH_WRITE 0x88 #define DS1302_YEAR_WRITE 0x8C #define DS1302_SECOND_READ 0x81 /读时钟芯片的寄存器位置 #define DS1302_MINUTE_READ 0x83 #define DS1302_HOUR_READ 0x85 #define DS1302_WEEK_READ 0x8B #define DS1302_DAY_READ 0x87 #define DS1302_MONTH_READ 0x89 #define DS1302_YEAR_READ
11、 0x8D /-操作宏-/ #define DS1302_SCLK_HIGH io_DS1302_SCLK = 1 ; #define DS1302_SCLK_LOW io_DS1302_SCLK = 0 ; #define DS1302_IO_HIGH io_DS1302_IO = 1 ; #define DS1302_IO_LOW io_DS1302_IO = 0 ; #define DS1302_IO_READ io_DS1302_IO #define DS1302_RST_HIGH io_DS1302_RST = 1 ; #define DS1302_RST_LOW io_DS1302
12、_RST = 0 ; /* * 保存时间数据的结构体 * */ struct uint8 Second ; uint8 Minute ; uint8 Hour ; uint8 Day ; uint8 Week ; uint8 Month ; uint8 Year ; CurrentTime ; /* * Function: static void v_DS1302Write_f( uint8 Content ) * * Description:向DS1302写一个字节的内容 * * Parameter:uint8 Content : 要写的字节 * * * */ void delay(ucha
13、r z)uchar a,b;for(a=z;a>0;a-)for(b=110;b>0;b-); static void v_DS1302Write_f( uint8 Content ) uint8 i ; for( i = 8 ; i > 0 ; i- ) if( Content & 0x01 ) DS1302_IO_HIGH /IO=1 else DS1302_IO_LOW /IO=0 Content >>= 1 ; DS1302_SCLK_HIGH /SCLK=1DS1302_SCLK_LOW /SCLK=0 /* * Function: static uint8 v_
14、DS1302Read_f( void ) * * Description: 从DS1302当前设定的地址读取一个字节的内容 * * Parameter: * * Return: 返回读出来的值(uint8) * */ static uint8 v_DS1302Read_f( void ) uint8 i, ReadValue ; DS1302_IO_HIGH for( i = 8 ; i > 0 ; i- ) ReadValue >>= 1 ; if( DS1302_IO_READ ) ReadValue |= 0x80 ; else ReadValue &= 0x7f ; DS1
15、302_SCLK_HIGH DS1302_SCLK_LOW return ReadValue ; /* * Function: void v_DS1302WriteByte_f( uint8 Address, uint8 Content ) * * Description: 从DS1302指定的地址写入一个字节的内容 * * Parameter: Address: 要写入数据的地址 * * Content: 写入数据的具体值 * * Return: * */ void v_DS1302WriteByte_f( uint8 Address, uint8 Content ) DS1302_RST_
16、LOW DS1302_SCLK_LOW DS1302_RST_HIGH v_DS1302Write_f( Address ) ; v_DS1302Write_f( Content ) ; DS1302_RST_LOW DS1302_SCLK_HIGH /* * Function: uint8 v_DS1302ReadByte_f( uint8 Address ) * * Description:从DS1302指定的地址读出一个字节的内容 * * Parameter:Address: 要读出数据的地址 * * * * Return: 指定地址读出的值(uint8) * */ uint8 v_DS
17、1302ReadByte_f( uint8 Address ) uint8 ReadValue ; DS1302_RST_LOW DS1302_SCLK_LOW DS1302_RST_HIGH v_DS1302Write_f( Address ) ; ReadValue = v_DS1302Read_f ; DS1302_RST_LOW DS1302_SCLK_HIGH DS1302_IO_LOW /字节读操作完后,将DS1302的IO端口置零就可消除85、45和?闪现等问题return ReadValue ; /* * Function: void v_ClockInit_f( void )
18、 * * Description:初始化写入DS1302时钟寄存器的值(主程序中只需调用一次即可) * * Parameter: * * * * Return: * */ void v_ClockInit_f( void ) if( v_DS1302ReadByte_f( 0xc1) != 0xf0 ) v_DS1302WriteByte_f( 0x8e, 0x00 ) ; /允许写操作 v_DS1302WriteByte_f( DS1302_YEAR_WRITE, 0x11 ) ; /年 v_DS1302WriteByte_f( DS1302_WEEK_WRITE, 0x01 ) ; /星期
19、 v_DS1302WriteByte_f( DS1302_MONTH_WRITE, 0x01 ) ; /月 v_DS1302WriteByte_f( DS1302_DAY_WRITE, 0x03 ) ; /日 v_DS1302WriteByte_f( DS1302_HOUR_WRITE, 0x15 ) ; /小时 v_DS1302WriteByte_f( DS1302_MINUTE_WRITE, 0x21 ) ; /分钟 v_DS1302WriteByte_f( DS1302_SECOND_WRITE, 0x30 ) ; /秒 v_DS1302WriteByte_f( 0x90, 0xa5 )
20、 ; /充电 v_DS1302WriteByte_f( 0xc0, 0xf0 ) ; /判断是否初始化一次标识写入 v_DS1302WriteByte_f( 0x8e, 0x80 ) ; /禁止写操作 /* * Function: void v_ClockUpdata_f( void ) * * Description:读取时间数据,并保存在结构体CurrentTime中 * * Parameter: * * * * Return: * */ void v_ClockUpdata_f( void ) CurrentTime.Second = v_DS1302ReadByte_f( DS1302
21、_SECOND_READ ) ; CurrentTime.Minute = v_DS1302ReadByte_f( DS1302_MINUTE_READ ) ; CurrentTime.Hour = v_DS1302ReadByte_f( DS1302_HOUR_READ ) ; CurrentTime.Day = v_DS1302ReadByte_f( DS1302_DAY_READ ) ; CurrentTime.Month = v_DS1302ReadByte_f( DS1302_MONTH_READ ) ; CurrentTime.Week = v_DS1302ReadByte_f(
22、DS1302_WEEK_READ ) ; CurrentTime.Year = v_DS1302ReadByte_f( DS1302_YEAR_READ ) ; void updatamiao = (CurrentTime.Second&0x70)>>4)&0x0f)*10 + (CurrentTime.Second&0x0F);fen = (CurrentTime.Minute&0x70)>>4)&0x0f)*10 + (CurrentTime.Minute&0x0F);shi = (CurrentTime.Hour&0x30)>>4)&0x0f)*10 + (Cur
23、rentTime.Hour&0x0F);day=(CurrentTime.Day&0x30)>>4)&0x0f)*10 + (CurrentTime.Day&0x0F); month=(CurrentTime.Month&0x10)>>4)&0x0f)*10 + (CurrentTime.Month&0x0F); week=CurrentTime.Week; year=(CurrentTime.Year&0xf0)>>4)&0x0f)*10 + (CurrentTime.Year&0x0F); void displayriqi /显示日期 /因为当LE为1时,锁存器是透
24、明的,应该先使P0清零,即一个段也不被点亮P0=tablemonth%10; /将第1位的值放入锁存器 ,显示第1位if(set&yue)P0=0XFF;P1=0x02; /位选通delay(10); P0=tablemonth/10; /显示第2位if(set&yue)P0=0XFF;P1=0x01;delay(10);P0=table11; /显示_P1=0x04;delay(10); P0=tableday%10; /显示第3位if(set&tian)P0=0XFF;P1=0x10;delay(10); P0=tableday/10; /显示第4位if(set&tian)P0=0XFF;
25、P1=0x08;delay(10);P0=tableweek;if(set&xq)P0=0XFF; P1=0x80;delay(10); /if(set&(k=main_flag-1)/P0=0XFF;void displayshijianP0=tablemiao%10; / 将第1位的值放入锁存器 ,显示第1位if(set&mm)P0=0XFF;P1=0x80; /位选通delay(5); P0=tablemiao/10; /显示第2位if(set&mm)P0=0XFF;P1=0x40;delay(5);P0=table11; /显示_P1=0x20;delay(5); P0=tablefe
26、n%10; /显示第3位if(set&ff)P0=0XFF;P1=0x10;delay(5); P0=tablefen/10; /显示第4位if(set&ff)P0=0XFF;P1=0x08;delay(5);P0=table11; /显示_P1=0x04;delay(5); P0=tableshi%10; /显示第5位if(set&ss)P0=0XFF;P1=0x02;delay(5);P0=tableshi/10; /显示第6位if(set&ss)P0=0XFF;P1=0x01;/ delay(5); void main v_ClockInit_f; /初始化设置时间Time0_int;
27、/初始化定时器0EA=1; /开总中断while(1) v_ClockUpdata_f; /读取时间数据,并保存在结构体CurrentTime中 updata;/将读出的数据转换成十进制if(main_flag=1)/main_flag=1显示日期displayriqi; else/main_flag=0显示时间displayshijian;if(dao10MS) dao10MS=0;switch (GetKey)case (KEY_1|KEY_PRESS): /key1按下,日期时间切换 if(+main_flag>=2)main_flag=0; break;case (KEY_2|KE
28、Y_PRESS): /key2按下,调整日期时间 switch (main_flag) case 0: /main_flag=0,调整时间 if(+tiaoshijian>=5)tiaoshijian=0; switch(tiaoshijian)case 1:mm=0;ss=1; break;case 2:ss=0; ff=1; break;case 3:ff=0; mm=1; break;case 4:ff=0;mm=0;ss=0; break;break;case 1: /main_flag=1,调整日期if(+tiaoriqi>=5) tiaoriqi=0; switch(tia
29、oriqi)case 1:xq=0;yue=1; break;case 2:yue=0;tian=1; break;case 3:tian=0;xq=1; break;case 4:tian=0;xq=0;yue=0; break; /end for switch (main_flag) /end for case(KEY_2|KEY_PRESS)break;case (KEY_3|KEY_PRESS): /时间,日期加if(main_flag=0)&(ss=1)/调小时 v_DS1302WriteByte_f(0x8e,0x00); /关写保护shi=bcdtoasc(CurrentTime
30、.Hour);shi+=1;if(shi>=24)shi=0;shi=asctobcd(shi); v_DS1302WriteByte_f(0x84,shi);/write_add(0x04,shi);/写分数据 / shi=read_add(0x04)&0x3f;/读取秒数据 CurrentTime.Hour = v_DS1302ReadByte_f( DS1302_HOUR_READ ) ; shi=(CurrentTime.Hour&0x30)>>4)&0x0f)*10 + (CurrentTime.Hour&0x0F); v_DS1302WriteByte_f(0x8e,0
31、x80); /开写保护displayshijian; else if(main_flag=0)&(ff=1) /调分钟 v_DS1302WriteByte_f(0x8e,0x00); /关写保护fen=bcdtoasc(CurrentTime.Minute);fen+=1;if(fen>=60)fen=0;fen=asctobcd(fen); v_DS1302WriteByte_f(0x82,fen);/write_add(0x04,shi);/写分数据 / shi=read_add(0x04)&0x3f;/读取秒数据 CurrentTime.Minute = v_DS1302ReadBy
32、te_f(DS1302_MINUTE_READ ) ; fen=(CurrentTime.Minute&0x70)>>4)&0x0f)*10 + (CurrentTime.Minute&0x0F); v_DS1302WriteByte_f(0x8e,0x80); /开写保护displayshijian; else if(main_flag=0)&(mm=1)/调秒 v_DS1302WriteByte_f(0x8e,0x00); /关写保护miao=bcdtoasc(CurrentTime.Second);miao+=1;if(miao>=60)miao=0;miao=asctobc
33、d(miao); v_DS1302WriteByte_f(0x80,miao);/write_add(0x04,shi);/写分数据 / shi=read_add(0x04)&0x3f;/读取秒数据 CurrentTime.Second= v_DS1302ReadByte_f(DS1302_SECOND_READ ) ; miao=(CurrentTime.Second&0x70)>>4)&0x0f)*10 + (CurrentTime.Second&0x0F); v_DS1302WriteByte_f(0x8e,0x80); /开写保护displayshijian; else if(
34、main_flag=1)&(yue=1)/调月份 v_DS1302WriteByte_f(0x8e,0x00); /关写保护month=bcdtoasc(CurrentTime.Month);month+=1;if(month>=13)month=0;month=asctobcd(month); v_DS1302WriteByte_f(0x88,month);CurrentTime.Month = v_DS1302ReadByte_f( DS1302_MONTH_READ ) ; month=(CurrentTime.Month&0x10)>>4)&0x0f)*10 + (CurrentTime.Month&0x0F); v_DS1302WriteByte_f(0x8e,0x80); /开写保护displayshijian; else if(main_flag=1)&(tian=1)/调日 v_DS1302WriteByte_f(0x8e,0x00); /关写保护day=bcdtoasc(CurrentTime.Day);day+=1;if(day>=32)day=1;day=asctobcd(day); v_DS1302WriteByte_f(0x86,day);/wr