时钟芯片DS1302时序分析、读写代码解析

admin 2025-10-17 05:11:52

1、DS1302芯片原理图分析

引脚名称功能X1、X2外接32.768kHz 晶振,用于内部计时SCLK和主控通信的时钟线I/O数据输入输出引脚CE使能引脚VCC1接电池供电,保证主板掉电时间能继续走VCC2主板的电源供电

(1)DS1302芯片的通信接口是SPI协议接口,只有一根数据线,所以是半双工通信; (2)SPI协议可参考博客:《SPI协议详解(Standard SPI、Dual SPI和Queued SPI)》;

2、芯片寄存器地址定义

(1)与DS1302通信的大致过程:发送命令码表示本次的操作,发送要读取或者写入的数据; (2)比如:要读取秒就先发送0x81命令码,然后从数据线上接收8bit数据来获取秒数;要写入秒就先发送0x80命令码,然后往数据线上依次写8bit数据来设置秒; (3)在DS1302中,时间是以8421BCD码进行保存的,简单一点可以理解成低4bit表示一个含义,高4bit表示一个含义;

3、命令字解析

不同的bit含义bit7必须是逻辑 1. 如果是 0,则禁止对 DS1302写入bit60表示读写日期,1表示操作DS1302内部31字节的RAMbit5-bit1寄存器地址bit00表示写入,1表示读取

4、读写时序分析

(1)起始条件:使能线从低变高,在整个通讯期间使能线必须保持高电平; (2)先发送命令字,表示此次是什么操作; (3)从数据线写入/读取数据; 总结:CE线变高表示通信周期的开始;在每个上升沿,DS1302从数据线读取数据;在每个下降沿,DS1302往数据线写入数据;

5、写芯片寄存器的函数

// 向ds1302的内部寄存器addr写入一个值value

void ds1302_write_reg(unsigned char addr, unsigned char value)

{

unsigned char i = 0;

unsigned char dat = 0;

// 第1部分: 时序起始

SCLK = 0;

delay();

RST = 0;

delay();

RST = 1; // SCLK为低时,RST由低变高,意味着一个大的周期的开始

delay();

// 第2部分: 写入第1字节,addr

//在每个上升沿之前,把要发送给DS1302的数据放到数据线上

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

{

dat = addr & 0x01; // 从低位开始传输的

DSIO = dat; // 把要发送的bit数据丢到IO引脚上去准备好

SCLK = 1; // 制造上升沿,让DS1302把IO上的值读走

delay(); // 读走之后,一个小周期就完了

SCLK = 0; // 把SCLK拉低,是为了给下一个小周期做准备

delay();

addr >>= 1; // 把addr右移一位

}

// 第3部分: 写入第2字节,value

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

{

dat = value & 0x01; // SPI是从低位开始传输的

DSIO = dat; // 把要发送的bit数据丢到IO引脚上去准备好

SCLK = 1; // 制造上升沿,让DS1302把IO上的值读走

delay(); // 读走之后,一个小周期就完了

SCLK = 0; // 把SCLK拉低,是为了给下一个小周期做准备

delay();

value = value >> 1; // 把addr右移一位

}

// 第4部分: 时序结束

SCLK = 0; // SCLK拉低为了后面的周期时初始状态是对的

delay();

RST = 0; // RST拉低意味着一个大周期的结束

delay();

}

6、读芯片寄存器的函数

// 从ds1302的内部寄存器addr读出一个值,作为返回值

unsigned char ds1302_read_reg(unsigned char addr)

{

unsigned char i = 0;

unsigned char dat = 0; // 用来存储读取到的一字节数据的

unsigned char tmp = 0;

// 第1部分: 时序起始

SCLK = 0;

delay();

RST = 0;

delay();

RST = 1; // SCLK为低时,RST由低变高,意味着一个大的周期的开始

delay();

// 第2部分: 写入要读取的寄存器地址,addr

//在每个上升沿之前,把要发送给DS1302的数据放到数据线上

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

{

dat = addr & 0x01; // 从低位开始传输的

DSIO = dat; // 把要发送的bit数据丢到IO引脚上去准备好

SCLK = 1; // 制造上升沿,让DS1302把IO上的值读走

delay(); // 读走之后,一个小周期就完了

SCLK = 0; // 把SCLK拉低,是为了给下一个小周期做准备

delay();

addr >>= 1; // 把addr右移一位

}

// 第3部分: 读出一字节DS1302返回给我们的值

dat = 0;

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

{

// 在前面向ds1302写入addr的最后一个bit后,ds1302就会将读取到的寄存器值

// 的第一个bit放入到IO引脚上,所以我们应该先读取IO再制造下降沿然后继续

// 读取下一个bit

tmp = DSIO;

dat |= (tmp << i); // 读出来的数值是低位在前的

SCLK = 1; // 由于上面SCLK是低,所以要先拉到高

delay();

SCLK = 0; // 拉低SCLK制造一个下降沿,让DS1302往数据线放下一个数据

delay();

}

// 第4部分: 时序结束

SCLK = 0; // SCLK拉低为了后面的周期时初始状态是对的

delay();

RST = 0; // RST拉低意味着一个大周期的结束

delay();

// 第5部分:解决读取时间是ff的问题,如果读取时间没有FF乱码,可不加

DSIO = 0;

return dat;

}