有用過DS1302的親嗎,幫我看一下?
----------------2017.8.9更新------------------
額,源程序和電路圖如下:
51黑電子鐘求助.png (103.29 KB, 下載次數: 68)
下載附件
DS1302電子鐘原理圖
2017-8-9 19:12 上傳
- #include<reg51.h>
- #include<string.h>
- #include<intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- sbit SDA = P3^4;// 實物
- sbit CLK = P3^6;
- sbit RST = P3^5;
- sbit EN = P2^7;
- sbit RW = P2^5;
- sbit RS = P2^6;
- sbit K1 = P3^1;
- sbit K2 = P3^0;
- sbit K3 = P3^2;
- sbit K4 = P3^3;
- uchar tCount = 0;
- //一年中每個月的天數,2月的天數由年份決定
- uchar MonthsDays[] = { 0,31,0,31,30,31,30,31,31,30,31,30,31 };
- uchar *WEEK[]= {"SUN","MON","TUS","WEN","THU","FRI","SAT"};
- //LCD顯示緩沖
- uchar LCD_DSY_BUFFER1[] = {"DATE 00-00-00 "};//???為什么要空4鍵?----為后面的YMHD等留空間
- uchar LCD_DSY_BUFFER2[] = {"TIME 00:00:00 "};
- uchar DateTime[7] = {0, 0, 0x12, 0x01, 0x01, 0x02, 0x13}; //所讀取的日期時間
- char Adjust_Index = -1;//當前調節的時間對象(不調節秒與周)
- uchar Change_Flag[] = "-MHDM-Y";
- //----------------------------------------------------
- //延時
- //----------------------------------------------------
- void DelayMS(uint x)
- {
- uchar i;
- while(x--) for(i=0;i<120;i++);
- }
- //----------------------------------------------------
- //向DS1302寫入一個字節
- //----------------------------------------------------
- void Write_A_Byte_TO_DS1302(uchar x)
- {
- uchar i;
- for(i=0;i<8;i++)
- {
- SDA = x & 0x01;
- x >>= 1;
- CLK = 1;
- _nop_();
- CLK = 0;
- _nop_();
- }
- }
- //----------------------------------------------------
- //從DS1302讀取一字節
- //----------------------------------------------------
- uchar Get_A_Byte_FROM_DS1302()
- {
- uchar i,b,t;
- for(i = 0 ;i < 8 ;i++)
- {
- t = SDA;
- b = (b>>=1) | (t<<7); //3
-
- CLK = 1;
- _nop_();
- CLK = 0;
- _nop_();
- }
- //BCD碼轉換
- return b / 16 * 10+ b % 16;
- }
- //------------------------------------------------------
- //向DS1302某地址寫入數據
- //------------------------------------------------------
- void Write_DS1302(uchar addr,uchar dat)
- {
- RST = 0;
- _nop_();
- CLK = 0;
- _nop_();
- RST = 1;
- _nop_();
- Write_A_Byte_TO_DS1302(addr);
- Write_A_Byte_TO_DS1302(dat);
- RST = 0;
- _nop_();
- }
- //------------------------------------------------------
- //從DS1302指定位置讀數據
- //------------------------------------------------------
- uchar Read_Data(uchar addr)
- {
- uchar dat;
- RST = 0;
- _nop_();
- CLK = 0;
- _nop_();
- RST = 1;
- _nop_();
- Write_A_Byte_TO_DS1302(addr);
- dat = Get_A_Byte_FROM_DS1302();
-
- RST = 0; //2.以下為DS1302復位的穩定時間,必須的。
- _nop_();
- CLK = 1;
- _nop_();
- SDA = 0;
- _nop_();
- SDA = 1;
- _nop_();
- // CLK =1;
- // RST=0;
- return dat;
- }
- //------------------------------------------------------
- //設置時間
- //------------------------------------------------------
- void SET_DS1302() //(初始化)
- {
- uchar i;
- //寫控制字,取消寫保護
- Write_DS1302(0x8E,0x00);
- //分時日年月依次寫入
- for(i = 1; i < 7; i++ )
- {
- 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(){
- uchar state;
- RS=0;RW=1;EN=1;DelayMS(1);state = P0; EN = 0; DelayMS(1);
- return state;
- }
- //------------------------------------------------------
- //忙等待
- //-------------------------------------------------------
- void LCD_Busy_Wait()
- {
- while((Read_LCD_State() & 0x80) == 0x80);
- DelayMS(5);
- }
- //------------------------------------------------------
- //向LCD寫數據
- //------------------------------------------------------
- void Write_LCD_Data(uchar dat)
- {
- LCD_Busy_Wait();
- RS = 1;
- RW = 0;
- EN = 0;
- P0 = dat;
- DelayMS(1);
- EN = 1;
- DelayMS(5);
- EN = 0;
- }
- //------------------------------------------------------
- //寫LCD指令
- //------------------------------------------------------
- void Write_LCD_Command(uchar cmd)
- {
- LCD_Busy_Wait();
- RS = 0;
- RW = 0;
- EN = 0;
- P0 = cmd;
- DelayMS(1);
- EN = 1;
- DelayMS(5);
- EN = 0;
- }
- //------------------------------------------------------
- //LCD初始化
- //------------------------------------------------------
- void Init_LCD()
- {
- Write_LCD_Command(0x38);DelayMS(1);
- Write_LCD_Command(0x0F);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)
- {
- 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);
- }
- }
- //------------------------------------------------------
- //日期與時間值轉換為數字字符
- //------------------------------------------------------
- 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);
- }
- //------------------------------------------------------
- //求星期幾
- //------------------------------------------------------
- void RefreshWeekDay()
- {
- uint i,d,w = 5;
- 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]--;
- MonthsDays[2] = isLeapYear(2000 + DateTime[6]) ? 29 : 28;
- if(DateTime[3] > MonthsDays[DateTime[4]] )
- DateTime[3] = MonthsDays[DateTime[4]];
- RefreshWeekDay();
- break;
-
- case 4://月
- if(x == 1 && DateTime[4] < 12 ) DateTime[4]++;
- if(x ==-1 && DateTime[4] > 1 ) DateTime[4]--;
- MonthsDays[2] = isLeapYear(2000 + DateTime[6]) ? 29 : 28;
- if(DateTime[3] > MonthsDays[DateTime[4]] )
- DateTime[3] = MonthsDays[DateTime[4]];
- RefreshWeekDay();
- break;
-
- case 3://日
- MonthsDays[2] = isLeapYear(2000 + DateTime[6]) ? 29 : 28;
- 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 = -5000 / 256;
- TL0 = -5000 % 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);
- }
- //------------------------------------------------------
- //鍵盤中斷
- //------------------------------------------------------
- void EX_INT0() interrupt 0
- {
- if(K1==0)//選擇調整對象(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;//跳過對星期的調節
- 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();//將調整后的時間寫入DS1302
- LCD_DSY_BUFFER2[13] = ' ';
- LCD_DSY_BUFFER2[14] = ' ';
- LCD_DSY_BUFFER2[15] = ' ';
- Adjust_Index = -1;//操作索引重設為-1,時間繼續正常顯示
- }
- }
- //------------------------------------------------------
- //主程序
- //------------------------------------------------------
- //void Int0Configuration()
- //{
- // //設置INT0
- // IT0=1;//跳變沿出發方式(下降沿)
- // EX0=1;//打開INT0的中斷允許。
- // EA=1;//打開總中斷
- //}
- void main()
- {
- Init_LCD();//液晶初始化
- IE = 0x83;//允許INT0,T0中斷
- IP = 0x01;
- IT0 = 0X01;
- TMOD = 0x01;
- TH0 = -5000 / 256;
- TL0 = -5000 % 256;
- TR0 = 1;
- while(1)
- {
- //如果未執行調整操作則正常讀取當前時間
- if(Adjust_Index == -1) GetTime();
- }
- }
復制代碼
全部資料下載地址:
DS1302設計的電子鐘.rar
(60.13 KB, 下載次數: 7)
2017-8-9 19:18 上傳
點擊文件名下載附件
|