51单片机与DS1302Write/Read方法

目录

1. DS1302与各接口简介 

2.Write与Read操作

2.1 Write/Rrad与input/output联系【1】

2.2命令字——DS1302的操作指令

2.3 RTC存放时钟相关寄存器

2.4 write/read周期与SCLK、SE时钟联系

3.初始化时钟并通过LCD1602显示实验程序


1. DS1302与各接口简介 

         DS1302 计时芯片包含一个实时时钟/日历和 31 字节的静态 RAM.通过简单的串行接口(SCLK,IO,CE)与微处理器通讯。(该A2单片机板子备用电源VCC1没有硬件支持,所以没有断电后计时功能)

d2b76d43bb164ed993605af7d12c2774.png

图1.1. DS1302模块图 

b651895523274fbea1f56e10dad5804c.png

 图1.2 DS1302内部逻辑结构图

  •  VCC2: 双供电配置中的主电源供应管脚,VCC1 连接到备用电源,在主电源 失效时保持时间和日期数据。
  • X1、X2:连接到振荡器和标准32.768kHz石英晶振相连,为时钟提供精确1HZ频率。
  • CE: 输入.CE信号在读写时必须保持高电平 
  • I/O: 输入/(推挽)输出,双向传输数据管脚
  • SCLK : 用来同步(控制)串行接口上的数据动作

2.Write与Read操作

2.1 Write/Rrad与input/output联系【1】

0a6bbde14c6643c8b44cafb497ed1f75.jpg

图2.1 单片机芯片与外设通信

  • 单片机芯片Read外设芯片/器件Output的数据;
  • 单片机芯片Write的数据通过外设芯片/器件Input;

2.2命令字——DS1302的操作指令

        命令字存于DS1302中控制寄存器,命令字启动每一次数据传输,每次read或write前八个周期上升沿就是将命令字写入DS1302控制寄存器,随后便根据这个命令字决定如何处理接着的数据。

  • 位 7  必须是逻辑 1. 如果是 0, 则禁止对 DS1302写入.
  • 位 6  在逻辑 0时表示接下来操作的是时钟/日历数据,逻辑 1时则为 RAM数据. 
  • 位 0  在逻辑0时为Write操作,逻辑1时为Read操作.
  • 位1-位5为要操作的(寄存器或RAM)地址(A0-A4与下图为A1-A5一样)

6edaebc944744f7c958a3cbb8a713f33.png

图 2.2 命令字(指令)格式

2.3 RTC存放时钟相关寄存器

         注意存放时钟日期(年月日时分秒星期)相关寄存器采用BCD码存储在寄存器中(因此时钟自动进位是按照BCD码进行进位的,所以要以BCD码输入和BCD转换成十进制输出)。因此输入write建议用16进制0xXX输入,Read时记得转BCD为十进制。(A0-A4就是A1-A5)

例如想对秒寄存器写34s:

那命令字为 1 0 00000  0 =0x80

写入数据为0x34,秒寄存器内内容为 0011 0100

  2.4 write/read周期与SCLK、SE时钟联系

         对于数据input:输入写命令字的 8个 SCLK周期后 ,接下来的 8个 SCLK 周期的上升沿数据字节被输入。在第一次使用DS1302时,必须将WP写保护位置0,允许写人操作。

a4138574fb22446fa81830726b5520fb.png

/*完成一次将命令字Command与Data写入DS1302中Command指定寄存器或RAM*/
void DS1302_WriteByte(unsigned char Command,Data) {
	unsigned char i;
    //以下根据write时序图控制write的CE与SCLK电平
	DS1302_CE = 1;//开始CE必须先置高电平1
	
	for(i=0;i<8;i++)//前八个周期上升沿IO内容作为命令字被写入DS1302控制寄存器
	{
		DS1302_IO = Command&(0x01<<i);//将低位到高位送到IO
		DS1302_SCLK =1;//上升沿发送
		DS1302_SCLK =0;//恢复低电平0
	}
	
	for(i=0;i<8;i++)//后八个周期上升沿IO内容作为要写入数据被写入DS1302
	{
		DS1302_IO = Data&(0x01<<i);//将低位到高位送到IO
		DS1302_SCLK =1;//上升沿发送
		DS1302_SCLK =0;//恢复低电平0
	}
	
	DS1302_CE = 0;//恢复CE低电平0
}

        对于数据output:输入读命令字的 8个 SCLK周期后, 随后的 8个 SCLK 周期的下降沿,一个数据字节被输出。 注意第一个数据位的传送发生在命令字节被写完后的第一个下降沿。

746d25b053584581a9f7a6228b892c1e.png

/*完成一次将命令字Command写入DS1302控制寄存器,并根据Command内容读出Data*/
unsigned char DS1302_ReadByte(unsigned char Command) {
	unsigned i,Data=0x00;
	Command = Command|1;//根据规律:DS1302_ReadCommand[i] = DS1302_WriteCommand[i] | 1
	DS1302_CE = 1;//开始CE必须先置高电平1
    //Read的整个周期比Write少一个周期,因为在第八个上升沿接着的下降沿IO就收到DS1302数据了
	for(i=0;i<8;i++)
	{
		DS1302_IO = Command&(0x01<<i);//将低位到高位送到IO
		DS1302_SCLK =0;//恢复上一次(第一次循环i=0时SCLK=0不起作用)循环中上升沿1
		DS1302_SCLK =1;//上升沿发送
	}
	
	DS1302_IO = 0;//这里不加会导致readbyte函数在循环中读出255,原因还没想到捏
	
	for(i=0;i<8;i++)//DS1302将数据Output到IO上,接着被单片机read到
	{
		DS1302_SCLK =0;//i=0时,为第八个上升沿接着的下降沿
		if(DS1302_IO == 1)
			Data = Data|(0x01<<i);//将Output到IO上的数据放到Data上(知识:二进制转十进制每位权值,移位操作)
		if(i!=7)
			DS1302_SCLK =1;//i<7时,根据时序图,需要拉高电平
		else
			DS1302_SCLK =0;//在i=7时,整个Read周期结束,不必再置高电平
	}
	DS1302_CE = 0;//恢复CE低电平0
	Data = BCD2D(Data);//因为DS1302存储时间为BCD码格式,将其转十进制返回
	return Data;
}

3.初始化时钟并通过LCD1602显示实验程序

/*DS1302模块代码*/

#include <REGX52.H>
#include "LCD1602.H"
#define DS1302_WP_Command = 0x8e;//写保护字的命令字
sbit DS1302_SCLK = P3^6; //根据开发板原理图定义与DS1602通信线
sbit DS1302_IO = P3^4;
sbit DS1302_CE = P3^5;

//从[0]到[6]存放年、月、日、时、分、秒、星期
unsigned char DS1302_TimeInit[7]= {0x23,0x02,0x08,0x21,0x40,0x00,0x03};
//存放写入RTC年、月、日、时、分、秒、星期寄存器中命令字
unsigned char DS1302_WriteCommand[7] = {0x8c,0x88,0x86,0x84,0x82,0x80,0x8a};
/*
根据规律:DS1302_ReadCommand[i] = DS1302_WriteCommand[i] | 1
0x81 =0x80 | 1 = =0x80 | 0x0000 0001£;
就不用定义DS1302_ReadCommand[i]了,在使用时|=就行
*/

/*初始化,令CE与SCLK为低电平*/
void DS1302_Init(void) {
	DS1302_CE = 0;
	DS1302_SCLK =0;
}
/*将BCD码转为10进制*/
unsigned char BCD2D(unsigned char BCD) {
	unsigned char Data;
	Data = BCD/16*10 + BCD%16;
	return Data;
}
/*完成一次将命令字Command与Data写入DS1302中Command指定寄存器或RAM*/
void DS1302_WriteByte(unsigned char Command,Data) {
	unsigned char i;
    //以下根据write时序图控制write的CE与SCLK电平
	DS1302_CE = 1;//开始CE必须先置高电平1
	
	for(i=0;i<8;i++)//前八个周期上升沿IO内容作为命令字被写入DS1302控制寄存器
	{
		DS1302_IO = Command&(0x01<<i);//将低位到高位送到IO
		DS1302_SCLK =1;//上升沿发送
		DS1302_SCLK =0;//恢复低电平0
	}
	
	for(i=0;i<8;i++)//后八个周期上升沿IO内容作为要写入数据被写入DS1302
	{
		DS1302_IO = Data&(0x01<<i);//将低位到高位送到IO
		DS1302_SCLK =1;//上升沿发送
		DS1302_SCLK =0;//恢复低电平0
	}
	
	DS1302_CE = 0;//恢复CE低电平0
}

/*完成一次将命令字Command写入DS1302控制寄存器,并根据Command内容读出Data*/
unsigned char DS1302_ReadByte(unsigned char Command) {
	unsigned i,Data=0x00;
	Command = Command|1;//根据规律:DS1302_ReadCommand[i] = DS1302_WriteCommand[i] | 1
	DS1302_CE = 1;//开始CE必须先置高电平1
    //Read的整个周期比Write少一个周期,因为在第八个上升沿接着的下降沿IO就收到DS1302数据了
	for(i=0;i<8;i++)
	{
		DS1302_IO = Command&(0x01<<i);//将低位到高位送到IO
		DS1302_SCLK =0;//恢复上一次(第一次循环i=0时SCLK=0不起作用)循环中上升沿1
		DS1302_SCLK =1;//上升沿发送
	}
	
	DS1302_IO = 0;//这里不加会导致readbyte函数在循环中读出255,原因还没想到捏
	
	for(i=0;i<8;i++)//DS1302将数据Output到IO上,接着被单片机read到
	{
		DS1302_SCLK =0;//i=0时,为第八个上升沿接着的下降沿
		if(DS1302_IO == 1)
			Data = Data|(0x01<<i);//将Output到IO上的数据放到Data上(知识:二进制转十进制每位权值,移位操作)
		if(i!=7)
			DS1302_SCLK =1;//i<7时,根据时序图,需要拉高电平
		else
			DS1302_SCLK =0;//在i=7时,整个Read周期结束,不必再置高电平
	}
	DS1302_CE = 0;//恢复CE低电平0
	Data = BCD2D(Data);//因为DS1302存储时间为BCD码格式,将其转十进制返回
	return Data;
}
/*根据DS1302_TimeInit[]内各时间与对应的写命令字DS1302_WriteCommand[]写入各个存放时间寄存器内*/
void DS1302_InitTime(void) {
	unsigned char i;
	DS1302_WriteByte(0x8e,0x00);//关闭写保护,允许修改DS1302内容
	for(i=0;i<7;i++)
	{
		DS1302_WriteByte(DS1302_WriteCommand[i],DS1302_TimeInit[i]);
	}
	DS1302_WriteByte(0x8e,0x80);//打开写保护,禁止修改DS1302内容
}
/*与DS1302_InitTime()功能一样,只是换个名字为了以后项目扩展*/
void DS1302_SetTime() {
	DS1302_InitTime();
}
/*修改DS1302_TimeInit[]内时间为调用该函数时的DS1302内运行的时间*/
void DS1302_getRTCTime(void) {
	unsigned char i;
	for(i=0;i<7;i++)
	{
			DS1302_TimeInit[i] = DS1302_ReadByte(DS1302_WriteCommand[i]|1);
	}
	
}
/*将DS1302此时的时间(年-月-日\n时:分:秒)显示到LCD1602*/
void DS1302_ShowTime(void) {
	unsigned char d;
		d = DS1302_ReadByte(DS1302_WriteCommand[0]|1);
		LCD_ShowString(1,1,"20");LCD_ShowNum(1,3,d,2);
		d = DS1302_ReadByte(DS1302_WriteCommand[1]|1);
		LCD_ShowString(1,5,"-");LCD_ShowNum(1,6,d,2);
		d = DS1302_ReadByte(DS1302_WriteCommand[2]|1);
		LCD_ShowString(1,8,"-");LCD_ShowNum(1,9,d,2);
	
		d = DS1302_ReadByte(DS1302_WriteCommand[3]|1);
		LCD_ShowNum(2,1,d,2);
		d = DS1302_ReadByte(DS1302_WriteCommand[4]|1);
	    LCD_ShowString(2,3,":");LCD_ShowNum(2,4,d,2);
		d = DS1302_ReadByte(DS1302_WriteCommand[5]|1);
	    LCD_ShowString(2,6,":");LCD_ShowNum(2,7,d,2);
	
}

/*main函数部分*/ 

#include <REGX52.H>
#include "DS1302.H"
#include "LCD1602.H"
//#include "Delay1ms.h"

unsigned char s;
void main()
{
	LCD_Init();
	DS1302_Init();
	DS1302_InitTime();
	


	while(1)
	{
		DS1302_ShowTime();
	}
	
}

e650250db0c54c61883d515baba43bf5.jpg

 ——————————————————————————————————————————

【1】查看时序图,芯片是上升沿还是下降沿读写数据_dragon_cdut的博客-CSDN博客_sclk和sdata区别上升沿读数据还是写数据

LCD1602.H文件及源码为B站江科大自化协提供:软件安装包、开发板资料、课件及程序源码百度网盘链接:https://pan.baidu.com/s/1vDTN2o8ffvczzNQGfyjHng 提取码:gdzf,链接里压缩包的解压密码:51 ,如果打不开请复制链接到浏览器再打开

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是基于C语言51单片机驱动DS1302实时时钟的代码,需要用到DS1302的时钟和IO口: ```c #include <reg51.h> sbit SCLK = P1^0; //定义SCLK引脚 sbit DSIO = P1^1; //定义DSIO引脚 sbit RST = P1^2; //定义RST引脚 void Write_DS1302_Byte(unsigned char dat) //写入一个字节的数据 { unsigned char i; for(i=0;i<8;i++) //发送8位数据 { DSIO=dat&0x01; //先发送最低位 SCLK=0; //拉低时钟线 dat>>=1; //移位,准备发送下一位 SCLK=1; //拉高时钟线,数据被写入 } } unsigned char Read_DS1302_Byte() //读取一个字节的数据 { unsigned char i; unsigned char dat=0; for(i=0;i<8;i++) //接收8位数据 { dat>>=1; //先接收最低位 if(DSIO==1) dat|=0x80; //如果接收到高电平,就将最高位设置为1 SCLK=0; //拉低时钟线 SCLK=1; //拉高时钟线,准备接收下一位 } return dat; } void Write_DS1302(unsigned char address,unsigned char dat) //向DS1302写入一个字节的数据 { RST=0; //拉低复位线 SCLK=0; //拉低时钟线 RST=1; //拉高复位线 Write_DS1302_Byte(address); //写入地址 Write_DS1302_Byte(dat); //写入数据 RST=0; //写入完成,再次拉低复位线 } unsigned char Read_DS1302(unsigned char address) //从DS1302读取一个字节的数据 { unsigned char dat; RST=0; //拉低复位线 SCLK=0; //拉低时钟线 RST=1; //拉高复位线 Write_DS1302_Byte(address); //写入地址 dat=Read_DS1302_Byte(); //读取数据 RST=0; //读取完成,再次拉低复位线 return dat; } void DS1302_Init() //初始化DS1302 { Write_DS1302(0x8e,0x00); //禁用写保护 Write_DS1302(0x80,0x00); //秒清零 Write_DS1302(0x82,0x00); //分清零 Write_DS1302(0x84,0x00); //时清零 Write_DS1302(0x86,0x01); //日为1 Write_DS1302(0x88,0x01); //月为1 Write_DS1302(0x8c,0x20); //年为20 Write_DS1302(0x8e,0

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值