DS1302实时时钟

目录

一、基础介绍

1、功能

2、内部结构与外部引脚

3、DS1302时钟寄存器

4、DS1302通信时序 

5、BCD码转换

二、相关代码 

1.程序设计流程

2.实际代码


一、基础介绍

DS1302实时时钟是啥? 它是指美国DALLSA推出的一款高性能、低功耗的日历时钟芯片。

1、功能

  •  DS1302是一种串行接口的实时时钟
  • 芯片内部具有可编程的日历时钟和31个字节的静态RAM
  • 日历时钟可以自动进行闰年补偿
  • 计时准确、接口简单、使用方便、工作电压范围宽(2.5~5.5V)
  • 芯片可以对备用电池进行涓流充电,可有效延长备用电池使用寿命(主电源断电,备用电池供电)
  • 能够实现数据与该数据出现的时间同时记录

广泛应用于测量系统中,进行数据与数据出现时间的记录 

2、内部结构与外部引脚

       内部结构如下图

      

       外部引脚分布见下图

        

  VCC1 备用电源(接预留电池座)    VCC2 备用电源 (接开发板的系统电源)(当备用电源大于主电源+0.2V时,由备用电源为DS1302供电,否则由主电源为其供电)

  SCLK 串行时钟输入端,控制数据输入与输出

  I/O     双向输入线

  CE     使能端,CE为高时允许读写DS1302数据,为低时禁止读写 

  X1、X2   晶振引脚外接32.768KHZ圆形晶振,为时钟芯片提供工作时序

需要用杜邦线将j5和相应的单片机I/0口接上 

3、DS1302时钟寄存器

 时钟日历和控制寄存器如下图,其包含在7个读/写寄存器内,读/写寄存器中的数据是BCD码

特殊标志位: 

  •  秒寄存器(81h,80h)中的BIT7定义为时钟暂停标志(CH)。该位置为1时,时钟振荡器停止,DS1302处于低功耗状态;该位置为1时,时钟开始运行。
  • 小时寄存器(85h,84h)中的BIT5用于定义为12小时模式还是24小时模式。当其为1时,为12小时工作模式,此时BIT5为AM/PM位;当其为0时,为24小时工作模式,BIT5为小时数据位;
  • 控制寄存器(8Fh,8Eh)中的为写保护位(WP),其它七位均为0。在任何时钟的读写操作之前,WP位必须为0.当WP位为1时,不能对任何时钟日历寄存器或RAM进行写操作。

当然,DS1302芯片还有其它的寄存器,例如31字节静态RAM以及工作模式寄存器

31字节静态RAM地址寄存器:

小tips:如果需要存储地址,直接向RAM发送写地址码(对应的内存位置自己选择,例如我选第一个位置,则发送C0h),之后如需读地址,发送对应读地址指令即可。

工作模式寄存器:

 突发模式:一次传送多个字节或RAM数据(即突发模式写指令发出后,可以直接连续写入7个数据,与前面所述的一条一条指令发送数一个一个写入不同)

4、DS1302通信时序 

数据从最低位开始传输,且以位为单位进行传输

(1)读数据 :一开始CE为低电平,它从低到高的一个上升沿允许开始读写数据。(CE为低时禁止读写                     数据)

                   SCLK起始为低电平,从低到高时数据允许并开始发送至DS1302,发送之后要记得拉                    低,以便下次发送数据;从高到低数据允许读出。(上升沿发送,下降沿读出)

注:普通模式与突发模式均需先发送数据(命令字节)过去,再读出数据。 

(2) 写数据 :一开始CE为低电平,它从低到高的一个上升沿允许开始读写数据。(CE为低时禁止读                        写数据)

                   SCLK起始为低电平,从低到高时数据允许并开始发送至DS1302,发送之后要记得拉                     低,以便下次发送数据。

注:普通模式与突发模式均需先发送命令字节过去,再发送数据

 所以读写数据最大的不同在于读数据先发再读,发送数据先发再发。

5、BCD码转换

你知道在DS1302中有关时钟日历的寄存器数据是以BCD码存储的吗?那么我们如何转换回来呢?

(1)BCD码是什么?

我们使用的时钟日历寄存器往往是8421码型的BCD码

BCD码指用4个二进制数表示一位十进制数的0-9(共十个数),这十个数简称BCD码,即0000~1001

一个字节的BCD码(8421型)中的低四位用于表示十进制的个位,高四位用于表示十进制的十位,例如10的BCD码为=0001 0000;

(2)BCD码怎么转换为十进制数?设BCD码为x

令a=x/10; b=x%10; 十进制数为a*16+b

二、相关代码 

1.程序设计流程

写DS1302一字节数据->读一字节数据->BCD码转换->关闭写保护->设置DS1302时钟日历寄存器->

设置写保护->关闭写保护->读取DS1302时钟日历->设置写保护->用数码管显示DS1302时分秒

2.实际代码

#include <reg52.h>
#include <intrins.h>

#define  uchar unsigned char
#define  uint unsigned int

sbit TSCLK = P1^0;  //时钟线,接到P10上(杜邦线)
sbit TIO = P1^1;  //数据线,接到P11上
sbit TRST = P1^2; //使能端,接到P12上
sbit LA=P2^2;  
sbit LB=P2^3;
sbit LC=P2^4;   //数码管段选


void delay2(unsigned int z)    //延时函数,delay(1000)=1s
{
	unsigned int x,y;
	for(x=z;x>0;x--)
	   for(y=120;y>0;y--);
}

unsigned char smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
					0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};


void timefrist()
{
                EA = 1;          //打开总开关
	ET0 = 1;         //中断函数0的开关
	TR0 = 1;         //打开定时器0开关
	TMOD = 0x01;      //模式一,定时模式
	TH0 = 0xED;       //这里改值了,到上限就5ms(改初值)
	TL0 = 0xFF;
//开关、模式、赋初值
}


unsigned char sec=0,min=0,hour=0;
void DigDisplay(unsigned char sec,unsigned char min,unsigned char hour)
{
	unsigned char a=hour%10;
	unsigned char b=hour/10;
	static unsigned char wei=0;
	switch(wei)
	{
		case 0: LA=1;LB=1;LC=1;P0 = smgduan[b];break;
		case 1: LA=0;LB=1;LC=1;P0 = smgduan[a];break;
	}
	wei++;
	if(wei==2)
	{
	         wei = 0;
	}
                a=min%10;
                b=min/10;
                wei=0;
                switch(wei)
	{
		case 0: LA=1;LB=0;LC=1;P0 = smgduan[b];break;
		case 1: LA=1;LB=0;LC=0;P0 = smgduan[a];break;
	}
	wei++;
	if(wei==2)
	{
	         wei = 0;
	}
                a=sec%10;
                b=sec/10;
                wei=0;
                switch(wei)
	{
		case 0: LA=1;LB=1;LC=0;P0 = smgduan[b];break;
		case 1: LA=0;LB=0;LC=1;P0 = smgduan[a];break;
	}
	wei++;
	if(wei==2)
	{
	         wei = 0;
	}
}

void Write_DS1302_DAT(uchar cmd,uchar dat)
{
        uchar i;
        TRST = 0;  //拉低使能端
        TSCLK = 0;  //拉高数据总线
        TRST = 1; //拉高使能端,产生上升沿
        for(i=0;i<8;i++)  //每次写一位,写8次
        {
              TSCLK =0;                  
              TIO = cmd & 0x01;  
              TSCLK = 1;  //上升沿发送数据,DS1302将其读走 
              cmd >>=1;  //右移一位 (不懂可见红外通信文章)
        }
        for(i=0;i<8;i++)
        {
              TSCLK =0;
              TIO = dat & 0x01;
              TSCLK = 1;  //上升沿发送数据
              dat >>=1;  //右移一位(不懂可见红外通信文章)

        }
}

//读DS1302数据
uchar Read_DS1302_DAT(uchar cmd)
{
        uchar i,dat;
        TRST = 0;
        TSCLK = 0;
        TRST = 1; //使能端产生上升沿,允许读写数据
        for(i=0;i<8;i++)
        {
              TSCLK = 0;
              TIO = cmd & 0x01;
              TSCLK = 1;  //产生上升沿(DS1302读走数据)
              cmd >>=1;  //右移一位
        }
        //从上面循环出来之后TSCLK就变为了1
        for(i=0;i<8;i++)  //每次读一位,读8次
        {
              TSCLK =0;   //拉低时钟线,产生下降沿,开始读数据(DS1302将数据放在TIO上)    1000 0000
              dat >>=1;  //右移一位                  
              if(TIO) dat |= 0x80;  //读取数据,从最低位开始读                                 0000 0000                                
              TSCLK = 1;  //拉高时钟总线,方便下次产生下降沿
        }
        return dat;  //返回读出数据
}

//数据转BCD 码
uchar Dat_Chg_BCD(uchar dat)
{
        uchar dat1,dat2;
        dat1 = dat/10;
        dat2 = dat%10;
        dat2 = dat2 + dat1*16;
        return dat2;
}

//BCD码转换为数据
uchar BCD_Chg_Dat(uchar dat)
{
        uchar dat1,dat2;
        dat1 = dat / 16;
        dat2 = dat%16;
        dat2 = dat2 + dat1*10;
        return dat2;
}

void main()
{
        uchar i;
        uchar Sec,Min,Hour
        Write_DS1302_DAT(0x8e,0);  //控制寄存器,关闭写保护(才能成功写入)
        Write_DS1302_DAT(0x80,Dat_Chg_BCD(30))  //数据转换为BCD码,存放在时钟日历寄存器(秒)
        Write_DS1302_DAT(0x82,Dat_Chg_BCD(15))  //数据转换为BCD码,存放在时钟日历寄存器(分)
        Write_DS1302_DAT(0x82,Dat_Chg_BCD(19))  //数据转换为BCD码,存放在时钟日历寄存器(时)
        Write_DS1302_DAT(0x8e,0x80);  //控制寄存器,打开写保护(防止设置好的数据被修改)
        while(1)
        {
                Write_DS1302_DAT(0x8e,0);  //清除写保护
                Sec = BCD_Chg_Dat(Read_DS1302_DAT(0x81)); //读秒寄存器(并进行BCD码转换)
                Min = BCD_Chg_Dat(Read_DS1302_DAT(0x83));   //读分寄存器
                Hour = BCD_Chg_Dat(Read_DS1302_DAT(0x85));  //读时寄存器
                Write_DS1302_DAT(0x8e,0x80);  //打开写保护
                delay(1000);
                for(i=0;i<50;i++)  //循环显示程序
                {
                       sec = Sec;
                       min = Min;
                       hour = Hour;
                }
        }
}

//定时器中断函数
void timer0() interrupt 1
{
	 TH0 = 0xED;         //重新定义5ms初始值
	 TL0 = 0xFF;
	 DigDisplay(sec,min,hour);   //不断5ms显示为动态显示
}

  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值