DS1302 中文资料+代码 单片机制作时钟

DS1302 中文资料

DS1302 是 DALLAS 公司推出的涓流充电时钟芯片内含有一个实时

时钟/日历和 31 字节静态 RAM

可通过简单的串行接口与单片机进行通信

可提供:

--秒分时日日期月年的信息

--每月的天数和闰年的天数可自动调整

--可通过 AM/PM 指示决定采用 24 或 12 小时格式

--保持数据和时钟信息时功率小于 1mW


DS1302 引脚

X1 X2 32.768KHz 晶振管脚

GND 地

CE 复位脚

I/O 数据输入/输出引脚

SCLK 串行时钟

Vcc1,Vcc2 电源供电管脚

各引脚的功能为各引脚的功能为:

     Vcc2 备份电源。 Vcc2>Vcc1+0.2VVcc1 主电源;Vcc1:Vcc2:当Vcc2>Vcc1+0.2VVcc2>Vcc1+0.2V时, Vcc2由Vcc2

DS1302Vcc2< Vcc1时,由Vcc1 DS1302Vcc1 DS1302供电。向DS1302DS1302供电,当Vcc2< Vcc1Vcc1向DS1302

SCLKSCLK:串行时钟,输入,控制数据的输入与输出;

I/OI/O:三线接口时的双向数据线;

CECE:输入信号,在读、写数据期间,必须为高。该引脚有两个功能:

CE第一,CECE开始控制字访问移位寄存器的控制逻辑;其次,

CE 提供结束单字节或多字节数据传输的方法。


参考电路参考电路:

如上图所示:

          CESCLKDS1302 与单片机的连接也仅需要 3 条线:CE 引脚、SCLK 串行时钟

引脚、I/O 串行数据引脚,Vcc2 为备用电源,外接 32.768kHz 晶振,

为芯片提供计时脉冲。


实际电路:实际电路:

Vcc_5V:为电路中的主电源;Vcc2,也就是 BT1 为备份电源。当Vcc_5V 为电路中的主电源; Vcc2,也就是_5V:主电源;Vcc2

Vcc2>Vcc1+0.2V 时,

由 Vcc2 向 DS1302 供 电 , 当 Vcc2< Vcc1 时 , 由 Vcc1 向

DS1302 供电

CLK 和 I/O 虽然和 IIC 总线接在一条引脚上 , DS1302 其实并不是总线接在一条引脚上,但

使用 IIC 总线,而是一种三线式总线,


DS1302 内部结构:

DS1302 内部包括:

Power control:电源控制模块

Input shift registers:输入移位寄存器

Command and control logic:通讯与逻辑控制器

Oscillator and divider:晶体振荡器及分频器

DS1302 的内部主要组成部分虽然有:移位寄存器、控制逻辑、振荡器、实时时

钟以及 RAM。虽然数据分成两种,但是对单片机的程序而言,其实是一样的,

就是对特定的地址进行读写操作。


DS1302 控制字:

710控制字的最高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入

DS1302到DS1302DS1302中。

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

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

001位0(最低有效位):如为0,表示要进行写操作,为1表示进行读操作。

控制字总是从最低位开始输出。在控制字指令输入后的下一个 SCLK 时钟的上

        0升沿时,数据被写入DS1302DS1302,数据输入从最低位(0 位)开始。同样,在紧跟

8 位的控制字指令后的下一个 SCLK 脉冲的下降沿,读出 DS1302 的数据,读

出的数据也是从最低位到最高位。


DS1302 时序:

如图,所示

CE 输入驱动高启动所有的数据传输。

CE 输入有两个功能。首先,CE 打开控制逻辑,允许访问的移位寄存器的地址

/命令序列。其次,CE 提供了一个终止单字节或多字节数据传输方法。

一个时钟周期是由一个下降沿之后的上升沿序列。对于数据 传输而言,数据必

须在有效的时钟的上升沿输入,在时钟的下降沿输出。如果 CE 为低,所有的 I

/ O 引脚变为高阻抗状态,数据传输终止。

对于数据输入:

开始的 8 个 SCLK 周期,输入写命令字节,数据字节在后 8 个 SCLK 周期的


上升沿输入。数据输入位 0 开始。

对于数据输出:

开始的 8 个 SCLK 周期,输入一个读命令字节,数据字节在后 8 个 SCLK 周

期的下降沿输出。注意,第一个数据字节的第一个下降沿发生后,命令字的最

后一位被写入(Note that the first data bit to be transmitted occurs on

the first falling edge after the last bit of the command byte is

written. ,命令字节的最后一位被写入。当 CE 仍为高时。如果还有额外的

SCLK 周期,DS1302 将重新发送数据字节,这使 DS1302 具有连续突发读取的

能力。


DS1302 驱动程序分析

置C E为

在上升沿按位传输

地址字

读取或写入相应地

址的数据

置C E为

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

      :*名称: uchar DS1302Read()

*说明: 先写地址,后读数据:

      :*功能: cmd 相应地址中读取一个字节的数据

      :*调用: DS1302WriteByte(),DS1302ReadByte()

      : cmd:要写入的控制字节*输入: cmd:

      : dat:读取的数据*输出: dat:

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

uchar DS1302Read(uchar cmd)

{

    uchar dat;

            //RST=0;////初始 CE 线置为0

               //SCLK=0;////初始时钟线置为 0

            //RST=1;////初始 CE 置为1,传输开始

                          ///DS1302WriteByte(cmd);////传输命令字,要读取的时间/日历地址

                         ///dat=DS1302ReadByte();////读取要得到的时间/日期


           //SCLK=1;////时钟线拉高

        //CERST=0;////读取结束,CE 置为0,结束数据的传输

            ///return dat;////返回得到的时间/日期

}

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

*名称: DS1302Write:

       :*说明: 先写地址,后写数据

       :*功能: cmd 相应地址中写一个字节的数据

       :*调用: DS1302WriteByte()

       : cmd:要写入的控制字,dat:,dat:*输入: cmd:,dat:要写入的数据

       :*输出:

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

void DS1302Write(uchar cmd, uchar dat)

{

   RST=0; 初始 CE 线置为0

   SCLK=0; 初始时钟线置为 0

   RST=1; 初始 CE 置为1,传输开始

                                                 /DS1302WriteByte(cmd); /传输命令字,要写入的时间/日历地址

                                        /DS1302WriteByte(dat); 写入要修改的时间/日期

   SCLK=1; 时钟线拉高

                           CERST=0; 读取结束,CE 置为0,结束数据的传输

}

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

       :*名称: DS1302WriteByte

*说明: :

       :*功能: 写入8bit 数据

       :*调用: delayus()

       : dat:要写入的数据*输入: dat:

       :*输出:

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

void DS1302WriteByte(uchar dat)

{

   uchar i;

                //SCLK=0;////初始时钟线置为 0

   delayus(2);

                       //for(i=0;i<8;i++)////开始传输 8 个字节的数据

     {

                          //SDA=dat&0x01;////取最低位,注意 DS1302 的数据和地址都是从最低位开始传输的

          delayus(2);

                    //SDASCLK=1;////时钟线拉高,制造上升沿,SDA 的数据被传输

          delayus(2);

                    //SCLK=0;////时钟线拉低,为下一个上升沿做准备

                   //dat>>=1;////数据右移一位,准备传输下一位数据

     }


}

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

      : DS1302ReadByte()*名称: DS1302ReadByte()

      :*说明:

      :*功能: 读取8bit 的数据

*调用: delayus():

      :*输入:

      : dat:读取的数据*输出: dat:

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

uchar DS1302ReadByte()

{

   uchar i,dat;

   delayus(2);

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

    {

                  //dat>>=1;////要返回的数据左移一位

                       //if(SDA==1)////当数据线为高时,证明该位数据为 1

                      //,dat|=0x80;////要传输数据的当前值置为 1,1,若不是,则为0

         SCLK=1;//拉高时钟线

         delayus(2);

                   //SCLK=0;////制造下降沿

        delayus(2);

    }

               //return dat;////返回读取出的数据

}


寄存器和 RAM

对 DS1302 的操作就是对其内部寄存器的操作,DS1302 内部共有 12 个寄存器,

其中有:

7 个寄存器与日历、时钟相关,存放的数据位为 BCD 码形式。

此外,DS1302 还有年份寄存器、控制寄存器、充电寄存器、时钟突发寄存器

及与 RAM 相关的寄存器等。

时钟突发寄存器可一次性顺序读写除充电寄存器以外的寄存器。

如下所示:

DS1302 数据地址和传输格式

如图所示,时钟日历包含在 7 个读/写寄存器内,读/写寄存器中的数据是二—

—十进制的 BCD 码。

秒寄存器的BIT7 定义为时间暂停位, BIT1 为 1 时,当时钟振荡器停止工作,

DS1302 进入低功耗模式,电源消耗小于 100 微安,当 BIT1 为 0 时,时钟振荡

器启动,DS1302 正常工作。

小时寄存器的BIT7 定义为 12 或 24 小时工作模式选择位,当 BIT7 为高时,


为 12 小时工作模式,此时 BIT5 为 AM/PM 位,低电平标示 AM,高电平标示

PM,在 24 小时模式下,BIT5 为第二个 10 小时位标示(20~23 时)。

写保护寄存器的BIT7:WP 是写保护位,工作时,出 WP 外的其他位都置为

0,对时钟/日历寄存器或 RAM 进行写操作之前,WP 必须为 0,当 WP 为高电

平的时候,不能对任何时钟/日历寄存器或 RAM 进行写操作。

关于突发模式(burst mode 或称多字节传输模式),突发模式可以指定任

何的时钟/日历或者 RAM 寄存器为突发模式,和以前一样,第 6 位指定时钟或

RAM 而 0 位指定读或写。突发模式的实质是指一次传送多个字节的时钟信号和

RAM 数据。如下图所示

在时钟/日历寄存器中的 9 至 31 和在 RAM 寄存器的地址 31 不能存储数据。

突发模式的读取或写入从地址的位 0 开始。

如下程序所示:如下程序所示:

/*---------------------------------------------------------------------------------------------------/*---------------------------------------------------------------------------------------------------

            :函数名称: DS1302_NReadRam(unsigned char *rstr)

            :函数功能: 多字节突发模式读RAMRAM

                                             31DS1302_NRRAM 一次可进行3131个片内 RAM 单元读

            : *rstr:存放读到的 N 个数据输入参数: *rstr

输出参数:

------------------------------------------------------------------------------------------------------*/------------------------------------------------------------------------------------------------------*/

void DS1302_burst_Read(unsigned char *rstr)DS1302_burstburst_

{

      unsigned char i;

      RST=0;

      SCLK=0;

      RST=1; //CE 拉高,传输开始

                                                    0XFFDS1302_WriteByte(0XFF); // 0XFF0XFF,多字节突发方式读 RAM 具体细节见上一节


for(i=0;i<31;i++)//31//连续读取个31 字节

{

    *rstr=DS1302ReadByte(address) ;//*rstr=DS1302ReadByte address) //此处的 ADDRESS 指的是你需要进行连续读取的地址DS1302ReadByte(

    rstr++;

}

RST=0;//CE 信号拉低,传输结束RST=0;//CE

CLK=1;

}

/*---------------------------------------------------------------------------------------------------------/*---------------------------------------------------------------------------------------------------------

            :函数名称: DS1302_NReadRam(unsigned char *rstr)

            :函数功能: 多字节突发模式写RAMRAM

      DS1302_NRRAM 一次可进行31 个片内RAM 单元写

              : *wstr:要被写入的 N 个数据输入参数: *wstr

输出参数:

---------------------------------------------------------------------------------------------------------------*/---------------------------------------------------------------------------------------------------------------*/

void DS1302_burstWrite(unsigned char *wstr)DS1302_burstburstWrite(unsigned

{

unsigned char i;

unsigned char *tmpstr;

tmpstr=wstr ;

DS1302Write(0x8e,0x00);//DS1302Write(0x8e,0x00);////写保护关

RST=0;

SCLK=0;

RST=1;

DS1302_WriteByte(0XFE);// 0XFE RAM, RAM,

                               31for(i=0;i<31;i++)连续写入31 字节

{

    DS1302_WriteByte(*tmpstr) ;

    tmpstr++;

}

RST=0;

SCLK=1;

DS1302Write(0x8e,0x80); 开写保护

}


此 寄 存 器 为 DS1302 充 电 模 式 控 制 位 , 结 构 如 下 所 示

TCS 位:涓流充电选择位(BIT4 至 7)控制涓流充电器的选择。为防止偶

然的因素使其工作,只有 1010 模式才能使涓流充电器工作。所有其它的模式

将禁止涓流充电。在 DS1302 上电后。涓流充电将被禁止。

DS :该二极管选择(BIT2 和 3)选择是一个二极管还是两个二极管之间在

Vcc2 和 Vcc1 连接。如果 DS 为 01,则选择一个二极管。如果 DS 为 10,则

两个二极管被选中。如果 DS 为 00 或 11,充电器被禁止,与 TCS 无关。

RS 位(BIT0 和 1):选择是在 Vcc2 和 Vcc1 之间的连接电阻。电阻的选择

如下所示:


程序流程设计

初始化

取D S1 3 0 2

在L C D上 显 示

几个数组,用来定义要显示的汉字信息

unsigned char Chinese_1[17] = {0xc4,0xea, 0xd4,0xc2, 0xc8,0xd5, 0xca,0xb1, 0xb7,0xd6,

0xd0,0xc7, 0xc6,0xda, ' '};//年 月 日 时 分 秒 星 期

unsigned char Chinese_2[15] = {0xd2,0xbb, 0xb6,0xfe, 0xc8,0xfd, 0xcb,0xc4, 0xce,0xe5,

0xcc,0xec, ' '};//一二三四五六天

unsigned char Cursor[6] ={0x81,0x83,0x85,0x90,0x92,0x94};//定义光标移动的位置

0xc3,0xeb,

0xc1,0xf9,


主函数部分

主函数部分只需要按照流程图的需要调用各个模块即可

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

       :*名称: void main()

       :*说明:

*功能: 读取8bit 的数据:

       : delaym*调用: delayms()

       :*输入:

       : dat:读取的数据*输出: dat:

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

void main()

{

     Delayms(50);

               //EX1 = 1;////外部中断开

     EA = 1; 全局中断开

                         //Initialize_device();////初始化 CH452 LCD DS1302 等器件

               /whilewhile(1)//while 中的值只循环显示小时,分钟,秒这几个常变量,有其他需要,可以继续添加

     {

                                 /Display_Clock();//显示你需要从DS1302 中读取的值

                Delayms(500);

         }

     };

}

DS1302 的初始化部分

只需要调用一次,写入一个初始值即可

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

     :*名称: void Init_DS1302(void)

*说明: 1302 写入一个初始的值:

     :*功能: 写入日期,和时钟的值

     : DS1302Write()*调用: DS1302Write

     :*输入:

     :*输出:


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

void Init_DS1302(void)

{

     DS1302Write(0x8e,0x00);//DS1302Write(0x8e,0x00);////写保护关

     DS1302Write(DS1302_SECOND_WRITE,0x00); 初始秒值为 0

     DS1302Write(DS1302_MINUTE_WRITE,0x20);//DS1302Write(DS1302_MINUTE_WRITE,0x20);////初始分钟值为 0

     DS1302Write(DS1302_HOUR_WRITE,0x09); 初始为 24 小时模式初始时间为0

     DS1302Write(DS1302_DAY_WRITE,0x25); //2011 1 1 星期6

     DS1302Write(DS1302_MONTH_WRITE,0x12);

     DS1302Write(DS1302_YEAR_WRITE,0x10);

     DS1302Write(DS1302_WEEK_WRITE,0x06);

     DS1302Write(0x90,0x01);充电

     DS1302Write(0xc0,0xf0);初始化一次标示

     DS1302Write(0x8e,0x80);

}

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

      : Initialize_device()*名称: Initialize_device()

*说明: :

      :*功能: 初始化实验用到的器件

      : elayms()Init_1602();Dispaly_Menu();Init8259a();*调用: delayms() Init_1602();Dispaly_Menu();Init8259a();

      :*输入:

      :*输出:

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

Void Initialize_device()

{

                                   //CH452_Write(CH452_SYSON2);////初始化 CH452

     Init_1602();初始化 LCD

     Init8259a();初始化 8259a

                        //Dispaly_Menu();////显示年月日等文字

     Delayms(50);

                     Init_DS1302();////初始化 DS1302DS1302,只需要执行一次,设定好后,不需要再次执行

}

由于 DS1302 的很多数值都是十位数,所以需要把十位数分

2 次在 LCD12864 上显示

//----------------------------------------------------------------

                                             void//函数名称:void Split_display()

//函数功能:把一个十位数分二次显示至传递来的位置

                                             unsigned//入口参数:unsigned char address

//出口参数:无

//-----------------------------------------------------------------

void Split_display(unsigned char address)


{

unsigned char i;

i = DS1302Read(address);//DS1302Read(address);////读取十位

i = i/16 + '0';

Write_data(i);//显示十位Write_data(i);//

Delayms(3);

i = DS1302Read(address);//DS1302Read(address);////读取个位

i = i%16 + '0';

Write_data(i);//Write_data(i);////显示个位

Delayms(5);

}


屏幕显示部分

显示屏幕上的文字信息

显示效果为:

20XX XX XX

XX XX XX

星期 X

//----------------------------------------------------------------

                                             void//函数名称:void Dispaly_Menu()

//函数功能:显示屏幕上的所有元素

//入口参数:无

//出口参数:无

//-----------------------------------------------------------------

void Dispaly_Menu()

{

      Write_com(0x01);

      Delayms(100);

      Write_com(0x80);

      Delayms(100);

      Write_data('2');

      Delayms(5);

      Write_data('0');

      Delayms(1);

Split_display(DS1302_YEAR_READ);// 显示年份Split_display(DS1302_YEAR_READ);//

Write_data(Chinese_1[0]);//Write_data(Chinese_1[0]);////显示

Delayms(3);

Write_data(Chinese_1[1]);

Delayms(3);


Split_display(DS1302_MONTH_READ);//Split_display(DS1302_MONTH_READ);//显示月份

Write_data(Chinese_1[2]);//Write_data(Chinese_1[2]);////显示

Delayms(3);

Write_data(Chinese_1[3]);

Delayms(3);

Split_display(DS1302_DAY_READ);//Split_display(DS1302_DAY_READ);////显示日期

Write_data(Chinese_1[4]);//Write_data(Chinese_1[4]);////显示

Delayms(3);

Write_data(Chinese_1[5]);

Delayms(3);

Write_data(Chinese_1[16]);

Delayms(3);

Write_com(0x90); 换第二行

Split_display(DS1302_HOUR_READ);//Split_display(DS1302_HOUR_READ);////显示小时

Write_data(Chinese_1[6]);//Write_data(Chinese_1[6]);////显示

Delayms(3);

Write_data(Chinese_1[7]);

Delayms(3);

Split_display(DS1302_MINUTE_READ);//Split_display(DS1302_MINUTE_READ);////显示分钟

Write_data(Chinese_1[8]);//Write_data(Chinese_1[8]);////显示

Delayms(3);

Write_data(Chinese_1[9]);

Delayms(3);//

c = DS1302Read(DS1302_SECOND_READ);//DS1302Read(DS1302_SECOND_READ);////读取秒的十位

c = c&0x7f;

c = c/16 + '0';

Write_data(c);//Write_data(c);////显示秒的十位

Delayms(3);

c = DS1302Read(DS1302_SECOND_READ);//DS1302Read(DS1302_SECOND_READ);////读取秒的个位

c = c%16 + '0';

Write_data(c);

Delayms(5);//Delayms(5);////显示秒

Write_data(Chinese_1[10]);//Write_data(Chinese_1[10]);////显示

Delayms(3);

Write_data(Chinese_1[11]);

Delayms(3);

Write_data(Chinese_1[16]);


Delayms(3);

Write_com(0x88);//Write_com(0x88);////换第三行

                      ""显示"星期"

Write_data(Chinese_1[12]);

Delayms(3);

Write_data(Chinese_1[13]);

Delayms(3);

Write_data(Chinese_1[14]);

Delayms(3);

Write_data(Chinese_1[15]);

Delayms(3);

Write_data(Chinese_2[(DS1302Read(0x8b)-1)*2]);

Delayms(3);

Write_data(Chinese_2[(DS1302Read(0x8b)-1)*2+1]);

Delayms(3);

Write_data(Chinese_1[16]);

Delayms(3);

  Write_com(0x81);

Delayms(5000);

}

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

     :*名称: void Display_Clock();

     :*说明:

     :*功能: 显示屏幕上改变的数值

*调用: delayms() Write_com();: delaym s()Write_com();

     :*输入:

     : dat:读取的数据*输出: dat:

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

Void Display_Clock()

{

             Write_com(Cursor[3]); //Write_com(Cursor[3]);////小时的位置,再次紧紧列出了几个最长改变的时间变量,如果有需

要,可以另外加上其他的变量,如年,月

             Split_display(DS1302_HOUR_READ);//Split_display(DS1302_HOUR_READ);////显示小时

             Delayms(5);//

Write_com(Cursor[4]); 分钟的位置

Delayms(3);

Split_display(DS1302_MINUTE_READ);//Split_display(DS1302_MINUTE_READ);////显示分钟

Delayms(5);//


Write_com(Cursor[5]); 秒的位置

c = DS1302Read(DS1302_SECOND_READ);//DS1302Read(DS1302_SECOND_READ);////读取秒的十位

c = c&0x7f;

c = c/16 + '0';

Write_data(c);//Write_data(c);////显示秒的十位

Delayms(3);

c = DS1302Read(DS1302_SECOND_READ);//DS1302Read(DS1302_SECOND_READ);////读取秒的个位

c = c%16 + '0';

Write_data(c);//Write_data(c);////显示秒

}

思考题:

1.如何用 4*4 键盘动态改变 DS1302 中的时间/日

历?

提示:


2.如何显示日历式日期,如:

提示:

//----------------------------------------------------------------

                                             int//函数名称:int WeekDay(int year, int month, int day)

//函数功能:由日期计算今天为星期几

                                             int//入口参数:int year, int month, int day

                                             (int)sum%7//出口参数:(int)sum%7

//-----------------------------------------------------------------

int WeekDay(int year, int month, int day) 根据输入的日期,返回对应的星期

{

       int i;

       int run=0, ping=0;

       long sum;

       for(i=1; i {

       if(i%4==0 && i%100!=0 || i%400==0)

       run++;

       else

       ping++;

}

       sum = 366*run + 365*ping;

       for(i=1; i sum += MonthDays(year, i);

       sum =sum + day; 计算总天数

       return (int)sum%7;

}

  //----------------------------------------------------------------

                                              int//函数名称:int MonthDays(int year, int month)

//函数功能:根据输入的年号和月份,返回该月的天数

//int入口参数:int year, int month, int day

                                              (int)sum%7//出口参数:(int)sum%7

//-----------------------------------------------------------------

int MonthDays(int year, int month)//

{

switch(month)

{


case 1:

case 3:

case 5:

case 7:

case 8:

case 10:

case 12: return 31; 一三五七八十腊,三十一天永不差

case 4:

case 6:

case 9:

                    //30case 11: return 30;////其他月份自然是3030

case 2://计算闰月

          if(year%4==0 && year%100!=0 || year%400==0)

         return 29;

         else

         return 28;

default:

    Return 0;

}

 

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值