有用过DS1302的亲吗,帮我看一下?
----------------2017.8.9更新------------------
额,源程序和电路图如下:
- #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)
|