DS1302芯片说明 DS1302实时时钟的使用

电子说

1.2w人已加入

描述

1、DS1302芯片说明

DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时,且具有闰年补偿等多种功能。

寄存器

P17:SCLK为时钟输入端。P23:I/O为串行数据输入输出端(双向)

P13:RST是复位

2、日历时钟寄存器

(1)有关的时间寄存器:

寄存器

(2)寄存器说明

第一行:秒->因为秒的范围是0-59,所以6,5,4位表示秒的十位,3,2,1,0表示个位,十位最大是5,所以三位即可。

第二行:跟上面一样;

第三行:7位:1为12小时制,0为24小时制;5位:12小时制时为0表示上午,1表示下午,24小时制时,和4位一起表示小时的十位;

其余的时间一样的表示。

倒数第二行:只看7位:为WP=1时禁止写数据,所以开始写数据时必须置0;

3、官方提供库文件

寄存器

#include "ds1302.h"
/********************************************************************/ 
/*单字节写入一字节数据*/
void Write_Ds1302_Byte(unsigned char dat) 
{
    unsigned char i;
    SCK = 0;
    for (i=0;i< 8;i++) 
    { 
        if (dat & 0x01)     // 等价于if((addr & 0x01) ==1) 
        {
            SDA_SET;        //#define SDA_SET SDA=1 /*电平置高*/
        }
        else 
        {
            SDA_CLR;        //#define SDA_CLR SDA=0 /*电平置低*/
        }        
        SCK_SET;
        SCK_CLR;        
        dat = dat > > 1; 
    } 
}
/********************************************************************/ 
/*单字节读出一字节数据*/
unsigned char Read_Ds1302_Byte(void) 
{
    unsigned char i, dat=0; 
    for (i=0;i< 8;i++)
    {   
        dat = dat > > 1;
        if (SDA_R)    //等价于if(SDA_R==1)    #define SDA_R SDA /*电平读取*/   
        {
            dat |= 0x80;
        }
        else 
        {
            dat &= 0x7F;
        }
        SCK_SET;
        SCK_CLR;
    }
    return dat;
}

/********************************************************************/ 
/*向DS1302 单字节写入一字节数据*/
void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat)
{ 

    RST_CLR;            /*RST脚置低,实现DS1302的初始化*/
    SCK_CLR;            /*SCK脚置低,实现DS1302的初始化*/

    RST_SET;            /*启动DS1302总线,RST=1电平置高 */
    addr = addr & 0xFE;  
    Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是写操作,写之前将最低位置零*/   
    Write_Ds1302_Byte(dat);  /*写入数据:dat*/
    RST_CLR;                 /*停止DS1302总线*/
}

/********************************************************************/ 
/*从DS1302单字节读出一字节数据*/
unsigned char Ds1302_Single_Byte_Read(unsigned char addr) 
{ 
    unsigned char temp;
    RST_CLR;            /*RST脚置低,实现DS1302的初始化*/
    SCK_CLR;            /*SCK脚置低,实现DS1302的初始化*/

    RST_SET;    /*启动DS1302总线,RST=1电平置高 */   
    addr = addr | 0x01;  
    Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是读操作,写之前将最低位置高*/
    temp=Read_Ds1302_Byte(); /*从DS1302中读出一个字节的数据*/      
    RST_CLR;    /*停止DS1302总线*/
    return temp;
}

4、实时时钟“实例一”

可以自己结合官方提供的库文件,进行实时时钟显示操作。这是把官方库文件和自己所写的代码结合一起,形成一个.c文件。

例:要求显示初始值为:18—50—50,依次显示时间。

#include< stc15f2k60s2.h >

#define uchar unsigned char
#define uint unsigned int

sbit SCK=P1^7;
sbit SDA=P2^3;
sbit RST=P1^3;

uchar code tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF};
uint f1,f2,f3,f4,f5,f6,f7,f8;
uint ReadValue1,ReadValue2,ReadValue3,hour,minute,sec;
void Write_Ds1302_Byte(unsigned char dat);
unsigned char Read_Ds1302_Byte(void);
void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat);
unsigned char Ds1302_Single_Byte_Read(unsigned char addr);
void allinit();
void display12(uchar f1,uchar f2);
void display34(uchar f3,uchar f4);
void display56(uchar f5,uchar f6);
void display78(uchar f7,uchar f8);
void delay();

void main(){
allinit();
f1=11;f2=11;f3=11;f4=11;f5=11;f6=11;f7=11;f8=11;

Ds1302_Single_Byte_Write(0x8e,0x00);
Ds1302_Single_Byte_Write(0x84,((18/10)< < 4|(18%10)));
Ds1302_Single_Byte_Write(0x82,((50/10)< < 4|(50%10)));
Ds1302_Single_Byte_Write(0x80,((50/10)< < 4|(50%10)));
Ds1302_Single_Byte_Write(0x8e,0x80); 

while(1){

ReadValue1=Ds1302_Single_Byte_Read(0x85);
hour=((ReadValue1&0x70) > >4)*10+(ReadValue1&0x0f);
Ds1302_Single_Byte_Write(0x80, 0x00);

ReadValue2=Ds1302_Single_Byte_Read(0x83);
minute=((ReadValue2&0x70) > >4)*10+(ReadValue2&0x0f);
Ds1302_Single_Byte_Write(0x80, 0x00);

ReadValue3=Ds1302_Single_Byte_Read(0x81);
sec=((ReadValue3&0x70) > >4)*10+(ReadValue3&0x0f);
Ds1302_Single_Byte_Write(0x80, 0x00);

f1=hour/10;f2=hour%10;f3=10;
f4=minute/10;f5=minute%10;f6=10;
f7=sec/10;f8=sec%10;

display12(f1,f2);
display34(f3,f4);
display56(f5,f6);
display78(f7,f8);
}
}

void allinit(){
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF;
P2=0XC0;P0=0XFF;P2=0XFF;P0=0XFF;
}

/*单字节写入一字节数据*/
void Write_Ds1302_Byte(unsigned char dat) 
{
    unsigned char i;
    SCK = 0;
    for (i=0;i< 8;i++) 
    { 
        if (dat & 0x01)     // 等价于if((addr & 0x01) ==1) 
        {
            SDA=1;      //#define SDA_SET SDA=1 /*电平置高*/
        }
        else 
        {
            SDA=0;      //#define SDA_CLR SDA=0 /*电平置低*/
        }        
        SCK=1;
        SCK=0;      
        dat = dat > > 1; 
    } 
}
/********************************************************************/ 
/*单字节读出一字节数据*/
unsigned char Read_Ds1302_Byte(void) 
{
    unsigned char i, dat=0; 
    for (i=0;i< 8;i++)
    {   
        dat = dat > > 1;
        if (SDA)      //等价于if(SDA_R==1)    #define SDA_R SDA /*电平读取*/   
        {
            dat |= 0x80;
        }
        else 
        {
            dat &= 0x7F;
        }
        SCK=1;
        SCK=0;
    }
    return dat;
}

/********************************************************************/ 
/*向DS1302 单字节写入一字节数据*/
void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat)
{ 

    RST=0;          /*RST脚置低,实现DS1302的初始化*/
    SCK=0;          /*SCK脚置低,实现DS1302的初始化*/

    RST=1;          /*启动DS1302总线,RST=1电平置高 */
    addr = addr & 0xFE;  
    Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是写操作,写之前将最低位置零*/   
    Write_Ds1302_Byte(dat);  /*写入数据:dat*/
    RST=0;               /*停止DS1302总线*/
}

/********************************************************************/ 
/*从DS1302单字节读出一字节数据*/
unsigned char Ds1302_Single_Byte_Read(unsigned char addr) 
{ 
    unsigned char temp;
    RST=0;          /*RST脚置低,实现DS1302的初始化*/
    SCK=0;          /*SCK脚置低,实现DS1302的初始化*/

    RST=1;  /*启动DS1302总线,RST=1电平置高 */   
    addr = addr | 0x01;  
    Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是读操作,写之前将最低位置高*/
    temp=Read_Ds1302_Byte(); /*从DS1302中读出一个字节的数据*/      
    RST=0;  /*停止DS1302总线*/
    return temp;
}

void display12(uchar f1,uchar f2){
P2=0XC0;P0=0X01;P2=0XFF;P0=tab[f1];
delay();
P2=0XC0;P0=0X02;P2=0XFF;P0=tab[f2];
delay();
}

void display34(uchar f3,uchar f4){
P2=0XC0;P0=0X04;P2=0XFF;P0=tab[f3];
delay();
P2=0XC0;P0=0X08;P2=0XFF;P0=tab[f4];
delay();
}

void display56(uchar f5,uchar f6){
P2=0XC0;P0=0X10;P2=0XFF;P0=tab[f5];
delay();
P2=0XC0;P0=0X20;P2=0XFF;P0=tab[f6];
delay();
}

void display78(uchar f7,uchar f8){
P2=0XC0;P0=0X40;P2=0XFF;P0=tab[f7];
delay();
P2=0XC0;P0=0X80;P2=0XFF;P0=tab[f8];
delay();
}

void delay(){
int i,j;
for(i=2;i >0;i--)
for(j=600;j >0;j--);
}

结果与体会:

由于官方已经给出驱动文件,把驱动文件加以修改,在结合自己的显示代码,最终可以实现实时时钟。实时时钟部分只需要知道,如何读时间、如何写入初始值、转换公式是什么。

写入初始值操作:

Ds1302_Single_Byte_Write(0x8e,0x00);
Ds1302_Single_Byte_Write(0x84,((18/10)< < 4|(18%10)));//时
Ds1302_Single_Byte_Write(0x82,((50/10)< < 4|(50%10)));//分
Ds1302_Single_Byte_Write(0x80,((50/10)< < 4|(50%10)));//秒
Ds1302_Single_Byte_Write(0x8e,0x80);

记着转换公式为:((value/10)<<4|(value%10))

读出数据操作:

ReadValue1=Ds1302_Single_Byte_Read(0x85);
hour=((ReadValue1&0x70) > >4)*10+(ReadValue1&0x0f);
Ds1302_Single_Byte_Write(0x80, 0x00);

ReadValue2=Ds1302_Single_Byte_Read(0x83);
minute=((ReadValue2&0x70) > >4)*10+(ReadValue2&0x0f);
Ds1302_Single_Byte_Write(0x80, 0x00);

ReadValue3=Ds1302_Single_Byte_Read(0x81);
sec=((ReadValue3&0x70) > >4)*10+(ReadValue3&0x0f);
Ds1302_Single_Byte_Write(0x80, 0x00);

记着转换公式为:((ReadValue&0x70)>>4)*10+(ReadValue&0x0f)

另外写入、读出年、星期、月、日也是如此,只要修改写入、读出初始值就OK了。

5、实时时钟“实例二”

实例一是把所有定义的函数都放到一起了,接下来的实例二,是分模块化实现功能。两种方法都可以实现实时时钟,不过分模块化更有利于修改代码,所以对于以后多个功能的实现,分块处理,代码修改比较方便。

下面给出各个模块代码:

ds1302.c

#include "ds1302.h"
unsigned char time[]={58,58,17,0,0,0,0};
/********************************************************************/ 
/*单字节写入一字节数据*/
void Write_Ds1302_Byte(unsigned char dat) 
{
    unsigned char i;
    SCK = 0;
    for (i=0;i< 8;i++) 
    { 
        if (dat & 0x01)     // 等价于if((addr & 0x01) ==1) 
        {
            SDA_SET;        //#define SDA_SET SDA=1 /*电平置高*/
        }
        else 
        {
            SDA_CLR;        //#define SDA_CLR SDA=0 /*电平置低*/
        }        
        SCK_SET;
        SCK_CLR;        
        dat = dat > > 1; 
    } 
}
/********************************************************************/ 
/*单字节读出一字节数据*/
unsigned char Read_Ds1302_Byte(void) 
{
    unsigned char i, dat=0; 
    for (i=0;i< 8;i++)
    {   
        dat = dat > > 1;
        if (SDA_R)    //等价于if(SDA_R==1)    #define SDA_R SDA /*电平读取*/   
        {
            dat |= 0x80;
        }
        else 
        {
            dat &= 0x7F;
        }
        SCK_SET;
        SCK_CLR;
    }
    return dat;
}

/********************************************************************/ 
/*向DS1302 单字节写入一字节数据*/
void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat)
{ 

    RST_CLR;            /*RST脚置低,实现DS1302的初始化*/
    SCK_CLR;            /*SCK脚置低,实现DS1302的初始化*/

    RST_SET;            /*启动DS1302总线,RST=1电平置高 */
    addr = addr & 0xFE;  
    Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是写操作,写之前将最低位置零*/   
    Write_Ds1302_Byte((dat/10< < 4)|(dat%10));     /*写入数据:dat*/
    RST_CLR;                 /*停止DS1302总线*/
}

/********************************************************************/ 
/*从DS1302单字节读出一字节数据*/
unsigned char Ds1302_Single_Byte_Read(unsigned char addr) 
{ 
    unsigned char temp;
    unsigned char dat1,dat2;
    RST_CLR;            /*RST脚置低,实现DS1302的初始化*/
    SCK_CLR;            /*SCK脚置低,实现DS1302的初始化*/

    RST_SET;    /*启动DS1302总线,RST=1电平置高 */   
    addr = addr | 0x01;  
    Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是读操作,写之前将最低位置高*/
    temp=Read_Ds1302_Byte(); /*从DS1302中读出一个字节的数据*/

    dat1=temp/16;
    dat2=temp%16;
    temp=10*dat1+dat2;      
    //RST_CLR;  /*停止DS1302总线*/
    SD=0;
    return temp;
}

void Ds1302_init(){
unsigned char i,add;
add=0x80;
Ds1302_Single_Byte_Write(0x8e,0x00);
for(i=0;i< 7;i++){
Ds1302_Single_Byte_Write(add,time[i]);
add+=2;
}
Ds1302_Single_Byte_Write(0x8e,0x80);
}

void Ds1302_Gettime(){
unsigned char i,add;
add=0x81;
Ds1302_Single_Byte_Write(0x8e,0x00);
for(i=0;i< 7;i++){
time[i]=Ds1302_Single_Byte_Read(add);
add+=2;
}
Ds1302_Single_Byte_Write(0x8e,0x80);
}

ds1302.h

#ifndef  __DS1302_H__
#define  __DS1302_H__

#include< stc15f2k60s2.h >
#include< intrins.h >
/********************************************************************/ 
sbit SCK=P1^7;        
sbit SD=P2^3;        
sbit RST=P1^3;
/********************************************************************/ 
/*复位脚*/
#define RST_CLR    RST=0   /*电平置低*/
#define RST_SET    RST=1   /*电平置高*/
/*双向数据*/
#define SDA_CLR    SD=0    /*电平置低*/
#define SDA_SET    SD=1    /*电平置高*/
#define SDA_R    SD  /*电平读取*/    
/*时钟信号*/
#define SCK_CLR    SCK=0   /*时钟信号*/
#define SCK_SET    SCK=1   /*电平置高*/
/********************************************************************/ 
#define ds1302_sec_addr            0x80        //秒数据地址
#define ds1302_min_addr            0x82        //分数据地址
#define ds1302_hr_addr            0x84        //时数据地址
#define ds1302_date_addr        0x86        //日数据地址
#define ds1302_month_addr        0x88        //月数据地址
#define ds1302_day_addr            0x8A        //星期数据地址
#define ds1302_year_addr        0x8C        //年数据地址

#define ds1302_control_addr        0x8Ee       //写保护命令字单元地址
#define ds1302_charger_addr        0x90        //涓电流充电命令字地址             
#define ds1302_clkburst_addr    0xBE        //日历、时钟突发模式命令字地址

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

/********************************************************************/ 
/*单字节写入一字节数据*/
extern void Write_Ds1302_Byte(unsigned char dat);
/********************************************************************/ 
/*单字节读出一字节数据*/
extern unsigned char Read_Ds1302_Byte(void);

/********************************************************************/ 
/********************************************************************/ 
/*向DS1302单字节写入一字节数据*/
extern void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat);
/********************************************************************/ 
/*从DS1302单字节读出一字节数据*/
extern unsigned char Ds1302_Single_Byte_Read(unsigned char addr);

extern unsigned char time[];
extern void Ds1302_init();
extern void Ds1302_Gettime();

#endif     
/********************************************************************/
//                END FILE
/********************************************************************/

Text.c

#include< stc15f2k60s2.h >
#include"ds1302.h"
#define uchar unsigned char

uchar code tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF};
unsigned char f1,f2,f3,f4,f5,f6,f7,f8;

void delay();
void allinit();
void display12(uchar f1,uchar f2);
void display34(uchar f3,uchar f4);
void display56(uchar f5,uchar f6);
void display78(uchar f7,uchar f8);

void main()
{
allinit();
Ds1302_init();
while(1)
{
Ds1302_Gettime();

f1=time[2]/10;f2=time[2]%10;f3=10;
f4=time[1]/10;f5=time[1]%10;f6=10;
f7=time[0]/10;f8=time[0]%10;

display12(f1,f2);
display34(f3,f4);
display56(f5,f6);
display78(f7,f8);
}
}

void delay(){
unsigned int i,j;
for(i=0;i< 2;i++)
for(j=0;j< 200;j++);
}

void allinit(){
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF;
P2=0XC0;P0=0XFF;P2=0XFF;P0=0XFF;
}

void display12(uchar f1,uchar f2){
P2=0XC0;P0=0X01;P2=0XFF;P0=tab[f1];
delay();
P2=0XC0;P0=0X02;P2=0XFF;P0=tab[f2];
delay();
}

void display34(uchar f3,uchar f4){
P2=0XC0;P0=0X04;P2=0XFF;P0=tab[f3];
delay();
P2=0XC0;P0=0X08;P2=0XFF;P0=tab[f4];
delay();
}

void display56(uchar f5,uchar f6){
P2=0XC0;P0=0X10;P2=0XFF;P0=tab[f5];
delay();
P2=0XC0;P0=0X20;P2=0XFF;P0=tab[f6];
delay();
}

void display78(uchar f7,uchar f8){
P2=0XC0;P0=0X40;P2=0XFF;P0=tab[f7];
delay();
P2=0XC0;P0=0X80;P2=0XFF;P0=tab[f8];
delay();
}

结果与体会:

ds1302.c

此代码和官方给出的驱动有所修改,增加了DS1302初始化函数和获取时间的函数,还有在向DS1302单字节写入一字节数据,修改:

Write_Ds1302_Byte((dat/10<  < 4)|(dat%10));

/ 从DS1302单字节读出一字节数据 /函数修改为:

dat1=temp/16;
dat2=temp%16;
temp=10*dat1+dat2;        
//RST_CLR;    /*停止DS1302总线*/
SD=0;
return temp;

只要注意转换公式就可以了。

ds1302.h

要增加新定义的函数说明。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分