ds1302 引脚图及功能


 

X1 X2 32.768KHz ————晶振管脚

GND ———— 地

RST ———— 复位脚

I/O ————数据输入 / 输出引脚

SCLK ———— 串行时钟

Vcc1,Vcc2 ————电源供电管脚

 

DS1302 的引脚排列,其中 Vcc2 为主电源,VCC1 为后备电源。在主电源关闭的情况下,也能保持时钟的连续运行。DS1302 由 Vcc1 或 Vcc2 两者中的较大者供电。当 Vcc2 大于 Vcc1+0.2V 时,Vcc2 给 DS1302 供电。当 Vcc2 小于 Vcc1 时,DS1302 由 Vcc1 供电。

 

X1 和 X2 是振荡源,外接 32.768kHz 晶振。RST 是复位 / 片选线,通过把 RST 输入驱动置高电平来启动所有的数据传送。RST 输入有两种功能:首先,RST 接通控制逻辑,允许地址 / 命令序列送入移位寄存器;其次,RST 提供终止单字节或多字节数据传送的方法。

 

当 RST 为高电平时,所有的数据传送被初始化,允许对 DS1302 进行操作。如果在传送过程中 RST 置为低电平,则会终止此次数据传送,I/O 引脚变为高阻态。上电运行时,在 Vcc》2.0V 之前,RST 必须保持低电平。只有在 SCLK 为低电平时,才能将 RST 置为高电平。

 

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

 

DS1302 封装信息




DS1302 应用电路

应用电路一:

DS1302 的电路一个重点就是时钟电路,它所使用的晶振是一个 32.768k 的晶振,晶振外部也不需要额外添加其他的电容或者电阻电路了。时钟的精度,首先取决于晶振的精度以及晶振的引脚负载电容。如果晶振不准或者负载电容过大过小,都会导致时钟误差过大。在这一切都搞定后,最终一个考虑因素是晶振的温漂。随着温度的变化,晶振往往精度会发生变化,因此,在实际的系统中,其中一种方法就是经常校对。比如我们所用的电脑的时钟,通常我们会设置一个选项“将计算机设置于 internet 时间同步”。选中这个选项后,一般可以过一段时间,我们的计算机就会和 internet 时间校准同步一次。

 

 

应用电路二:

1 脚 VCC2 是主电源正极的引脚,2 脚 X1 和 3 脚 X2 是晶振输入和输出引脚,4 脚 GND 是负极,5 脚 CE 是使能引脚,接单片机的 IO 口,6 脚 I/O 是数据传输引脚,接单片机的 IO 口,7 脚 SCLK 是通信时钟引脚,接单片机的 IO 口,8 脚 VCC1 是备用电源引脚。考虑到 KST-51 开发板是一套以学习为目的的板子,加上备用电池对航空运输和携带不方便,所以 8 脚没有接备用电池,而是接了一个 10uF 的电容,这个电容就相当于一个电量很小的电池,经过试验测量得出其可以在系统掉电后仍维持 DS1302 运行 1 分钟左右,如果大家想运行时间再长,可以加大电容的容量或者换成备用电池,如果掉电后不需要它再维持运行,也可以干脆悬空,如图 15-7 和图 15-8 所示。

 

 

涓流充电功能,基本也用不到,因为实际应用中很少会选择可充电电池作为备用电源,成本太高,本课程也不讲了,大家作为选学即可。我们使用的时候直接用 5V 电源接一个二极管,在主电源上电的情况下给电容充电,在主电源掉电的情况下,二极管可以防止电容向主电路放电,而仅用来维持 DS1302 的供电,这种电路的最大用处是在电池供电系统中更换主电池的时候保持实时时钟的运行不中断,1 分钟的时间对于更换电池足够了。此外,通过我们的使用经验,在 DS1302 的主电源引脚串联一个 1K 电阻可以有效的防止电源对 DS1302 的冲击,R6 就是这个电阻,而 R9、R26、R32 都是上拉电阻。

DS1302 写入时序

通过命令的方式写入年月日时分秒信息。 命令格式为 2 字节。 第一字节为地址,第二字节为内容。

 

 

写入逻辑:

1 将 RST 先拉低

2 将 SCLK 拉低(如果不拉低,且本来是高电平,则瞬间就发出了一个 bit,我们还没放数据呢)

3 再 RST 拉高。。 形成一个上升沿

4 在 IO 口放入一个 bit(字节发送顺序,从低位到高位)

5 设 SCLK 为高电平,形成上升沿,这时候 DS1302 就会读取 IO 口的数据存入它的寄存器。

6 拉低 SCLK,为下一个字节做准备。,跳转到 5 ,直到发送完所有的 16 个字节

7 拉低 RST,整个写入过程完成。

 

DS1302 命令格式



虽然命令字节看起来很复杂,但编写程序很简单,比如你要设置秒为 13 秒。那么发送的两个字节的数据应该是什么?第一个字节是 0x80(写入秒的命令,见上图)。第二个数据,第四位为 3,高四位为 1。就是(1<<4)|3,为 0x13

 

其他的年月日类似。比较特殊的几个位说一下。

 

(1)如果想让表停下来

发送一个设置秒的命令,第二个字节最高位置为 1,即,发送 0x800x80 即可。

 

(2)小时的第二个字节的最高位控制着 12 还是 24 进制

Arduino 控制 DS1302 连线


 

Arduino 控制 DS1302 程序

/* * 读写 DS1302 时钟芯片

* @author Yangtf

* 很棒的文档 https://www.21ic.com/jichuzhishi/datasheet/DS1302/data/185858.html

* 时序图 https://www.21ic.com/d/file/201307/0a93263a0126e1580cc71c89dce1fda9.jpg

*

*/

#define RST 7

#define SCLK 6

#define IO 5

//#define L(item) digitalWrite((item),LOW)

//#define H(item) digitalWrite((item),HIGH)

#define uchar unsigned char

void setup() {

pinMode(RST,OUTPUT);

pinMode(SCLK,OUTPUT);

pinMode(IO,OUTPUT);

Serial.begin(9600);

attachInterrupt(0, settm, FALLING );

}

void writeData(unsigned char addr,unsigned char dat)

{

pinMode(IO,OUTPUT);

digitalWrite(RST,LOW); // 下拉低,再拉高

digitalWrite(SCLK,LOW) ; //SCLK 的上升沿, 芯片会读取 IO 端口 d

elayMicroseconds(1);

digitalWrite(RST,HIGH);

int i;

for(i =0;i《8;i++)

{

digitalWrite(SCLK,LOW);

digitalWrite(IO, addr&1);

addr =addr》》1;

digitalWrite(SCLK,HIGH);

delayMicroseconds(1);

}

for(i =0;i《8;i++){

digitalWrite(SCLK,LOW);

digitalWrite(IO, dat&1);

dat =dat》》1;

digitalWrite(SCLK,HIGH);

delayMicroseconds(1);

}

digitalWrite(RST,LOW);

}

uchar readData(uchar addr){

addr = addr | 1; // 读操作最低位置为 1

pinMode(IO,OUTPUT);

digitalWrite(RST,LOW); // 下拉低,再拉高

digitalWrite(SCLK,LOW) ; //SCLK 的上升沿, 芯片会读取 IO 端口

delayMicroseconds(1);

digitalWrite(RST,HIGH);

int i;

for(i =0;i《8;i++){

digitalWrite(SCLK,LOW);

digitalWrite(IO, addr&1);

addr =addr》》1;

digitalWrite(SCLK,HIGH);

delayMicroseconds(1);

}

pinMode(IO,INPUT);

int dat = 0;

for(i =0;i《8;i++){

digitalWrite(SCLK,LOW);

delayMicroseconds(10);

uchar b = digitalRead(IO);

dat = dat 》》1; // 先向右平移

dat = dat | (b《《7); // 将所得放入最高位

digitalWrite(SCLK,HIGH);

delayMicroseconds(1);

}

digitalWrite(RST,LOW);

return dat ;

}

#define SECOND 0x80

#define MIN 0x82

#define HOUR 0x84

#define DAY 0x86

#define MONTH 0x88

#define YEAR 0x8C

#define WEEK 0x8A

void writeTImeUnit(

uchar TYPE,uchar data){

uchar high = data / 10;

uchar low = data % 10;

uchar d = ((data /10) 《《 4) | (data % 10);

writeData(TYPE,data);

}

uchar readTImeUnit(uchar TYPE){

uchar r = readData(TYPE);

r = 10*(r 》》 4)+ (r & 0xf);

return r;

}

void writeAllTm(uchar tm[]){

uchar s = SECOND;

for(uchar i=0;i《5;i++){

writeTImeUnit(s,tm[5-i]);

s+=2; } writeTImeUnit(YEAR,tm[0]);

} void readAllTm(uchar tm[]){

uchar s = SECOND;

for(uchar i=0;i《5;i++){

tm[5-i] = readTimeUnit(s);

s+=2;

}

tm[0] = readTimeUnit(YEAR);

tm[6] = readTimeUnit(WEEK);

}

void printTm(uchar tm[]){

Serial.print(tm[0]);

Serial.print(“-”);

Serial.print(tm[1]);

Serial.print(“-”);

Serial.print(tm[2]);

Serial.print(“ ”);

Serial.print(tm[3]);

Serial.print(“:”);

Serial.print(tm[4]);

Serial.print(“:”);

Serial.print(tm[5]);

Serial.print(“ week ”);

Serial.print(tm[6]);

Serial.println();

}

uchar st = 0;

void loop() {

uchar tm[7] = {0};

readAllTm(tm);

printTm(tm);

delay(1000);

}

void settm()// 中断函数

{

uchar tm[] = {11,12,13,4,5,6 ,0}; // 2011-12-22 3:4:1

Serial.println(“set tm 。。.”);

writeAllTm(tm);

}