|
- #include <reg51.h>
- #include <string.h>
- #define uchar unsigned char
- #define uint unsigned int
- sbit SDA=P1^0; //DS1302 數(shù)據(jù)線
- sbit CLK=P1^1; //DSB1302 時鐘線
- sbit RST=P1^2; //DS1302 復位線
- sbit RS=P2^0; //LCD 寄存器選擇
- sbit RW=P2^1; //LCD 讀/寫控制
- sbit EN=P2^2; //LCD 啟用
- sbit K1=P3^4; //選擇
- sbit K2=P3^5; //加
- sbit K3=P3^6; //減
- sbit K4=P3^7; //確定
- uchar tCount=0;
- uchar dat; //定義參數(shù)
- //一年中每個月的天數(shù),二月的天數(shù)由年份決定
- uchar MonthsDays[]={31,0,31,30,31,30,31,31,30,31,30,31};
- //周日,周一到周六{0,1-6} [讀取 DS1302 時分別是 1-7]
- uchar *WEEK[]={"SUN","MON","TUS","WEN","THU","FRI","SAT"};
- //LCD 顯示緩沖
- uchar LCD_DSY_BUFFER1[]={"0019 00-00-00 "};
- uchar LCD_DSY_BUFFER2[]={"HWW 00:00:00 "};
- uchar DateTime[7]; //所讀取的日期時間
- char Adjust_Index=-1;//當前調(diào)節(jié)的時間對象:秒,分,時,日,月,年(0,1,2,3,4,6)
- uchar Change_Flag[]="-MHDM-Y";
- //(分,時,日,月,年) (不調(diào)節(jié)秒周)
- //延時,向 DS1302 寫、讀一字節(jié)以及從 DS1302 指定位置度、寫數(shù)據(jù)的程序
- //延時---------------------------------------------------
- void DelayMS(uint x)
- {
- uchar i;
- while(x--) for(i=0;i<120;i++);
- }
- //向 DS1302 寫入一個字節(jié)
- void Write_A_Byte_TO_DS1302(uchar x)
- {
- uchar i;
- for(i=0;i<8;i++)
- {
- SDA=x&1;CLK=1; CLK=0; x>>=1;
- }
- }
- //從 DA1302 讀取一字節(jié)---------------------------------------
- uchar Get_A_Byte_FROM_DS1302()
- {
- uchar i,b,t;
- for(i=0;i<8;i++)
- {
- b>>=1; t=SDA;b|=t<<7;CLK=1;CLK=0;
- }
- //BCD 碼轉(zhuǎn)換
- return b/16*10+b%16;
- }
- //從 DS1302 指定的位置讀數(shù)據(jù)--------------------------------------
- uchar Read_Data(uchar addr)
- {
- uchar dat;
- RST=0;CLK=0;RST=1;
- Write_A_Byte_TO_DS1302(addr);
- dat=Get_A_Byte_FROM_DS1302();
- CLK=1;RST=0;
- return dat;
- }
- // 向 DS1302 某地址寫入數(shù)據(jù)-------------------------------------------
- void Write_DS1302(uchar addr,uchar dat)
- {
- CLK=0;RST=1;
- Write_A_Byte_TO_DS1302(addr);
- Write_A_Byte_TO_DS1302(dat);
- CLK=0;RST=0;
- }
- //-------------------------------------------
- //------設(shè)置時間-------------------------------------
- void SET_DS1302()
- {
- uchar i;
- Write_DS1302(0x8E,0x00); //寫控制字,取消寫保護
- for(i=1;i<7;i++) //分時日月年依次寫入
- {
- //分的起始地址 10000010(0x82),后面續(xù)依次是時.日.月.周.年.寫入地址每次遞增 2
- Write_DS1302(0x80+ 2*i,(DateTime[i]/10<<4)|(DateTime[i]%10)); }
- Write_DS1302(0x8E,0x80);//加保護
- }
- //---------------------------------------------------
- //讀取當前日期時間
- //---------------------------------------------------
- void GetTime()
- {
- uchar i;
- for(i=0;i<7;i++)
- {
- DateTime[i]=Read_Data(0x81+2*i);
- }
- }
- //---------------------------------------------------
- //1602LCD 的若干顯示控制代碼
- //uchar Read_LCD_State() 讀 LCD 狀態(tài)
- uchar Read_LCD_State()
- {
- uchar state;
- RS=0;RW=1;EN=1;DelayMS(1);state=P0;EN=0;DelayMS(1);
- return state;
- }
- //void LCD_Busy_Wait() 忙等待
- void LCD_Busy_Wait()
- {
- while((Read_LCD_State()&0x80)==0x80);
- DelayMS(5);
- }
- //void Write_LCD_Data(uchar dat) 向 LCD 寫數(shù)據(jù)
- void Write_LCD_Data(uchar dat)
- {
- LCD_Busy_Wait();
- RS=1;RW=0;EN=0;P0=dat;EN=1;DelayMS(1);EN=0;
- }
- //void Write_LCD_Command(uchar cmd) 寫 LCD 指令
- void Write_LCD_Command(uchar cmd)
- {
- LCD_Busy_Wait();
- RS=0;RW=0;EN=0;P0=cmd;EN=1;DelayMS(1);EN=0;
- }
- // Void Init_LCD() LCD 初始化
- void Init_LCD()
- {
- Write_LCD_Command(0x38);DelayMS(1);
- Write_LCD_Command(0x01);DelayMS(1);
- Write_LCD_Command(0x06);DelayMS(1);
- Write_LCD_Command(0x0c);DelayMS(1);
- }
- //void Set_LCD_POS(uchar P) 設(shè)置液晶顯示位置
- void Set_LCD_POS(uchar p)
- {
- Write_LCD_Command(p|0x80);
- }
- //------------------------------------------------------
- //在 LCD 上顯示字符串
- void Display_LCD_String(uchar p,uchar *s)
- {
- uchar i;
- Set_LCD_POS(p);
- for(i=0;i<16;i++)
- {
- Write_LCD_Data(s[i]); DelayMS(1);
- }
- }
- //-----------------------------------------------------------
- //日期與時間值轉(zhuǎn)換為數(shù)字字符
- void Format_DateTime(uchar d,uchar *a)
- {
- a[0]=d/10+'0';a[1]=d%10+'0';
- }
- //----------------------------------------------------------
- //判斷是否為閏年
- uchar isLeapYear(uint y)
- {
- return(y%4==0&y%100!=0)||(y%400==0);
- }
- //-----------------------------------------------------------
- //求自 2000.1.1 開始的任何一天是星期幾
- //函數(shù)沒有通過,求出總天數(shù)后再求星期幾
- //因為求總天數(shù)可能會超越 uint 的范圍
- void RefreshWeekDay()
- {
- uint i,d,w=5;
- //已知 1999.12.31 是周五
- for(i=2000;i<2000+DateTime[6];i++)
- {
- d=isLeapYear(i)?366:365;
- w=(w+d)%7;
- }
- d=0;
- for(i=1;i<DateTime[4];i++) d+=MonthsDays[i];
- d+=DateTime[3];
- //保存星期,0~6 表示星期日至周六,為了與DS1302 的星期格式匹配,返回值需要加 1 DateTime[5]=(w+d)%7+1;
- }
- //----------------------------------------------------------
- void DateTime_Adjust(char x)
- {
- switch(Adjust_Index)
- {
- case 6://年 00-99
- if(x==1&DateTime[6]<99) DateTime[6]++;
- if(x==-1&DateTime[6]>0) DateTime[6]--;
- //獲取 2 月天數(shù)
- MonthsDays[2]=isLeapYear(2000+DateTime[6])?29:28;
- //如果年份變化后當前月份的天數(shù)大于上限則設(shè)為上限
- if(DateTime[3]>MonthsDays[DateTime[4]])
- DateTime[3]=MonthsDays[DateTime[4]]; RefreshWeekDay();
- //刷新星期
- break;
- case 4:
- //月 01-12
- if(x==1&DateTime[4]<12) DateTime[4]++;
- if(x==-1&DateTime[4]>1) DateTime[4]--;
- //獲取 2 月天數(shù)
- MonthsDays[2]=isLeapYear(2000+DateTime[6])?29:28;
- //如果月份變化后當前月份的天數(shù)大于上限則設(shè)為上限
- if(DateTime[3]>MonthsDays[DateTime[4]])
- DateTime[3]=MonthsDays[DateTime[4]];
- RefreshWeekDay();
- //刷新星期
- break;
- case 3://日00-28/29/30/31;調(diào)節(jié)之前首先根據(jù)年份得出該年中2月的天數(shù)
- MonthsDays[2]=isLeapYear(2000+DateTime[6])?29:28;
- //根據(jù)當前月份決定調(diào)節(jié)日期的上限
- if(x==1&DateTime[3]<MonthsDays[DateTime[4]]) DateTime[3]++;
- if(x==-1&DateTime[3]>0) DateTime[3]--;
- RefreshWeekDay();//刷新星期
- break;
- case 2://時
- if(x==1&DateTime[2]<23) DateTime[2]++;
- if(x==-1&DateTime[2]>0) DateTime[2]--;
- break;
- case 1://分
- if(x==1&DateTime[1]<59) DateTime[1]++;
- if(x==-1&DateTime[1]>0) DateTime[1]--;
- break;
- }
- }
- //---------------------------------------------------------
- //定時器 0 每秒刷新 LCD 顯示
- void T0_INT() interrupt 1
- {
- TH0=-50000/256;
- TL0=-50000%256;
- if(++tCount!=2) return;
- tCount=0;
- //按指定的格式生成待顯示的日期時間串
- Format_DateTime(DateTime[6],LCD_DSY_BUFFER1+5);
- Format_DateTime(DateTime[4],LCD_DSY_BUFFER1+8);
- Format_DateTime(DateTime[3],LCD_DSY_BUFFER1+11);
- //星期 strcpy(LCD_DSY_BUFFER1+13,WEEK[DateTime[5]-1]);
- //時分秒
- Format_DateTime(DateTime[2],LCD_DSY_BUFFER2+5);
- Format_DateTime(DateTime[1],LCD_DSY_BUFFER2+8);
- Format_DateTime(DateTime[0],LCD_DSY_BUFFER2+11);
- //顯示年月日,星期,時分秒
- Display_LCD_String(0x00,LCD_DSY_BUFFER1);
- Display_LCD_String(0x40,LCD_DSY_BUFFER2);
- }
- //---鍵盤中斷(INT0)-----------------------------------------
- void EX_INT0() interrupt 0
- {
- if(K1==0) //選擇調(diào)整對象(Y M D H M)
- {
- while(K1==0);
- if(Adjust_Index==-1||Adjust_Index==1) Adjust_Index=7;
- Adjust_Index--;
- if(Adjust_Index==5) Adjust_Index=4;//跳過對星期的調(diào)節(jié)
- LCD_DSY_BUFFER2[13]='[';
- LCD_DSY_BUFFER2[14]=Change_Flag[Adjust_Index];
- LCD_DSY_BUFFER2[15]=']';
- }
- else if(K2==0)//加
- {
- while(K2==0); DateTime_Adjust(1);
- }
- else if(K3==0)//減
- {
- while(K3==0); DateTime_Adjust(-1);
- }
- else if(K4==0)//確定
- {
- while(K4==0); SET_DS1302(); //將調(diào)整后的時間寫入 1302
- LCD_DSY_BUFFER2[13]=' ';
- LCD_DSY_BUFFER2[14]=' ';
- LCD_DSY_BUFFER2[15]=' ';
- Adjust_Index=-1;
- //操作索引重設(shè)為-1,時間繼續(xù)正常顯示
- }
- }
- //---------------------------------------------------------------
- //主程序 void main()
- void main()
- {
- Init_LCD();//液晶初始化
- IE=0x83; //允許INT0,T0中斷
- IP=0x01;
- IT0=0x01;
- TMOD=0x01;
- TH0=-50000/256;
- TL0=-50000%256;
- TR0=1;
- while(1)
- {
- //如果為執(zhí)行調(diào)整操作則正常讀取當前時間
- if(Adjust_Index==-1) GetTime();
- }
- }
復制代碼 |
-
-
新建 WinRAR 壓縮文件.rar
2021-3-26 13:33 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
14.79 KB, 下載次數(shù): 5, 下載積分: 黑幣 -5
|