DS1302
典型工作电路
命令字
图中显示的是命令字.命令字启动每一次数据传输. MSB (位 7)必须是逻辑 1. 如果是 0,则禁止对 DS1302写入. 位 6 在逻辑 0时规定为时钟/日历数据,逻辑 1时为 RAM数据.
位 1 至 位 5 表示了输入输出的指定寄存器.LSB (位 0) 在逻辑0时为写操作(输出),逻辑1时为读操作(输入).命令字以 LSB (位 0)开始总是输入.
CE 与时钟控制
所有数据传输开始驱动 CE输入高.CE输入实现两个功能.第一, CE 开启允许对地址/命令序列的移位寄存器进行读写的控制逻辑. 第二 CE 信号为单字节和多字节 CE数据传输提供了终止的方法.
一个时钟周期是一系列的上升沿伴随下降沿.要输入数据在时钟的上升沿数据必须有效,而且在下降沿要输出数据位.如果 CE输入为低电平,则所有数据传输终止,并且 I/O 口成高阻抗状态.图 4 显示了数据传输. 在上电时, CE必须为逻辑 0直到 VCC 大于 2.0V. 同样, SCLK 必须为逻辑 0当 CE 变成逻辑 1状态
数据输入
输入写命令字的 8个 SCLK周期后,接下来的 8个 SCLK 周期的上升沿数据字节被输入。如不慎发生, 多余的 SCLK 周期将被忽略,数据输入以位 0开始.
数据输出
输入读命令字的 8个 SCLK周期后, 随后的 8个 SCLK 周期的下降沿,一个数据字节被输出。注意第一个数据位的传送发生在命令字节被写完后的第一个下降沿.
写保护位
控制寄存器的位 7是写保护位,前 7位(位 0至位 6)被强制为 0且读取时总是读 0. 在任何对时钟或 RAM的写操作以前,位 7必须为 0.当为高时,写保护位禁止任何寄存器的写操作. 初始加电状态未定义. 因此,在试图写器件之前应该清除 WP位.
DS1302_Init();
DS1302_WriteByte(0x8E,0x00); //清楚WP位
时钟/日历
时间和日历寄存器的内容是二进制编码的十进制(BCD)格式的.
BCD
BCD码(Binary Coded Decimal),用4位二进制数来表示1位十进制数
例:0001 0011表示13,1000 0101表示85,0001 1010不合法
在十六进制中的体现:0x13表示13,0x85表示85,0x1A不合法
BCD码转十进制:DEC=BCD/16*10+BCD%16; (2位BCD)
十进制转BCD码:BCD=DEC/10*16+DEC%10; (2位BCD)
数据传输摘要
寄存器地址/定义
代码实现
#include <REGX51.H>
sbit DS1302_SCLK = P3^6;
sbit DS1302_IO = P3^4;
sbit DS1302_CE = P3^5;
#define DS1302_SECOND 0x80 //寄存器写入秒的地址
#define DS1302_MINUTE 0x82 //寄存器写入分钟的地址
#define DS1302_HOUR 0x84 //寄存器写入小时的地址
#define DS1302_DATA 0x86 //寄存器写入日的地址
#define DS1302_MONTH 0x88 //寄存器写入月份的地址
#define DS1302_DAY 0x8A //寄存器写入星期的地址
#define DS1302_YEAR 0x8C //寄存器写入年的地址
#define DS1302_WP 0x8E //寄存器写保护位的地址
unsigned char DS1302_Time[] = {24,4,25,19,18,30,4};
void DS1302_Init(void) //时钟芯片开始默认CE和SCLK为0,但单片机上电所有IO口置1,所以需要手动初始化
{
DS1302_CE = 0;
DS1302_SCLK = 0;
}
unsigned char DS1302_ReadByte(unsigned char Command)
{
unsigned char i,Data = 0x00;
Command |= 0x01; //将寄存器写的地址改为读的地址
DS1302_CE = 1;
for (i=0;i<8;i++)
{
DS1302_IO = Command & (0x01 << i);
DS1302_SCLK = 0;
DS1302_SCLK = 1;
}
for (i=0;i<8;i++)
{
DS1302_SCLK = 1; //重复置一次1让时序保持一致
DS1302_SCLK = 0;
if (DS1302_IO)
Data |= (0x01 << i);
}
DS1302_CE = 0;
DS1302_IO = 0; //读取后将数据IO置0,否则读出的数据会出错
return Data;
}
void DS1302_WriteByte(unsigned char Command,Data)
{
unsigned char i;
DS1302_CE = 1;
for (i=0;i<8;i++)
{
DS1302_IO = Command & (0x01 << i);
DS1302_SCLK = 1;
DS1302_SCLK = 0;
}
for (i=0;i<8;i++)
{
DS1302_IO = Data & (0x01 << i);
DS1302_SCLK = 1;
DS1302_SCLK = 0;
}
DS1302_CE = 0;
}
void DS1302_ReadTime(void)
{
//把DS1302现在的时间放到Time数组中去
unsigned char temp;
temp = DS1302_ReadByte(DS1302_YEAR);
DS1302_Time[0] = temp/16*10+temp%16; //将BCD转换成10进制数
temp = DS1302_ReadByte(DS1302_MONTH);
DS1302_Time[1] = temp/16*10+temp%16;
temp = DS1302_ReadByte(DS1302_DATA);
DS1302_Time[2] = temp/16*10+temp%16;
temp = DS1302_ReadByte(DS1302_HOUR);
DS1302_Time[3] = temp/16*10+temp%16;
temp = DS1302_ReadByte(DS1302_MINUTE);
DS1302_Time[4] = temp/16*10+temp%16;
temp = DS1302_ReadByte(DS1302_SECOND);
DS1302_Time[5] = temp/16*10+temp%16;
temp = DS1302_ReadByte(DS1302_DAY);
DS1302_Time[6] = temp/16*10+temp%16;
}
void DS1302_SetTime(void)
{
//Time数组中存放的是十进制数,而设置数据进DS1302中的数据是BCD数,所以要进行数据转换
DS1302_WriteByte(DS1302_WP,0x00); //清楚WP位
DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);
DS1302_WriteByte(DS1302_MONTH,DS1302_Time[1]/10*16+DS1302_Time[1]%10);
DS1302_WriteByte(DS1302_DATA,DS1302_Time[2]/10*16+DS1302_Time[2]%10);
DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);
DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);
DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);
DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);
DS1302_WriteByte(DS1302_WP,0x00); //开启写保护位
}