51单片机 DS1302可调时钟

DS1302时钟芯片的介绍

DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。 它可以对年、月、日、周、时、分、秒进行计时,且具有闰年补偿等多种功能 RTC(Real Time Clock):实时时钟,是一种集成电路,通常称为时钟芯片。 

由上图,通俗来讲,我们可以知道VCC和GND就相当于一个电器元件的正负极的接口,而CE口就是相当于一个电器元件的总开关,只有打开CE口,我们才能让DS1302在这个芯片工作,去发挥它应有的作用,接着IO口就是用来数据的递送与递出,最后SCLK接口就相当于频率控制器,只有控制到某个频率后,才可以才能保证数据的输入与输出不会丢失,详细的来说,首先,芯片肯定只有收到我们在电脑端输送过来的数据或者输出某些数据到某个地方时才能准确地去执行相应的功能,既然有数据的输入与输出,那么数据最终的目的地肯定要有数据接收器,通过一定的频率,每隔一定的时间接受一个数据,从而使数据能够一个不落地接受,因此SCLK的作用就是这个,打开SCLK接口后,就能保证数据不会丢失。

简洁的解释:

CE是芯片使能,不使能就不能读取,但时钟还是可以运行的; IO数据输入输出,用来获取和修改数据; SCLK串行时钟,发送一个时钟信号。

上图可以看出主要操控的位置只有三个——就是P3_6 P3_5 P3_4这三个串口,

DS1302控制字节与数据流
想要控制DS1302芯片的话,一定离不开DS1302控制字节和数据流这两部分,而这两部分可以这么理解,DS1302时钟芯片是有很多个寄存器的,控制字节就是在哪个位置去控制,必须要说明接下来是在哪里进行控制,可以是在秒的位置,分的位置,又或者是年的位置等其他时间位置上,而数据流就是将我们想要的时间传过去,因为DS1302时钟芯片是只有在我们将一个确切的时间传过去后,该芯片才能从这个时间开始工作,不断地往后计时,当然,一般都会将年 月 日 时 分 秒这些时间进行一个类似赋值的操作。并且有一点要注意,在写代码时,写完控制字节的代码后,还要紧跟对应数据流的代码。

上图是控制字节的所需要输入的指令

DS1302 的一条指令一个字节共 8 位,其中第 7 位(即最高位)固定为 1,这一位如果是0 的话,那写进去也是无效的。 置于第 6 位是选择 RAM 还是 CLOCK 的,我们这里主要讲 CLOCK 时钟的使用,它的 RAM 功能我们不用,所以如果选择 CLOCK 功能,因此第 6位是 0,如果要用 RAM,那第 6 位就是 1。 从第 5 到第 1 位,决定了寄存器的 5 位地址——就是年月日时分秒的寄存器,而第 0 位是读写位,如果要写,这一位就是 0,如果要读,这一位就是 1。
 

 上图是控制字节与数据流并与脉冲图相结合的图,可以更好的读懂。

在控制指令字输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位即位0开始。同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0位到高位7。这前面说的都是从该芯片读出数据的原理,而将数据写入芯片中的原理就与前面有些不同,控制字节的原理都是相同的,而数据流的原理就有些不同,当SCLK脉冲处于上升沿时就能够读取数据。
 

上图是DS1302时钟芯片里面寄存器的图表说明,我们可以将这张图表分为两部分,READ和WRITE这两列为第一部分,剩下几列为第二部分,

首先,第一部分下面的数据是以十六进制的形式来表示的,而这个数据就表示对应的位置,这是在写控制字节时需要看的,比如READ里面的第二行的81(十六进制)就代表秒的地址,而WRITE里面的第二行的80(十六进制)也代表秒的地址,之所以秒的地址有两个,是因为我们要对读写的操作进行区分。

接着,就是第二部分,有0~7位, 8个节,8个节就表示两位数,也就是十六进制的两个数,这是写数据流时需要看的,其中,再秒和分的两行中其实是用7个节来表示的,而CH位为0时,正常工作,为1时时钟停振,进入低功耗状态。

而像在第四行,第三列中,在24数字上面有一条横线,12数字上面却没有横线,这说明这是高低电压有关,有横线的是低电平有效,即电压为零时就可以运作,而没有横线的就是高电平有效,即电压为一时就可以运作。所有像这类的就可以在对应的位置写入二进制的0或1进行选择,然后将整个8位二进制的数转化位16进制的数即可。

而最后一列为寄存器中具有数值含义的值的范围。

其他细节的说明如下:

10 Seconds代表秒的十位数,其他类比。(所以这些用来表示时钟的寄存器属于BCD码,BCD码,用4位二进制数来表示1位十进制数中的0~9这10个数码,是一种二进制的数字编码形式,用二进制编码的十进制代码。)

倒数第二个寄存器为写保护寄存器,其中的WP位为1时,有写保护,DS1302只能读不能写。因此在对DS1302写入数据时,要把WP位清零。

进制转换:

在写入时我们需要将十进制转为BCD码

在读取时我们需要将BCD码转换为10进制

BCD码转十进制:DEC = BCD / 16 * 10  +  BCD % 16 ;

详解:先将BCD的前一位提出BCD/16,再提出BCD后一位BCD%16。最后将两位数整合转换成十进制。多位BCD码同理。

十进制转BCD码:BCD = DEC / 10 * 16 + DEC % 10 ;

  1. "DEC / 10":这部分表示将原始的十进制数(DEC)除以 10。除以 10 的操作实际上是在原始数字中去掉了个位数。例如,对于十进制数 123,"DEC / 10" 等于 12,因为它去掉了个位数,只剩下十位数和百位数。

  2. "DEC / 10 * 16":在上一步之后,得到的结果乘以 16。这是因为BCD码中,每个十进制数字需要用4位二进制数来表示。乘以 16 等于将这个结果左移了4位。左移4位相当于在二进制数中在原来的数字后面加上了4个0。这是因为在二进制中,每一位的左移一位相当于乘以2,左移4位相当于乘以16。

举例来说,如果原始的十进制数是 12,那么 "DEC / 10" 等于 1(去掉个位数),然后 "DEC / 10 * 16" 等于 16。这是因为将1左移4位得到16。所以,最终的BCD码中会有两个4位的二进制数,分别表示十位数和个位数。

时钟程序的编写

主函数
#include <REGX52.H>
#include "LCD1602.h"
#include "DS1302.h"


unsigned char Second;
void main()
{
		LCD_Init();
		DS1302_Init();
		LCD_ShowString(1,1,"  -  -  ");
		LCD_ShowString(2,1,"  :  :  ");
		DS1302_SetTime();

		while(1)
		  {
					DS1302_ReadTime();
					LCD_ShowNum(1,1,DS1302_Time[0],2);		
					LCD_ShowNum(1,4,DS1302_Time[1],2);	
					LCD_ShowNum(1,7,DS1302_Time[2],2);	
					LCD_ShowNum(2,1,DS1302_Time[3],2);		
					LCD_ShowNum(2,4,DS1302_Time[4],2);	
					LCD_ShowNum(2,7,DS1302_Time[5],2);	
			}
}
DS1302模块代码
#include <REGX52.H>
#include "LCD1602.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_Date 		0x86
#define DS1302_Month 		0x88
#define DS1302_Day 			0x8A
#define DS1302_Year 		0x8C
#define DS1302_WP 			0x8E


unsigned char DS1302_Time[]={19,11,16,12,59,55,6};


void DS1302_Init()
{
		DS1302_CE=0;
		DS1302_SCLK=0;
}

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;
}
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;
			DS1302_SCLK=0;   //一个下降沿读取1位
			if(DS1302_IO){Data=Data|(0x01<<i);}  //如果读取的那位为1,则将Data对应位置1,
																						//为假则不改变Data的值,为0
		}
		DS1302_CE=0;
		DS1302_IO=0;
		return Data;
}

void DS1302_SetTime(void)
{
		DS1302_WriteByte(DS1302_WP,0x00); //WP位为1时,有写保护,DS1302只能读不能写。
																				//因此在对DS1302写入数据时,要把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_Date,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,0x80);
}
 
void DS1302_ReadTime(void)
{
		unsigned char Temp;
		Temp=DS1302_ReadByte(DS1302_Year);
		DS1302_Time[0]=Temp/16*10+Temp%16;
		Temp=DS1302_ReadByte(DS1302_Month);
		DS1302_Time[1]=Temp/16*10+Temp%16;
		Temp=DS1302_ReadByte(DS1302_Date);
		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;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值