DS1302时钟

DS1302时钟芯片介绍

简介

DS1302 是 DALLAS 公司推出的涓流充电时钟芯片, 内含有一个实时时钟/日历和 31 字节静态 RAM, 通过简单的串行接口与单片机进行通信。

DS1302 与单片机之间能简单地采用同步串行的方式进行通信, 仅需用到三根通信线: ①RES
复位②I/O 数据线③SCLK 串行时钟。时钟/RAM 的读/写数据以一个字节或多达31 个字节的字符组方式通信。 DS1302 工作时功耗很低保持数据和时钟信息时功率小于 1mW。

  1.  VCC2: 主电源引脚
  2.  X1、 X2: DS1302 外部晶振引脚, 通常需外接 32.768K 晶振
  3.  GND: 电源地
  4.  CE: 使能引脚, 也是复位引脚(新版本功能变) 。
  5.  I/O: 串行数据引脚, 数据输出或者输入都从这个引脚
  6.  SCLK: 串行时钟引脚
  7.  VCC1: 备用电源

DS1302使用

操作 DS1302 的大致过程, 就是将各种数据写入 DS1302 的寄存器, 以设置它当前的时间的格式。 然后使 DS1302 开始运作, DS1302 时钟会按照设置情况运转, 再用单片机将其寄存器内的数据读出。 再用液晶显示, 就是我们常说的简易电子钟。 所以总的来说 DS1302 的操作分 2 步(显示部分属于液晶显示的内容,不属于 DS1302 本身的内容) , 但是在讲述操作时序之前, 我们要先看看寄存器,DS1302 有一个控制寄存器、 12 个日历、 时钟寄存器和 31 个 RAM。

(1)控制寄存器

  1.  第 7 位永远都是 1;
  2.  第 6 位, 1 表示 RAM, 寻址内部存储器地址; 0 表示 CK, 寻址内部寄存器;
  3.  第 5 到第 1 位, 为 RAM 或者寄存器的地址;
  4.  最低位, 高电平表示 RD, 即下一步操作将要“读” ; 低电平表示 W, 即下一步操作将要“写” 。 (与 AT24C02 寄存器类似, 这点要理解好) 。

 (3)日历/时钟寄存器

DS1302 共有 12 个寄存器, 其中有 7 个与日历、 时钟相关, 存放的数据为 BCD码形式

 下面对几个寄存器做下说明:
秒寄存器: 低四位为秒的个位, 高的次三位为秒的十位。 最高位 CH 为DS1302 的运行标志, 当 CH=0 时, DS1302 内部时钟运行, 反之 CH=1 时停止;
小时寄存器: 时寄存器。 最高位为 12/24 小时的格式选择位, 该位为 1 时表示 12 小时格式。 当设置为 12 小时显示格式时, 第 5 位的高电平表示下午(PM) ; 而当设置为 24 小时格式时, 第 5 位位具体的时间数据。
写保护寄存器: 当该寄存器最高位 WP 为 1 时, DS1302 只读不写, 所以要在往 DS1302 写数据之前确保 WP 为 0。
慢充电寄存器(涓细电流充电) 寄存器: 我们知道, 当 DS1302 掉电时, 可以马上调用外部电源保护时间数据。 该寄存器就是配置备用电源的充电选项的。其中高四位(4 个 TCS) 只有在 1010 的情况下才能使用充电选项; 低四位的情况与 DS1302 内部电路有关。

BCD 码是通过 4 位二进制码来表示 1 位十进制中的 0~9 这 10 个数码。
 

从 DS1302 中读取出来的时钟数据均为 BCD 码格式, 需转换为我们习惯的 10 进制。

(3)DS1302的读写时序

在控制指令字输入后的下一个 SCLK 时钟的上升沿时, 数据被写入 DS1302,数据输入从低位(位 0) 开始。 同样, 在紧跟 8 位的控制指令字后的下一个 SCLK脉冲的下降沿读出 DS1302 的数据, 读出数据时从低位 0 位到高位 7。

 上图就是 DS1302 的三个时序: 复位时序, 单字节写时序, 单字节读时序;

CE(RST) : 复位时序, 即在 RST 引脚产生一个正脉冲, 在整个读写器件,RST 要保持高电平, 一次字节读写完毕之后, 要注意把 RST 返回低电平准备下次读写周期;
单字节读时序: 注意读之前还是要先对寄存器写命令, 从最低位开始写; 可以看到, 写数据是在 SCLK 的上升沿实现, 而读数据在 SCLK 的下降沿实现。 所以,在单字节读时序中, 写命令的第八个上升沿结束后紧接着的第八个下降沿就将要读寄存器的第一位数据读到数据线上了! 这个就是 DS1302 操作中最特别的地方。当然读出来的数据也是最低位开始。
单字节写时序: 两个字节的数据配合 16 个上升沿将数据写入即可。
程序注意事项:

  • 要记得在操作 DS1302 之前关闭写保护;
  • 注意用延时来降低单片机的速度以配合器件时序;
  • DS1302 读出来的数据是 BCD 码形式, 要转换成我们习惯的 10 进制, 转换方法在源程序里;
  • 读取字节之前, 将 IO 设置为输入口, 读取完之后, 要将其改回输出口;
  • 在写程序的时候, 建议实现开辟数组(内存空间) 来集中放置 DS1302 的一系列数据, 方便以后扩展键盘输入。

硬件

 从上图中可知, DS1302 芯片的控制管脚接至单片机 P3.4-P3.6 上, 在芯片的X1、 X2 管脚处外接了一个 32.768KHZ 晶振, 为时钟运行提供一个稳定的时钟频率, C2 和 C3 为旁路电容, 目的是消除晶振起振时产生的电感干扰。

软件

//public.h
#ifndef _public_H
#define _public_H

#include "reg52.h"

typedef unsigned int u16;	//对系统默认数据类型进行重定义
typedef unsigned char u8;


void delay_10us(u16 ten_us);
void delay_ms(u16 ms);

#endif
//public.c
#include "public.h"

/*******************************************************************************
* 函 数 名       : delay_10us
* 函数功能		 : 延时函数,ten_us=1时,大约延时10us
* 输    入       : ten_us
* 输    出    	 : 无
*******************************************************************************/
void delay_10us(u16 ten_us)
{
	while(ten_us--);	
}

/*******************************************************************************
* 函 数 名       : delay_ms
* 函数功能		 : ms延时函数,ms=1时,大约延时1ms
* 输    入       : ms:ms延时时间
* 输    出    	 : 无
*******************************************************************************/
void delay_ms(u16 ms)
{
	u16 i,j;
	for(i=ms;i>0;i--)
		for(j=110;j>0;j--);
}
//ds1302.h
#ifndef _ds1302_H
#define _ds1302_H

#include "public.h"

//管脚定义
sbit DS1302_RST=P3^5;//复位管脚
sbit DS1302_CLK=P3^6;//时钟管脚
sbit DS1302_IO=P3^4;//数据管脚

//变量声明
extern u8 gDS1302_TIME[7];//存储时间

//函数声明
void ds1302_init(void);
void ds1302_read_time(void);


#endif
//ds1302.c
#include "ds1302.h"
#include "intrins.h"

//---DS1302写入和读取时分秒的地址命令---//
//---秒分时日月周年 最低位读写位;-------//
u8 gREAD_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d}; 
u8 gWRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};

//---DS1302时钟初始化2021年5月20日星期四13点51分47秒。---//
//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
u8 gDS1302_TIME[7] = {0x47, 0x51, 0x13, 0x20, 0x04, 0x05, 0x21};


/*******************************************************************************
* 函 数 名       : ds1302_write_byte
* 函数功能		 : DS1302写单字节
* 输    入       : addr:地址/命令
				   dat:数据
* 输    出    	 : 无
*******************************************************************************/
void ds1302_write_byte(u8 addr,u8 dat)
{
	u8 i=0;
	
	DS1302_RST=0;
	_nop_();	
	DS1302_CLK=0;//CLK低电平
	_nop_();
	DS1302_RST=1;//RST由低到高变化
	_nop_();

	for(i=0;i<8;i++)//循环8次,每次写1位,先写低位再写高位
	{
		DS1302_IO=addr&0x01;
		addr>>=1;
		DS1302_CLK=1;
		_nop_();
		DS1302_CLK=0;//CLK由低到高产生一个上升沿,从而写入数据
		_nop_();		
	}
	for(i=0;i<8;i++)//循环8次,每次写1位,先写低位再写高位
	{
		DS1302_IO=dat&0x01;
		dat>>=1;
		DS1302_CLK=1;
		_nop_();
		DS1302_CLK=0;
		_nop_();		
	}
	DS1302_RST=0;//RST拉低
	_nop_();	
}

/*******************************************************************************
* 函 数 名       : ds1302_read_byte
* 函数功能		 : DS1302读单字节
* 输    入       : addr:地址/命令
* 输    出    	 : 读取的数据
*******************************************************************************/
u8 ds1302_read_byte(u8 addr)
{
	u8 i=0;
	u8 temp=0;
	u8 value=0;

	DS1302_RST=0;
	_nop_();	
	DS1302_CLK=0;//CLK低电平
	_nop_();
	DS1302_RST=1;//RST由低到高变化
	_nop_();
	
	for(i=0;i<8;i++)//循环8次,每次写1位,先写低位再写高位
	{
		DS1302_IO=addr&0x01;
		addr>>=1;	
		DS1302_CLK=1;
		_nop_();
		DS1302_CLK=0;//CLK由低到高产生一个上升沿,从而写入数据
		_nop_();		
	}
	for(i=0;i<8;i++)//循环8次,每次读1位,先读低位再读高位
	{
		temp=DS1302_IO;
		value=(temp<<7)|(value>>1);//先将value右移1位,然后temp左移7位,最后或运算
		DS1302_CLK=1;
		_nop_();
		DS1302_CLK=0;
		_nop_();		
	}
	DS1302_RST=0;//RST拉低
	_nop_();	
	DS1302_CLK=1;//对于实物中,P3.4口没有外接上拉电阻的,此处代码需要添加,使数据口有一个上升沿脉冲。
	_nop_();
	DS1302_IO = 0;
	_nop_();
	DS1302_IO = 1;
	_nop_();	
	return value;		
}

/*******************************************************************************
* 函 数 名       : ds1302_init
* 函数功能		 : DS1302初始化时间
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void ds1302_init(void)
{
	u8 i=0;
	ds1302_write_byte(0x8E,0X00);
	for(i=0;i<7;i++)
	{
		ds1302_write_byte(gWRITE_RTC_ADDR[i],gDS1302_TIME[i]);	
	}
	ds1302_write_byte(0x8E,0X80);	
}

/*******************************************************************************
* 函 数 名       : ds1302_read_time
* 函数功能		 : DS1302读取时间
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void ds1302_read_time(void)
{
	u8 i=0;
	for(i=0;i<7;i++)
	{
		gDS1302_TIME[i]=ds1302_read_byte(gREAD_RTC_ADDR[i]);	
	}	
}
//smg.h
#ifndef _smg_H
#define _smg_H

#include "public.h"


#define SMG_A_DP_PORT	P0	//使用宏定义数码管段码口

//定义数码管位选信号控制脚
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;

extern u8 gsmg_code[17];

void smg_display(u8 dat[],u8 pos);

#endif
//smg.c
#include "smg.h"

//共阴极数码管显示0~F的段码数据
u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
				0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

/*******************************************************************************
* 函 数 名       : smg_display
* 函数功能		 : 动态数码管显示
* 输    入       : dat:要显示的数据
				   pos:从左开始第几个位置开始显示,范围1-8
* 输    出    	 : 无
*******************************************************************************/
void smg_display(u8 dat[],u8 pos)
{
	u8 i=0;
	u8 pos_temp=pos-1;

	for(i=pos_temp;i<8;i++)
	{
	   	switch(i)//位选
		{
			case 0: LSC=1;LSB=1;LSA=1;break;
			case 1: LSC=1;LSB=1;LSA=0;break;
			case 2: LSC=1;LSB=0;LSA=1;break;
			case 3: LSC=1;LSB=0;LSA=0;break;
			case 4: LSC=0;LSB=1;LSA=1;break;
			case 5: LSC=0;LSB=1;LSA=0;break;
			case 6: LSC=0;LSB=0;LSA=1;break;
			case 7: LSC=0;LSB=0;LSA=0;break;
		}
		SMG_A_DP_PORT=dat[i-pos_temp];//传送段选数据
		delay_10us(100);//延时一段时间,等待显示稳定
		SMG_A_DP_PORT=0x00;//消音
	}
}
//main.c
/**************************************************************************************
深圳市普中科技有限公司(PRECHIN 普中)
技术支持:www.prechin.net
PRECHIN
 普中

实验名称:DS1302时钟实验
接线说明:	
实验现象:下载程序后,数码管上显示电子时钟时分秒,格式为“XX-XX-XX”
注意事项:																				  
***************************************************************************************/
#include "public.h"
#include "smg.h"
#include "ds1302.h"


/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{	
	u8 time_buf[8];
	
	ds1302_init();//初始化DS1302

	while(1)
	{				
		ds1302_read_time();
		time_buf[0]=gsmg_code[gDS1302_TIME[2]/16];
		time_buf[1]=gsmg_code[gDS1302_TIME[2]&0x0f];
		time_buf[2]=0x40;
		time_buf[3]=gsmg_code[gDS1302_TIME[1]/16];
		time_buf[4]=gsmg_code[gDS1302_TIME[1]&0x0f];
		time_buf[5]=0x40;
		time_buf[6]=gsmg_code[gDS1302_TIME[0]/16];
		time_buf[7]=gsmg_code[gDS1302_TIME[0]&0x0f];
		smg_display(time_buf,1);
	}		
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值