完整版DS1302时钟芯片.docx
《完整版DS1302时钟芯片.docx》由会员分享,可在线阅读,更多相关《完整版DS1302时钟芯片.docx(24页珍藏版)》请在冰豆网上搜索。
![完整版DS1302时钟芯片.docx](https://file1.bdocx.com/fileroot1/2022-11/21/83ef4134-1432-4ecf-829f-48db22103d1d/83ef4134-1432-4ecf-829f-48db22103d1d1.gif)
完整版DS1302时钟芯片
第十四讲时钟芯片DS1302
DS1302是DALLAS公司推出的涓流充电时钟芯片,内含有一个实时时钟/日历和31字节静态RAM,通过简单的串行接口与单片机进行通信。
实时时钟/日历电路提供秒、分、时、日、周、月、年的信息,每月的天数和闰年的天数可自动调整。
时钟操作可通过AM/PM指示决定采用24或12小时格式。
DS1302与单片机之间能简单地采用同步串行的方式进行通信,仅需用到三个口线:
(1)RES复位
(2)I/O数据线(3)SCLK串行时钟。
时钟/RAM的读/写数据以一个字节或多达31个字节的字符组方式通信。
DS1302工作时功耗很低保持数据和时钟信息时功率小于1mW。
DS1302由DS1202改进而来增加了以下的特性:
双电源管脚用于主电源和备份电源供应,Vcc1为可编程涓流充电电源,附加七个字节存储器。
它广泛应用于电话、传真、便携式仪器以及电池供电的仪器仪表等产品领域下面。
将主要的性能指标作一综合:
★实时时钟具有能计算2100年之前的秒、分、时、日、星期、月、年的能力,还有闰年调整的能力
★318位暂存数据存储RAM
★串行I/O口方式使得管脚数量最少
★宽范围工作电压2.05.5V
★工作电流2.0V时,小于300nA
★读/写时钟或RAM数据时有两种传送方式单字节传送和多字节传送字符组方式
★8脚DIP封装或可选的8脚SOIC封装根据表面装配
★简单3线接口
★与TTL兼容Vcc=5V
★可选工业级温度范围-40---+85
★双电源管用于主电源和备份电源供应
以上是DS1302的一些全面的预览,以下为DS1302管脚图:
1)VCC2:
主用电源引脚
2)X1、X2:
DS1302外部晶振引脚
3)GND:
地
4)RST:
复位引脚
5)I/O:
串行数据引脚,数据输出或者输入都从这个引脚
6)SCLK:
串行时钟引脚
7)VCC1:
备用电源
1)VCC为主电源接5V,CX10为滤波电容
2)2、外接32.768K的晶振
3)3、5、6、7脚分别与控制器相联,注意外部4.7K上拉电阻
4)4、备用电源脚,注意是3.3V,DS1302要求备用电源电压稍微低于主用电源
下面讲讲DS1302的具体操作。
操作DS1302的大致过程,就是将各种数据写入DS1302的寄存器,以设置它当前的时间已经格式。
然后使DS1302开始运作,DS1302时钟会按照设置情况运转,再用单片机将其寄存器内的数据读出。
再用液晶显示,就是我们常说的简易电子钟。
所以总的来说DS1302的操作分2步(显示部分属于液晶显示的内容,不属于DS1302本身的内容)但是在讲述操作时序之前,我们要先看看寄存器:
上图是DS1302的寄存器样式,我们看到:
1、第7位永远都是1
2、第6位,1表示RAM,寻址内部存储器地址;0表示CK,寻址内部寄存器;
第5位到第1位,为RAM或者寄存器的地址;最低位,高电平表示RD:
即下一步操作将要“读”;低电平表示W:
即下一步操作将要“写”。
(与AT24C02寄存器类似,这点要理解好)。
下面是DS1302的内部寄存器和RAM:
上图左边为寄存器和RAM的地址,右边为具体内容。
各个寄存器的最高位都是1,最低位都是“RD/W”,比如要读秒寄存器则命令为10000101,反之写为10000100,要注意其含义。
(图片不是很清楚,看不清楚的朋友用软件放大)我们一个一个看:
1、SEC:
秒寄存器,注意具体右边内容:
低四位为SEC,高的次三位为10SEC。
最高位CH为
2、DS1302的运行标志,当CH=0时,DS1302内部时钟运行,反之CH=1时停止;
3、MIN:
分寄存器;
4、HR:
时寄存器,最高位为12/24小时的格式选择位,该位为1时表示12小时格式。
当设置为12小时显示格式时,第5位的高电平表示下午(PM);而当设置为24小时格式时,第5位位具体的时间数据。
5、DATE:
日寄存器;
6、MONTH:
月寄存器;
7、DAY:
周寄存器,注意一周只有7天,所以该寄存器只有低三位有效;
8、YEAR:
年寄存器;
9、CONTROL:
写保护寄存器,当该寄存器最高位WP为1时,DS1302只读不写,所以要在往DS1302写数据之前确保WP为0;
10、TRICKLECHARGEREGISTER:
涓细电流充电设置寄存器,我们知道,当DS1302掉电时,可以马上调用外部电源保护时间数据。
该寄存器就是配置备用电源的充电选项的。
其中高四位(4个TCS)只有在1010的情况下才能使用充电选项;低四位的情况,与DS1302内部电路有关,有点意思,下文详细讲述。
11、CLOCKBURST:
批量读写操作设置寄存器,设置该寄存器后,可以对DS1302的各个寄存器进行连续写入。
DS1302的另外一种读写方式。
笔者还没用过,感兴趣的朋友可以尝试。
最后还有一点,前文说过,DS1302有31个字节的存储空间,但是大家要看到的是,这31个存储空间,最后一个是RAMBURST的寄存器,设置该寄存器可以达到对RAM连续读写的作用。
所以DS1302的可用存储空间实际上为30个字节。
现在我们来看看DS1302的涓细电流充电的设置:
以下来自英文原版PDF:
Thetricklechargeselect(TCS)bits(bits4-7)controltheselectionofthetricklecharger.Inordertopreventaccidentalenabling,onlyapatternof1010willenablethetricklecharger.Allotherpatternswilldisablethetricklecharger.TheDS1302powersupwiththetricklechargerdisabled.Thediodeselect(DS)bits(bits2–3)selectwhetheronediodeortwodiodesareconnectedbetweenVCC2andVCC1.IfDSis01,onediodeisselectedorifDSis10,twodiodesareselected.IfDSis00or11,thetricklechargerisdisabledindependentlyofTCS.TheRSbits(bits0-1)selecttheresistorthatisconnectedbetweenVCC2andVCC1.Theresistorselectedbytheresistorselect(RS)bitsisasfollows:
好,英文水平不好也没关系:
看到这句“Thetricklechargeselect(TCS)bits(bits4-7)controltheselectionofthetricklecharger.Inordertopreventaccidentalenabling,onlyapatternof1010willenablethetricklecharger”,这句话是说“,TCS为用以控制涓细电流充电功能,为了防止意外产生,只当TCS位(四位)为1010时涓细电流充电功能才会生效”所以刚才提到“其中高四位(4个TCS)只有在1010的情况下才能使用充电选项”。
那DS呢?
“IfDSis01,onediodeisselectedorifDSis10,twodiodesareselected.IfDSis00or11,thetricklechargerisdisabledindependentlyofTCS”,既是说,如果两个DS位为01,则只有1个二极管接入电路,如果DS为10则表示有2个二极管接入,如果DS为00或者11,则充电功能由TCS单独控制”。
看到上部电路三个二极管处,DS为01时接入1个二极管,对应上面的开关闭合,为10时表示2个二极管接入,对应下面的开关闭合为00或者11时笔者认为两个开关都不闭合,充电电流不经过二极管。
对应的,RS的设置也相仿:
“TheRSbits(bits0-1)selecttheresistorthatisconnectedbetweenVCC2andVCC1.Theresistorselectedbytheresistorselect(RS)bitsisasfollows:
意思是:
RS位用以选择在VCC1和VCC2直接接入什么样的电阻:
1、当RS为00时,不接入电阻;
2、当RS为01时,接入典型值为2K电阻,对应电路图中的R1;
3、当RS为10时,接入典型值为4K电阻,对应电路图中的R2;
4、当RS为11时,接入典型值为8K电阻,对应电路图中的R3;
好了,至此我们知道了,DS和RS的作用是配置接入电路中的二极管和电阻,有什么用呢?
笔者认为这些二极管和电阻是分压和限流用的,以调整涓细充电电流的大小。
我们可以看看DS1302的读写时序了:
上图就是DS1302的三个时序:
复位时序,单字节写时序,单字节读时序;
RST:
复位时序,即在RST引脚产生一个正脉冲,在整个读写器件,RST要保持高电平,一次字节读写完毕之后,要注意把RST返回低电平准备下次读写周期;
SINGLEBYTEREAD:
单字节读,注意读之前还是要先对寄存器写命令,从最低位开始写;大家细心看可以看到,写数据是在SCLK的上升沿实现,而读数据在SCLK的下降沿实现,所以,在单字节读时序中,写命令的第八个上升沿结束后紧接着的第八个下降沿就将要读寄存器的第一位数据读到数据线上了!
这个就是DS1302操作中最特别的地方。
当然读出来的数据也是最低位开始。
SINGLEBUTEWRITE:
单字节写,两个字节的数据配合16个上升沿将数据写入即可。
程序注意事项:
★要记得在操作DS1302之前关闭写保护;
★注意用延时来降低单片机的速度以配合器件时序
★DS1302读出来的数据是BCD码形式,要转换成我们习惯的10进制,转换方法在源程序里;
★读取字节之前,将IO设置为输入口,读取完之后,要将其改回输出口;
★在写程序的时候,建议实现开辟数组(内存空间)来集中放置DS1302的一系列数据,方便以后扩展键盘输入;
打开
/*******************************************************************************
*实验名:
万年历实验
*使用的IO:
*实验效果:
1602显示时钟,按K3进入时钟设置,按K1选择设置的时分秒日月,按K2选择
*选择设置加1。
*注意:
*******************************************************************************/
#include
#include"lcd.h"
#include"ds1302.h"
sbitK1=P3^1;
sbitK2=P3^0;
sbitK3=P3^2;
sbitK4=P3^3;
voidInt0Configuration();
voidLcdDisplay();
unsignedcharSetState,SetPlace;
voidDelay10ms(void);//误差0us
/*******************************************************************************
*函数名:
main
*函数功能:
主函数
*输入:
无
*输出:
无
*******************************************************************************/
voidmain()
{
unsignedchari;
Int0Configuration();
LcdInit();
Ds1302Init();
while
(1)
{
if(SetState==0)
{
Ds1302ReadTime();
}
else
{
if(K1==0)//检测按键K1是否按下
{
Delay10ms();//消除抖动
if(K1==0)
{
SetPlace++;
if(SetPlace>=7)
SetPlace=0;
}
while((i<50)&&(K1==0))//检测按键是否松开
{
Delay10ms();
i++;
}
i=0;
}
if(K2==0)//检测按键K2是否按下
{
Delay10ms();//消除抖动
if(K2==0)
{
TIME[SetPlace]++;
if((TIME[SetPlace]&0x0f)>9)//换成BCD码。
{
TIME[SetPlace]=TIME[SetPlace]+6;
}
if((TIME[SetPlace]>=0x60)&&(SetPlace<2))//分秒只能到59
{
TIME[SetPlace]=0;
}
if((TIME[SetPlace]>=0x24)&&(SetPlace==2))//小时只能到23
{
TIME[SetPlace]=0;
}
if((TIME[SetPlace]>=0x32)&&(SetPlace==3))//日只能到31
{
TIME[SetPlace]=0;
}
if((TIME[SetPlace]>=0x13)&&(SetPlace==4))//月只能到12
{
TIME[SetPlace]=0;
}
if((TIME[SetPlace]>=0x7)&&(SetPlace==5))//周只能到7
{
TIME[SetPlace]=1;
}
//if(SetPlace==5)//月只能到12
//{
//TIME[SetPlace]=;
//}
}
while((i<50)&&(K2==0))//检测按键是否松开
{
Delay10ms();
i++;
}
i=0;
}
}
LcdDisplay();
}
}
/*******************************************************************************
*函数名:
LcdDisplay()
*函数功能:
显示函数
*输入:
无
*输出:
无
*******************************************************************************/
voidLcdDisplay()
{
LcdWriteCom(0x80+0X40);
LcdWriteData('0'+TIME[2]/16);//时
LcdWriteData('0'+(TIME[2]&0x0f));
LcdWriteData('-');
LcdWriteData('0'+TIME[1]/16);//分
LcdWriteData('0'+(TIME[1]&0x0f));
LcdWriteData('-');
LcdWriteData('0'+TIME[0]/16);//秒
LcdWriteData('0'+(TIME[0]&0x0f));
LcdWriteCom(0x80);
LcdWriteData('2');
LcdWriteData('0');
LcdWriteData('0'+TIME[6]/16);//年
LcdWriteData('0'+(TIME[6]&0x0f));
LcdWriteData('-');
LcdWriteData('0'+TIME[4]/16);//月
LcdWriteData('0'+(TIME[4]&0x0f));
LcdWriteData('-');
LcdWriteData('0'+TIME[3]/16);//日
LcdWriteData('0'+(TIME[3]&0x0f));
LcdWriteCom(0x8D);
LcdWriteData('0'+(TIME[5]&0x07));//星期
}
/*******************************************************************************
*函数名:
Int0Configuration()
*函数功能:
配置外部中断0
*输入:
无
*输出:
无
*******************************************************************************/
voidInt0Configuration()
{
//设置INT0
IT0=1;//跳变沿出发方式(下降沿)
EX0=1;//打开INT0的中断允许。
EA=1;//打开总中断
}
/*******************************************************************************
*函数名:
Int0()
*函数功能:
外部中断0中断函数
*输入:
无
*输出:
无
*******************************************************************************/
voidInt0()interrupt0
{
Delay10ms();
if(K3==0)
{
SetState=~SetState;
SetPlace=0;
Ds1302Init();
}
}
/*******************************************************************************
*函数名:
Delay10ms
*函数功能:
延时函数,延时10ms
*输入:
无
*输出:
无
*******************************************************************************/
voidDelay10ms(void)//误差0us
{
unsignedchara,b,c;
for(c=1;c>0;c--)
for(b=38;b>0;b--)
for(a=130;a>0;a--);
}
#include"ds1302.h"
//---DS1302写入和读取时分秒的地址命令---//
//---秒分时日月周年最低位读写位;-------//
ucharcodeREAD_RTC_ADDR[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
ucharcodeWRITE_RTC_ADDR[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
//---DS1302时钟初始化2013年1月1日星期二12点00分00秒。
---//
//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
ucharTIME[7]={0,0,0x12,0x01,0x01,0x02,0x13};
/*******************************************************************************
*函数名:
Ds1302Write
*函数功能:
向DS1302命令(地址+数据)
*输入:
addr,dat
*输出:
无
*******************************************************************************/
voidDs1302Write(ucharaddr,uchardat)
{
ucharn;
RST=0;
_nop_();
SCLK=0;//先将SCLK置低电平。
_nop_();
RST=1;//然后将RST(CE)置高电平。
_nop_();
for(n=0;n<8;n++)//开始传送八位地址命令
{
DSIO=addr&0x01;//数据从低位开始传送
addr>>=1;
SCLK=1;//数据在上升沿时,DS1302读取数据
_nop_();
SCLK=0;
_nop_();
}
for(n=0;n<8;n++)//写入8位数据
{
DSIO=dat&0x01;
dat>>=1;
SCLK=1;//数据在上升沿时,DS1302读取数据
_nop_();
SCLK=0;
_nop_();
}
RST=0;//传送数据结束
_nop_();
}
/*******************************************************************************
*函数名:
Ds1302Read
*函数功能:
读取一个地址的数据
*输入:
addr
*输出:
dat
**************************************************************