时钟芯片入门指南:从原理到实践
DS1302时钟
实时时钟芯片,精度高、
DS1302芯片可以对年、月、日、周、时、分、秒进行计时,并且具有闰年补偿等多种功能。
采用三线接口与CPU进行同步通信(采用串行数据传送方式简单SPI 3线接口),并可采用突发方式一次传送多个字节的时钟信号或RAM数据。
可以单字节传送和多字节传送方式.
SPI就是串行外围接口,SPI接口是在CPU和外围低速器件之间同步进行串行数据传输,在主器件的移位脉冲下,数据按位传输,高位在前,低位在后,为全双工通信。
SPI接口是以主从方式(一个主器件和多个从器件)工作的,其接口有四种信号:
1.MOSI--主器件数据输出,从器件数据输入(master主器件 slaver从器件 output输出 input输入)
2.MISO--主器件数据输入,从器件数据输出
3.SCLK--时钟信号,由主器件产生
4./CS--从器件使能信号,由主器件控制
DS1302管脚
VCC 1:工作电源 管脚8
VCC 2:备用电源。接入电池断电时提供1302电源 管脚1
X~1~、X~2~:32.76 KHz晶振接入引脚 管脚2、3
GND:接地 管脚4
RST:复位引脚,低电平有效,操作时高电平 管脚5
I/O:数据输入/输出引脚,具有三态功能(高阻态、高电平、低电平) 管脚6
SCLK:串行时钟输入引脚 管脚7
对DS1302的头文件定义
#ifndef __DS1302_H_
#define __DS1302_H_
//---包含头文件---//
#include<reg52.h>
#include<intrins.h>
//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
//---定义ds1302使用的IO口---//
sbit DSIO=P3^4;
sbit RST=P3^5;
sbit SCLK=P3^6;
//---定义全局函数---//
void Ds1302Write(uchar addr, uchar dat);
uchar Ds1302Read(uchar addr);
void Ds1302Init();
void Ds1302ReadTime();
//---加入全局变量--//
extern uchar TIME[7]; //加入全局变量
#endif
DS1302的寄存器
控制寄存器
控制字节的最高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入DS1302中;
位6(D 6)如果为0,则表示存取日历时钟数据,为1表示存取RAM数据;
位5至位1指示操作单元的地址;
最低有效位(D 0 ),如为0表示要进行写操作,为1表示进行读操作,控制字节总是从最低位开始输出。格式如下:
D 7 | D 6 | D 5 | D 4 | D 3 | D 2 | D 1 | D 0 |
1 | RAM/CK | A 4 | A 3 | A 2 | A 1 | A 0 | RD/W |
日历、时钟寄存器
DS1302有12个寄存器,其中有7个寄存器与日历、时钟相关,存放的数据位为BCD码形式。
寄存器名称 | 取值范围 | D 7 | D 6 | D 5 | D 4 | D 3 | D 2 | D 1 | D 0 |
秒寄存器 | 00~59 | CH | 秒的十位 | 秒的个位 | |||||
分寄存器 | 00~59 | 0 | 分的十位 | 分的个位 | |||||
小时寄存器 | 01~12 或 00~23 | 12/24 | 0 | A/P | HR | 小时的个位 | |||
日寄存器 | 01~31 | 0 | 0 | 日的十位 | 日的个位 | ||||
写保护寄存器 | WP | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
注:
1.数据都是以BCD码形式
2.小时寄存器的D 7位为12小时制或24小时制的选择位,当为’1‘时选择12小时制,当为’0‘时选24小时制。
12小时制时,D 5位为’1‘是上午,’0‘是下午;D 4是小时的十位。
24小时制时,D5、D4位为小时的十位。
3.秒寄存器中的CH位为时钟暂停位,当为’1‘时钟暂停,为’0‘时钟启动。
4.写保护位寄存器中的WP为写保护位,当WP=1,写保护,当WP=0,未写保护;
当对日历、时钟寄存器或片内RAM进行写时WP应清零,当对日历、时钟寄存器或片内RAM进行读时WP一般置1
DS1302初始化代码
void Ds1302Init()
{
uchar n;
Ds1302Write(0x8E,0X00); //禁止写保护,就是关闭写保护功能 (写保护位地址,关闭)
for (n=0; n<7; n++)//写入7个字节的时钟信号:分秒时日月周年
{
Ds1302Write(WRITE_RTC_ADDR[n],TIME[n]);
}
Ds1302Write(0x8E,0x80); //打开写保护功能
}
BCD码
用4位 二进制数 来表示1位 十进制数 中的0~9这10个数码,是一种二进制的数字编码形式,用 二进制编码的十进制 代码。. BCD码这种编码形式利用了四个位元来储存一个十进制的数码,使 二进制 和 十进制 之间的转换得以快捷的进行。
二进制码转换为BCD码的方法:
4位二进制码大于1001时,加6(0110)
如:BCD码00001100的二进制码为:
0000 1100+6=0001 0010
读取时钟信息
void Ds1302ReadTime()
{
uchar n;
for (n=0; n<7; n++) //读取7个字节的时钟信号:分秒时日月周年
{
TIME[n] = Ds1302Read(READ_RTC_ADDR[n]);
}
}
片内RAM
单字节方式和多字节方式
时钟突发寄存器可一次性顺序读写除充电寄存器外的所有寄存器内容。 DS1302与RAM相关的寄存器分为两类:一类是单个RAM单元,共31个,每个单元组态为一个8位的字节,其命令控制字为C0H~FDH(单字节),其中奇数为读操作,偶数为写操作;另一类为突发方式下的RAM寄存器,此方式下可一次性读写所有的RAM的31个字节,命令控制字为FEH(写)、FFH(读)。
RST是复位/片选线,通过把RST输入驱动置高电平来启动所有的数据传送。RST输入有两种功能:
首先,RST接通控制逻辑,允许地址/命令序列送入移位寄存器;
其次,RST提供终止单字节或多字节数据的传送手段。当RST为高电平时,所有的数据传送被初始化,允许对DS1302进行操作。
如果在传送过程中RST置为低电平,则会终止此次数据传送,I/O引脚变为高阻态。上电运行时,在Vcc≥2.5V之前,RST必须保持低电平。只有在SCLK为低电平时,才能将RST置为高电平。
数据输入输出(I/O)
在控制指令字输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位即位0开始。同时,在紧跟8位控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0到高位7.
单字节读写
DS1302 是通过SPI串行总线跟单片机通信的,当进行一次读写操作时最少得读取两个字节,第一个字节是控制字节,就是一个命令,告诉DS1302是读还是写操作,是对RAM还是对CLOK寄存器操作。第二个字节就是要读或写的数据了。
单字节读写:
只有在SCLK(时钟)为低电平时,才能将CE(P 35)置为高电平。所以在进行操作之前先将SCLK(P 36)置低电平,然后将CE置为高电平,接着开始在IO(P 34)上面放入要传送的电平信号,然后跳变SCLK。数据在SCLK上升沿时,DS1302读写数据,在SCLK下降沿时,DS1302放置数据到IO上。
对DS1302的操作主要步骤:
1.去掉写保护;
2.进行时间初始值的设置;
3.加上写保护;
4.不断的读取时间、日期信息并进行显示。
前三步工作只需要进行一次,可以放在初始化中进行。
涉及的操作:
写操作(写地址+写数据)、读操作(写地址+读数据)、显示时间和日期
写函数代码 向DS1302命令(写地址+写数据)
void Ds1302Write(uchar addr, uchar dat)
{
uchar n;
RST = 0; //最开始将CE置为低电平
_nop_();
SCLK = 0; //先将SCLK置低电平。
_nop_();
RST = 1; //然后将RST(CE)置高电平。
_nop_();
for (n=0; n<8; n++) //开始传送八位地址命令,写数据
{
DSIO = addr & 0x01; //数据从低位开始传送,取出最低位
addr >>= 1;
SCLK = 1; //数据在上升沿时,DS1302读取数据
_nop_();
SCLK = 0;
_nop_();
}
for (n=0; n<8; n++) // 写入8位数据,读数据
{
DSIO = dat & 0x01;
dat >>= 1;
SCLK = 1; //数据在上升沿时,DS1302读取数据
_nop_();
SCLK = 0;
_nop_();
}
RST = 0; //传送数据结束
_nop_();
}
读函数代码 读取一个地址的数据
uchar Ds1302Read(uchar addr)
{
uchar n,dat,dat1;
RST = 0; //最开始CE置低电平
_nop_();
SCLK = 0; //先将SCLK置低电平。
_nop_();
RST = 1; //然后将RST(CE)置高电平。
_nop_();
for(n=0; n<8; n++) //开始传送八位地址命令
{
DSIO = addr & 0x01; //数据从低位开始传送
addr >>= 1;
SCLK = 1; //数据在上升沿时,DS1302读取数据
_nop_();
SCLK = 0; //DS1302下降沿时,放置数据
_nop_();
}
_nop_();
for(n=0; n<8; n++) //读取8位数据
{
dat1 = DSIO; //从最低位开始接收
dat = (dat>>1) | (dat1<<7);
SCLK = 1;
_nop_();
SCLK = 0; //DS1302下降沿时,放置数据
_nop_();
}
RST = 0;
_nop_(); //以下为DS1302复位的稳定时间,必须的。
SCLK = 1;
_nop_();
DSIO = 0;
_nop_();
DSIO = 1;
_nop_();
return dat;
}