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

1、DS1302芯片原理图分析

时钟芯片DS1302时序分析、读写代码解析_第1张图片

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

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

2、芯片寄存器地址定义

时钟芯片DS1302时序分析、读写代码解析_第2张图片

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

3、命令字解析时钟芯片DS1302时序分析、读写代码解析_第3张图片

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

4、读写时序分析时钟芯片DS1302时序分析、读写代码解析_第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;
}

推荐

给大家推荐一个学校嵌入式知识的网站,博主在大学时候学习嵌入式知识、找工作的时候都在用这个网站,网站里有C语言、Linux等等的笔试题、面试常问问题等等知识,无论是学习基础知识、面试刷题、交流工作经验都是不错的选择。大家一起进步,欢迎留言交流。
链接:学习神器跳转
在这里插入图片描述
在这里插入图片描述

你可能感兴趣的:(51/stm32单片机,单片机,嵌入式硬件,DS1302)