基于51单片机的DS1302实时时钟

本讲内容:

      介绍DS1302实时时钟芯片基本知识,演示DS1302例程。

DS1302实时时钟:

      DS1302能提供包括秒、分、时、日期、月份和年份信息。闰年可自行调整,可选择12小时制和24小时制,可以设置AM、PM。

      只通过三根线进行数据的控制和传递:/RST、I/O、SCLK。

      通过备用电源可以让芯片在小于1mw的功率下运作。

      DS1302是总线驱动方式,它不仅要向寄存器写入控制字,还需要读取相应寄存器的数据。要想与DS1302通信,首先要先了解DS1302的控制字。DS1302的控制字如图。

      位7:必须是逻辑1,如果它为0,则不能把数据写入到DS1302中。

      位6:如果为0,则表示存取日历时钟数据,为1表示存取RAM数据。

      位5至位1(A4~A0):指示操作单元的地址。

      位0:为1表示进行读操作,为0表示要进行写操作,控制字后SCLK下降沿读数据,SCLK上升沿写数据。数据是低位在前,高位在后。

      读数据:

      读数据时在紧跟8位的控制字指令后的下一个SCLK脉冲的下降沿,读出DS1302的数据,读出的数据是从最低位到最高位。

      写数据:

      写数据时在紧跟8位的控制字指令后的下一个SCLK脉冲的上升沿,数据被写入DS1302,数据输入也是从最低位(0位)开始。

        DS1302的数据读写是通过I/O串行进行的。当进行一次读写操作时最少要读写两个字节。

      第一个字节是控制字节,就是一个命令,告诉DS1302是读还是写操作,是对RAM还是对CLOCK寄存器操作,以及操作的地址。

       第二个字节就是要读或写的数据了。

       单字节写:

       在进行操作之前先将CE(也可说是RST)置高电平,然后单片机将控制字的位0放到I/O上,当I/O的数据稳定后,将SCLK置高电平,DS1302检测到SCLK的上升沿后就将I/O上的数据读取,然后单片机将SCLK置为低电平,再将控制字的位1放到I/O上,如此反复,将一个字节控制字的8个位传给DS1302。接下来就是传一个字节的数据给DS1302,当传完数据后,单片机将CE置为低电平,操作结束。

      单字节读:

      一开始写控制字的过程和上面的单字节写操作是一样,但是单字节读操作在写控制字的最后一个位,SCLK还在高电平时,DS1302就将数据放到I/O上,单片机将SCLK置为低电平后数据锁存,单片机就可以读取I/O上的数据。如此反复,将一个字节的数据读入单片机。

 

 DS1302实时时钟芯片接口电路:

例程:

/**************DS1302_LCD1602显示****************

*单片机型号:STC89C52RC

*开发环境:KEIL

*名称:DS1302_LCD1602显示   

********************************************************/  

#include<reg52.h>

#define uint unsigned int

#define uchar unsigned char

uchar a,miao,shi,fen,ri,yue,nian,week,flag,temp,KEYn;

#define yh 0x80                                       //第一行的初始位置       

#define er 0x80+0x40                              //第二行初始位置     

sbit wr=P1^1;sbit rs=P1^0;sbit en=P2^5;

sbit SCLK=P2^1;sbit IO=P2^0;      

sbit RST=P2^4;sbit ACC0=ACC^0;

sbit ACC7=ACC^7;

sbit key=P3^7;

sbit SWITCH_S6=P3^0;

sbit SWITCH_S11=P3^1;

sbit SWITCH_S16=P3^2;

uchar code tab1[]={"2009-  -   THU"};

uchar code tab2[]={"  :  :  "};

void delay(int In,int Out)                                                                             

{

 int i,j;

 for(i=0;i<In;i++)

 {for(j=0;j<Out;j++){;}}

}

/******************液晶相关函数********************/

void write_1602com(uchar com)              //液晶写入指令函数    

{

 rs=0;                                                        //置为写入命令    

 P0=com;                                                  //送入数据  

 delay(5,10);

 en=1;                                                      //拉高使能端    

 delay(5,10);

 en=0;                                                      //完成高脉冲      

}

void write_1602dat(uchar dat)

{

 rs=1;                                                       //置为写入数据   

 P0=dat;                                                  //送入数据  

 delay(5,10);

 en=1;

 delay(5,10);

 en=0;

}

void lcd_init(void)

{  

 wr=0;

 write_1602com(0x38);            //设置液晶工作模式    

 write_1602com(0x0c);            //开显示不显示光标   

 write_1602com(0x06);            //整屏不移动,指针加一    

 write_1602com(0x01);

 write_1602com(yh+2);            //字符写入的位置     

 for(a=0;a<14;a++)

 {write_1602dat(tab1[a]);}

 write_1602com(er+4);

 for(a=0;a<8;a++)

 {write_1602dat(tab2[a]);}

}

/******************DS1302相关函数********************/

void write_byte(uchar dat)

{

 ACC=dat;

 RST=1;

 for(a=8;a>0;a--)

 {

  IO=ACC0;

  SCLK=0;

  SCLK=1;

  ACC=ACC>>1;

 }

}

uchar read_byte()

{

 RST=1;

 for(a=8;a>0;a--)

 {

  ACC7=IO;

  SCLK=1;

  SCLK=0;

  ACC=ACC>>1;

 }

 return (ACC);

}

void write_1302(uchar add,uchar dat)

{

 RST=0;

 SCLK=0;

 RST=1;

 write_byte(add);

 write_byte(dat);

 SCLK=1;

 RST=0;

}

uchar read_1302(uchar add)

{

 uchar temp;

 RST=0;

 SCLK=0;

 RST=1;

 write_byte(add);

 temp=read_byte();

 SCLK=1;

 RST=0;

 return(temp);

}

uchar BCD_Decimal(uchar bcd)

{

 uchar Decimal;

 Decimal=bcd>>4;

 return(Decimal=Decimal*10+(bcd&=0x0F));

}

void ds1302_init()

{

 RST=0;

 SCLK=0;

 write_1302(0x80,miao|0x00);     

}

void write_sfm(uchar add,uchar dat)

{

 uchar gw,sw;

 gw=dat%10;

 sw=dat/10;

 write_1602com(er+add);

 write_1602dat(0x30+sw);

 write_1602dat(0x30+gw);

}

void write_nyr(uchar add,uchar dat)

{

 uchar gw,sw;

 gw=dat%10;

 sw=dat/10;

 write_1602com(yh+add);

 write_1602dat(0x30+sw);

 write_1602dat(0x30+gw);

}

void write_week(uchar week)           //写星期函数    

{

 write_1602com(yh+0x0d);

 switch(week)

 {

  case 1:

  {

   write_1602dat('M');        

   write_1602dat('O');     

   write_1602dat('N');

  }break;

      

  case 2:

  {

   write_1602dat('T');    

   write_1602dat('U');     

   write_1602dat('E');

  }break;

       

  case 3:

  {

   write_1602dat('W');   

   write_1602dat('E');  

   write_1602dat('D');

  }break;

       

  case 4:

  {

   write_1602dat('T');    

   write_1602dat('H');  

   write_1602dat('U');

  }break;

       

  case 5:

  {

   write_1602dat('F');   

   write_1602dat('R');    

   write_1602dat('I');

  }break;

       

  case 6:

  {

   write_1602dat('S');    

   write_1602dat('T');     

   write_1602dat('A');

  }break;

       

  case 7:

  {

   write_1602dat('S');   

   write_1602dat('U');   

   write_1602dat('N');

  }break;

 }

}

/******************按键扫描相关函数*****************/

void keyscan()

{

 key=0;

 if(SWITCH_S6==0)               //SWITCH_S6为功能键   

 {

  delay(5,100);

  if(SWITCH_S6==0)

  {

   while(!SWITCH_S6);

   KEYn++;

   if(KEYn==9)

   KEYn=1;

   switch(KEYn)

   {   

    case 1:

    {

     TR0=0;                                             //关闭定时器       

     write_1602com(er+0x0b);                //写入光标位置 

     write_1602com(0x0f);                      //设置光标为闪烁      

     temp=(miao)/10*16+(miao)%10;

     write_1302(0x8e,0x00);

     write_1302(0x80,0x80|temp);                   //miao

     write_1302(0x8e,0x80);

    }break;

    case 2:{write_1602com(er+8);}break;        //fen

    case 3:{write_1602com(er+5);}break;        //shi

    case 4:{write_1602com(yh+0x0f);}break;   //week

    case 5:{write_1602com(yh+0x0b);}break;  //ri

    case 6:{write_1602com(yh+0x08);}break;  //yue

    case 7:{write_1602com(yh+0x05);}break;  //nian

    case 8:

    {

     write_1602com(0x0c);                       //设置光标不闪烁   

     TR0=1;                                              //打开定时器   

     temp=(miao)/10*16+(miao)%10;

     write_1302(0x8e,0x00);

     write_1302(0x80,0x00|temp);            //miao 

     write_1302(0x8e,0x80);                       

    }break;                                                                        

   }       

  }

 }

 if(KEYn!=0)                               

//当SWITCH_S6按下以下。再按以下键才有效

 { 

  if(SWITCH_S11==0)                         //上调键

  {

   delay(5,10);

   if(SWITCH_S11==0)

   {

    while(!SWITCH_S11);

    switch(KEYn)

    {

     case 1:

     {

      miao++;

      if(miao==60){miao=0;}

      write_sfm(0x0a,miao);  //写入新的秒数

      temp=(miao)/10*16+(miao)%10;

      write_1302(0x8e,0x00);

      write_1302(0x80,0x80|temp);

      write_1302(0x8e,0x80);

      write_1602com(er+0x0b);

      //因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置

     }break;

     case 2:

     {

      fen++;

      if(fen==60){fen=0;}

      write_sfm(0x07,fen);

      temp=(fen)/10*16+(fen)%10;

      write_1302(0x8e,0x00);

      write_1302(0x82,temp);

      write_1302(0x8e,0x80);

      write_1602com(er+8);

     }break;

     case 3:

     {

      shi++;

      if(shi==24){shi=0;}

      write_sfm(4,shi);

      temp=(shi)/10*16+(shi)%10;

      write_1302(0x8e,0x00);

      write_1302(0x84,temp);

      write_1302(0x8e,0x80);

      write_1602com(er+5);

     }break;

     case 4:

     {

      week++;

      if(week==8){week=0;}

      write_week(week);        

      write_1602com(yh+0x0f);

     }break;

     case 5:

     {

      ri++;

      if(ri==31){ri=0;}

      write_nyr(10,ri);

      temp=(ri)/10*16+(ri)%10;

      write_1302(0x8e,0x00);

      write_1302(0x86,temp);

      write_1302(0x8e,0x80);

      write_1602com(yh+11);

     }break;

     case 6:

     {

      yue++;

      if(yue==13){yue=0;}

      write_nyr(7,yue);

      temp=(yue)/10*16+(yue)%10;

      write_1302(0x8e,0x00);

      write_1302(0x88,temp);

      write_1302(0x8e,0x80);

      write_1602com(yh+8);

     }break;

     case 7:

     {

      nian++;

      if(nian==100){nian=0;}

      write_nyr(4,nian);

      write_1602com(yh+5);

     }break;

    }

   }

  }

  if(SWITCH_S16==0)

  {

   delay(5,100);

   if(SWITCH_S16==0)

   {

    while(!SWITCH_S16);

    switch(KEYn)

    {

     case 1:

     {

      miao--;

      if(miao==-1){miao=59;}

      write_sfm(0x0a,miao);  //写入新的秒数

      write_1602com(er+0x0b);

      //因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置

     }break;

     case 2:

     {

      fen--;

      if(fen==-1){fen=59;}

      write_sfm(7,fen);

      temp=(fen)/10*16+(fen)%10;

      write_1302(0x8e,0x00);

      write_1302(0x82,temp);

      write_1302(0x8e,0x80);

      write_1602com(er+8);

     }break;

     case 3:

     {

      shi--;

      if(shi==-1){shi=23;}

      write_sfm(4,shi);

      temp=(shi)/10*16+(shi)%10;

      write_1302(0x8e,0x00);

      write_1302(0x84,temp);

      write_1302(0x8e,0x80);

      write_1602com(er+5);

     }break;

     case 4:

     {

      week--;

      if(week==-1){week=7;}

      write_week(week);

      write_1602com(yh+0x0f);

     }break;   

     case 5:

     {

      ri--;

      if(ri==-1){ri=30;}

      write_nyr(10,ri);

      temp=(ri)/10*16+(ri)%10;

      write_1302(0x8e,0x00);

      write_1302(0x86,temp);

      write_1302(0x8e,0x80);

      write_1602com(yh+11);

     }break;

     case 6:

     {

      yue--;

      if(yue==-1){yue=12;}

      write_nyr(7,yue);

      temp=(yue)/10*16+(yue)%10;

      write_1302(0x8e,0x00);

      write_1302(0x88,temp);

      write_1302(0x8e,0x80);

      write_1602com(yh+8);

     }break;   

     case 7:

     {

      nian--;

      if(nian==-1){nian=99;}

      write_nyr(4,nian);

      write_1602com(yh+5);

     }break;           

    }

   }

  }

 }

}

void timer_init(){TMOD=0x11;TH0=0;TL0=0;EA=1;ET0=1;TR0=1;}

void sys_init(void)

{

 lcd_init();

 ds1302_init();

 timer_init();

}

void main()

{

 sys_init();

 while(1){keyscan();}

}

void timer0() interrupt 1

{

 miao = BCD_Decimal(read_1302(0x81));

 fen  = BCD_Decimal(read_1302(0x83));

 shi  = BCD_Decimal(read_1302(0x85));

 ri   = BCD_Decimal(read_1302(0x87));

 yue  = BCD_Decimal(read_1302(0x89));

 nian = BCD_Decimal(read_1302(0x8d));

 week = BCD_Decimal(read_1302(0x8b));  

 write_sfm(10,miao);

 write_sfm(7,fen);

 write_sfm(4,shi); 

 write_nyr(10,ri);

 write_nyr(7,yue);

}

最后,求求看到的此文的小伙伴点赞关注支持一下下哦。毕竟,码字不容易哦,您的支持是我最大的动力呀!!!呜呜呜~~~

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式硬件与代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值