SCLK:
串行时钟,输入,控制数据的输入与输出;I/O:
三线接口时的双向数据线;CE:
输入信号,在读、写数据期间,必须为高。
该引脚有两个功能:
第一,CE开始控制字访问移位存放器的控制逻辑;其次,CE提供完毕单字节或多字节数据传输的方法。
DS1302有如下几组存放器:
①DS1302有关日历、时间的存放器共有12个,其中有7个存放器〔读时81h~8Dh,写时80h~8Ch〕,存放的数据格式为BCD码形式,如下列图。
DS1302有关日历、时间的存放器
小时存放器〔85h、84h〕的位7用于定义DS1302是运行于12小时模式还是24小时模式。
当为高时,选择12小时模式。
在12小时模式时,位5是,当为1时,表示PM。
在24小时模式时,位5是第二个10小时位。
秒存放器〔81h、80h〕的位7定义为时钟暂停标志〔CH〕。
当该位置为1时,时钟振荡器停止,DS1302处于低功耗状态;当该位置为0时,时钟开始运行。
控制存放器〔8Fh、8Eh〕的位7是写保护位〔WP〕,其它7位均置为0。
在任何的对时钟和RAM的写操作之前,WP位必须为0。
当WP位为1时,写保护位防止对任一存放器的写操作。
②DS1302有关RAM的地址
DS1302中附加31字节静态RAM的地址如下列图。
③DS1302的工作模式存放器
所谓突发模式是指一次传送多个字节的时钟信号和RAM数据。
突发模式存放器如下列图。
④此外,DS1302还有充电存放器等。
2读写时序说明
DS1302是SPI总线驱动方式。
它不仅要向存放器写入控制字,还需要读取相应存放器的数据。
要想与DS1302通信,首先要先了解DS1302的控制字。
DS1302的控制字如图。
控制字〔即地址与命令字节〕
控制字的最高有效位〔位7〕必须是逻辑1,如果它为0,如此不能把数据写入到DS1302中。
位6:
如果为0,如此表示存取日历时钟数据,为1表示存取RAM数据;位5至位1〔A4~A0〕:
指示操作单元的地址;位0〔最低有效位〕:
如为0,表示要进展写操作,为1表示进展读操作。
控制字总是从最低位开始输出。
在控制字指令输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从最低位〔0位〕开始。
同样,在紧跟8位的控制字指令后的下一个SCLK脉冲的下降沿,读出DS1302的数据,读出的数据也是从最低位到最高位。
数据读写时序如图。
数据读写时序
3电路原理图:
电路原理图如图,DS1302与单片机的连接也仅需要3条线:
CE引脚、SCLK串行时钟引脚、I/O串行数据引脚,Vcc2为备用电源,外接32.768kHz晶振,为芯片提供计时脉冲。
4软件设计
软件各模块设计流程:
日期功能设计:
时间功能设计:
闹钟功能设计:
程序实现代码:
#include
typedefunsignedcharunchar;
typedefunsignedintunint;
sbitT_CLK=P2^0;//DS1302中串行时钟引脚
sbitT_IO=P2^1;//DS1302中串行数据输入/输出
sbitT_RST=P2^2;//DS1302中复位/片选线
sbitBee=P2^7;
sbitDQ=P3^4;
sbitDT=P0^7;
sbitP1_6=P1^6;
sbitP1_7=P1^7;
sbitTAD=P2^7;
sbitK1=P2^6;
sbitK2=P2^5;
sbitK3=P2^4;
sbitACC0=ACC^0;//累加存放器
sbitACC7=ACC^7;
unchardatayear=0x10,month=0x07,date=0x25,day=0x01,hour=0x12,minute=0x59,second=0x45;
unchardataLed[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};//分别代表0,1,2,3,4,5,6,7,8,9,-
unchardataDispbuff[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
unchardataring[]={0x00,0x00};
unchardataring1[]={0x00,0x00};
unchardataring2[]={0x00,0x00};
unsignedcharCode[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};
uncharsec,min,hou,dat,mon,wek,yea,i=0,j=0,i1=0,i2=0,i3=0,i4=0;
longk=0;
voidCDelay(uncharCDelay)//延时
{
while(CDelay--);
}
ReadOneChar(void)//读一个字节
{
unchari=0;
unchardat=0;
for(i=8;i>0;i--)
{
DQ=0;
dat>>=1;
DQ=1;
if(DQ)//判断DQ上下电平,假如为高电平如此赋给dat高电平值
{
dat|=0x80;
}
CDelay(4);//延时
}
return(dat);//返回dat值
}
WriteOneChar(unchardat)//写一个字节
{
unchari=0;
for(i=8;i>0;i--)
{
DQ=0;//低电平脉冲信号
DQ=dat&0x01;
CDelay(5);//延时
DQ=1;//高电平脉冲信号
dat>>=1;//dat右移一位
}
CDelay(4);
}
voidoneByteToClock(uncharucDa)//向DS1302中写一位
{
unchari;
ACC=ucDa;
for(i=8;i>0;i--)
{
T_IO=ACC0;//相当于汇编中的RRC
T_CLK=1;
T_CLK=0;
ACC=ACC>>1;//下一位移到ACC0
}
}
uncharoneByteFromClock(void)//从DS1302中读一位
{
unchari;
for(i=8;i>0;i--)
{
ACC=ACC>>1;//*相当于汇编中的RRC
ACC7=T_IO;
T_CLK=1;
T_CLK=0;
}
return(ACC);
}
voidgiveOneTime(uncharucAddr,uncharucDa)
{
T_RST=0;
T_CLK=0;
T_RST=1;
oneByteToClock(ucAddr);//地址,命令
oneByteToClock(ucDa);//写1Byte数据
T_CLK=1;
T_RST=0;
}
unchargetOneTime(uncharucAddr)
{
uncharucDa;
T_RST=0;
T_CLK=0;
T_RST=1;
oneByteToClock(ucAddr);//地址,命令
ucDa=oneByteFromClock();//读1Byte数据
T_CLK=1;
T_RST=0;
return(ucDa);
}
voidresetTime(void)
{
giveOneTime(0x8e,0x00);//8e:
写存放器BIT7=WP控制命令,WP=0,写操作
T_RST=0;
T_CLK=0;
T_RST=1;
oneByteToClock(0xbe);//0xbe:
时钟突发模式:
写存放器时钟多字节写命令
oneByteToClock(second);
oneByteToClock(minute);
oneByteToClock(hour);
oneByteToClock(date);
oneByteToClock(month);
oneByteToClock(day);
oneByteToClock(year);
oneByteToClock(0);
T_CLK=1;
T_RST=0;
}
voiddisTime(void)
{
uncharsec,min,hou,dat,mon,wek,yea,i,j=0;
T_RST=0;
T_CLK=0;
T_RST=1;
oneByteToClock(0xbf);//*0xbf:
时钟突发模式存放器:
读存放器时钟多字节读命令
sec=oneByteFromClock();
min=oneByteFromClock();
hou=oneByteFromClock();
dat=oneByteFromClock();
mon=oneByteFromClock();
wek=oneByteFromClock();
yea=oneByteFromClock();
T_CLK=1;
T_RST=0;
Dispbuff[0]=sec%16;
Dispbuff[1]=sec/16;
Dispbuff[2]=0xa;
Dispbuff[3]=min%16;
Dispbuff[4]=min/16;
Dispbuff[5]=0xa;
Dispbuff[6]=hou%16;
Dispbuff[7]=hou/16;
for(i=0;i<8;i++)
{
P1=j;
P0=Led[Dispbuff[i]];
CDelay(60);
j++;
CDelay(60);
}
}
voiddisDate(void)
{
uncharsec,min,hou,dat,mon,wek,yea,i,j=0;
T_RST=0;
T_CLK=0;
T_RST=1;
oneByteToClock(0xbf);//*0xbf:
时钟多字节读命令
sec=oneByteFromClock();
min=oneByteFromClock();
hou=oneByteFromClock();
dat=oneByteFromClock();
mon=oneByteFromClock();
wek=oneByteFromClock();
yea=oneByteFromClock();
T_CLK=1;
T_RST=0;
Dispbuff[0]=dat%16;
Dispbuff[1]=dat/16;
Dispbuff[2]=0xa;
Dispbuff[3]=mon%16;
Dispbuff[4]=mon/16;
Dispbuff[5]=0xa;
Dispbuff[6]=yea%16;
Dispbuff[7]=yea/16;
for(i=0;i<8;i++)
{
P1=j;
P0=Led[Dispbuff[i]];
CDelay(60);
j++;
CDelay(60);
}
}
voidiniClock()
{
giveOneTime(0x8e,0x00);//控制写入WP=0
giveOneTime(0x90,0xa5);
giveOneTime(0x80,second);//秒
giveOneTime(0x82,minute);//分
giveOneTime(0x84,hour);//时
giveOneTime(0x86,date);//日
giveOneTime(0x88,month);//月
giveOneTime(0x8a,day);//星期
giveOneTime(0x8c,year);//年*/
giveOneTime(0x8e,0x80);
}
uncharbcdToChar(uncharbcd)
{uncharn;
n=(bcd>>4)*10+(bcd&0x0F);
returnn;
}
uncharcharToBcd(uncharnum)
{
uncharn;
n=((num/10)<<4)|(num%10);
returnn;
}
uncharsToS(unchars)
{
uncharn;
n=(s/16)*10+(s%16);
returnn;
}
voiddisRing()//闹钟1设置显示
{
P1=0;
P0=Led[ring[0]%10];
CDelay(60);
P1=1;
P0=Led[ring[0]/10];
CDelay(60);
P1=4;
P0=Led[ring[1]%10];
CDelay(60);
P1=5;
P0=Led[ring[1]/10];
CDelay(60);
}
voiddisRing1()//闹钟2设置显示
{
P1=0;
P0=Led[ring1[0]%10];
CDelay(60);
P1=1;
P0=Led[ring1[0]/10];
CDelay(60);
P1=4;
P0=Led[ring1[1]%10];
CDelay(60);
P1=5;
P0=Led[ring1[1]/10];
CDelay(60);
}
voiddisRing2()//闹钟3设置显示
{
P1=0;
P0=Led[ring2[0]%10];
CDelay(60);
P1=1;
P0=Led[ring2[0]/10];
CDelay(60);
P1=4;
P0=Led[ring2[1]%10];
CDelay(60);
P1=5;
P0=Led[ring2[1]/10];
CDelay(60);
}
voidDateDisF()
{
if(i==0)
{
disDate();
//K1
if(K1==0&&i1==0)
{
i1=1;
yea=bcdToChar(getOneTime(0x8d));
if(yea==89)
{
yea=0;
yea=charToBcd(yea);
giveOneTime(0x8e,0x00);//*控制命令,WP=0,写操作
giveOneTime(0x8c,yea);//写存放器指令,年
giveOneTime(0x8e,0x80);
disDate();
}
else{
yea=yea+1;
yea=charToBcd(yea);
giveOneTime(0x8e,0x00);//*控制命令,WP=0,写操作
giveOneTime(0x8c,yea);//写存放器指令,年
giveOneTime(0x8e,0x80);
disDate();
}
}
//K2
if(K2==0&&i2==0)
{
i2=1;
mon=bcdToChar(getOneTime(0x89));
if(mon==12)
{
mon=1;
mon=charToBcd(mon);
giveOneTime(0x8e,0x00);//*控制命令,WP=0,写操作?
giveOneTime(0x88,mon);//写存放器指令,月
giveOneTime(0x8e,0x80);
disDate();
}
else{
mon=mon+1;
mon=charToBcd(mon);
giveOneTime(0x8e,0x00);//*控制命令,WP=0,写操作?
giveOneTime(0x88,mon);//写存放器指令,月
giveOneTime(0x8e,0x80);
disDate();
}
}
//K3
if(K3==0&&i3==0)
{
i3=1;
mon=bcdToChar(getOneTime(0x89));
dat=bcdToChar(getOneTime(0x87));
yea=bcdToChar(getOne