SCLK:
串行时钟,输入,控制数据的输入与输出;
I/O:
三线接口时的双向数据线;
CE:
输入信号,在读、写数据期间,必须为高。
该引脚有两个功能:
第一,CE开始控制字访问移位寄存器的控制逻辑;其次,
CE提供结束单字节或多字节数据传输的方法。
DS1302有下列几组寄存器:
①DS1302有关日历、时间的寄存器共有12个,其中有7个寄存器
(读时81h~8Dh,写时80h~8Ch),存放的数据格式为BCD码形式,如图3所示。
图3DS1302有关日历、时间的寄存器小时寄存器(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的地址如图4所示。
图4
③DS1302的工作模式寄存器
所谓突发模式是指一次传送多个字节的时钟信号和RAM数据。
突发模式寄存器如图5所示。
图5
④此外,DS1302还有充电寄存器等。
2读写时序说明
DS1302是SPI总线驱动方式。
它不仅要向寄存器写入控制字,还需要读取相应寄存器的数据。
要想与DS1302通信,首先要先了解DS1302的控制字。
DS1302
的控制字如图6。
图6控制字(即地址及命令字节)
控制字的最高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入到DS1302中。
位6:
如果为0,则表示存取日历时钟数据,为1表示存取RAM数据;
位5至位1(A4~A0):
指示操作单元的地址;
位0(最低有效位):
如为0,表示要进行写操作,为1表示进行读操作。
控制字总是从最低位开始输出。
在控制字指令输入后的下一个
SCLK时钟的上升沿时,数据被写入DS1302,数据输入从最低位(0位)开始。
同样,在紧跟8位的控制字指令后的下一个SCLK脉冲的下降沿,读出DS1302的数据,读出的数据也是从最低位到最高位。
数据读写时序如图7。
图7数据读写时序
具体操作见驱动程序。
3电路原理图:
电路原理图如图8,DS1302与单片机的连接也仅需要3条线:
CE引脚、
SCLK串行时钟引脚、I/O串行数据引脚,Vcc2为备用电源,外接
32.768kHz晶振,为芯片提供计时脉冲。
图8
以上部分是我拷贝别人的,在此我要感谢他,后面的部分全部是我自己写的,经过调试,系统运行稳定。
本来是不准备拷贝的,但考虑读者可能会读不懂程序,所以我才将核心器件的通信协议拿来给大家看看,当初老师叫我随便用C语言编写个单片机程序,于是我就找了个DS1302时钟的程序,写的有点长,可能是我第一次经验不够吧。
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
ucharcodetable[]=
{0xc0,0xf9,0xa4,0xb0,
0x99,0x92,0x82,0xf8,
0x80,0x90,0x7f};//0123456789.
sbitsclk=P3^6;
sbitdata_io=P3^7;
sbitrst=P3^5;
sbitk1=P1^4;//mod功能选择键
sbitk2=P1^5;//--(待机时按此键显示当前日期)
sbitk3=P1^6;//++(待机时,按此键显示闹钟时间及状态,进入闹钟设定时此键是闹铃开关键)
sbitk4=P1^7;//退出设定
sbitdidi=P3^0;//闹钟铃音
ucharmod;
ucharkaiguan;
bitkeys(void);//函数申明
voidshow(x,y,z);//函数申明
voidalarmshow(a_shi,a_fen);//函数申明
voiddelay(uintms)//1ms延时子程序
{
uinti,j;
for(i=ms;i>0;i--)
for(j=244;j>0;j--);
}
voidalarmdisplay(ucharshu,ucharwei)//闹钟显示子程序
{
P2=0x00;
P0=table[shu];
P2=(1<delay
(1);
P2=0x00;
if(kaiguan%2)//显示ON12-23,闹钟时间显示格式
{
P0=0xc0;
P2=0x01;
delay
(1);
P2=0x00;
P0=0xc8;
P2=0x02;
delay
(1);
P2=0x00;
P0=0xf7;
P0=0x08;
delay
(1);
P2=0x00;
}
else//显示OFF12-23,闹钟时间显示格式
{
P2=0x00;
P0=0xc0;
P2=0x01;
delay
(1);
P2=0x00;
P0=0x8e;
P2=0x02;
delay
(1);
P2=0x00;
P0=0x8e;
P2=0x04;
delay
(1);
P2=0x00;
}
}
voiddisplay(ucharshu,ucharwei)//显示函数
{
P2=0x00;
P0=table[shu];
P2=(1<delay
(1);
P2=0x00;//显示该位数字
P0=0xbf;
P2=0x04;
delay
(1);//显示横杠
P2=0x00;
P0=0xbf;
P2=0x20;
delay
(1);//显示横杠
P2=0x00;
}
voidweidisplay(void)//调时间时显示调整哪一个位
{
ucharwei;
P2=0x00;
P0=0x7f;
if(mod==1||mod==4||mod==7)
wei=3;
if(mod==2||mod==5)
wei=0;
if(mod==3||mod==6)
wei=6;
P2=(3<delay(3);
P2=0x00;
}
voidalarm()//闹钟铃音子程序
{
uinti;
for(i=59;i>0;i--)
{
didi=1;
delay
(1);
didi=0;
delay
(1);
if(k1==0)
{
delay(5);
if(k1==0)
{
while(~k1);
break;
}
}
}
}
voidwrite(ucharaddr,ucharshu)//写两个字节
{
uchartemp,t;
rst=0;
sclk=0;
rst=1;
temp=addr;
for(t=0;t<8;t++)
{
if(temp&0x01)
data_io=1;
elsedata_io=0;
sclk=1;
delay
(1);
sclk=0;
temp>>=1;
}
temp=shu;
for(t=0;t<8;t++)
{
if(temp&0x01)
data_io=1;
elsedata_io=0;
sclk=1;
delay
(1);
sclk=0;
temp>>=1;
}
rst=0;
}
ucharread(ucharaddr)//读一个字节
{
uchartemp,t;
rst=0;
sclk=0;
rst=1;
temp=addr;
for(t=0;t<8;t++)
{
if(temp&0x01)
data_io=1;
elsedata_io=0;
sclk=1;
sclk=0;
temp>>=1;
}
temp=0;
for(t=0;t<7;t++)
{
if(data_io==1)
temp=temp|0x80;
elsetemp=temp&0x7f;
sclk=1;
sclk=0;
temp>>=1;
}
returntemp;
}
//************************************************8888
//************************************************8888
voidmain()//主函数
{
bitflag;
ucharshi,fen,miao,nian,yue,ri,a_shi,a_fen;//当前时间10:
06:
5310-12-20
write(0x80,0x53);
write(0x82,0x06);//秒寄存器(初始化年月日,时分秒,闹铃)
write(0x84,0x10);//时寄存器
write(0x86,0x20);//日寄存器
write(0x88,0x12);//月寄存器
write(0x8c,0x10);//年寄存器
a_shi=0x07;//初始化闹钟时间7:
30
a_fen=0x30;
while
(1)
{
shi=read(0x85);//读小时
fen=read(0x83);//读分钟
miao=read(0x81);//读秒钟
if(kaiguan%2)//判断闹钟
{
if(a_shi==shi&&a_fen==fen)
alarm();
}
if(k3==0&&mod==0)//待机情况下按k3显示闹铃时间
{
delay(5);
if(k3==0&&mod==0)
{
while(~k3)
alarmshow(a_shi,a_fen);
}
}
if(k2==0&&mod==0)//待机情况下按k2显示日期
{
delay(5);
if(k2==0&&mod==0)
{
while(~k2)
show(nian,yue,ri);
}
}
flag=keys();//按键标识位,有按键按下时flag=1;
if
(1)//程序出现个小错误,原本这里是写flag,但没有办法,只能写1了,感兴趣的话自己分析
{
if(mod==1)
{
if(k4==0)//如果k4=0,则退出设定
{
delay(5);
if(k4==0)
{
while(~k4);
mod=0;
}
}
if(k2==0)
{
delay(5);
if(k2==0)
{
while(~k2);
fen=(fen>>4)*10+(fen&0x0f);
fen++;
if(fen==60)
fen=0;
fen=((fen/10)<<4)+((fen%10)&0x0f);
write(0x82,fen);
}
}
}
if(mod==2)
{
if(k4==0)//如果k4=0,则退出设定
{
delay(5);
if(k4==0)
{
while(~k4);
mod=0;
}
}
if(k2==0)
{
delay(5);
if(k2==0)
{
while(~k2);
shi=(shi>>4)*10+(shi&0x0f);
shi++;
if(shi==24)
shi=0;
shi=((shi/10)<<4)+((shi%10)&0x0f);
write(0x84,shi);
}
}
}
if(mod==1)
{
if(k4==0)//如果k4=0,则退出设定
{
delay(5);
if(k4==0)
{
while(~k4);
mod=0;
}
}
if(k3==0)
{
delay(5);
if(k3==0)
{
while(~k3);
fen=(fen>>4)*10+(fen&0x0f);
if(fen==0)
fen=60;
fen--;
fen=((fen/10)<<4)+((fen%10)&0x0f);
write(0x82,fen);
}
}
}
if(mod==2)
{
if(k4==0)//如果k4=0,则退出设定
{
delay(5);
if(k4==0)
{
while(~k4);
mod=0;
}
}
if(k3==0)
{
delay(5);
if(k3==0)
{
while(~k3);
shi=(shi>>4)*10+(shi&0x0f);
if(shi==0)
shi=24;
shi--;
shi=((shi/10)<<4)+((shi%10)&0x0f);
write(0x84,shi);
}
}
}
if(mod==3)
{
if(k4==0)//如果k4=0,则退出设定
{
delay(5);
if(k4==0)
{
while(~k4);
mod=0;
}
}
if(k2==0)
{
delay(5);
if(k2==0)
{
while(~k2);
ri=(ri>>4)*10+(ri&0x0f);
ri++;
if(ri==32)
ri=0;
ri=((ri/10)<<4)+((ri%10)&0x0f);
write(0x86,ri);
}
}
}
if(mod==4)
{
if(k4==0)//如果k4=0,则退出设定
{
delay(5);
if(k4==0)
{
while(~k4);
mod=0;
}
}
if(k2==0)
{
delay(5);
if(k2==0)
{
while(~k2);
yue=(yue>>4)*10+(yue&0x0f);
yue++;
if(yue==13)
yue=0;
yue=((yue/10)<<4)+((yue%10)&0x0f);
write(0x88,yue);
}
}
}
if(mod==5)
{
if(k4==0)//如果k4=0,则退出设定
{
delay(5);
if(k4==0)
{
while(~k4);
mod=0;
}
}
if(k2==0)
{
delay(5);
if(k2==0)
{
while(~k2);
nian=(nian>>4)*10+(nian&0x0f);
nian++;
if(nian==100)
nian=0;
nian=((nian/10)<<4)+((nian%10)&0x0f);
write(0x8c,nian);
}
}
}
if(mod==3)//年月日减
{
if(k4==0)//如果k4=0,则退出设定
{
delay(5);
if(k4==0)
{
while(~k4);
mod=0;
}
}
if(k3==0)
{
delay(5);
if(k3==0)
{
while(~k3);
ri=(ri>>4)*10+(ri&0x0f);
if(ri==0)
ri=32;
ri--;
ri=((ri/10)<<4)+((ri%10)&0x0f);
write(0x86,ri);
}
}
}
if(mod==4)
{
if(k4==0)//如果k4=0,则退出设定
{
delay(5);
if(k4==0)
{
while(~k4);
mod=0;
}
}
if(k3==0)
{
delay(5);
if(k3==0)
{
while(~k3);
yue=(yue>>4)*10+(yue&0x0f);
if(yue==0)
yue=32;
yue--;
yue=((yue/10)<<4)+((yue%10)&0x0f);
write(0x88,yue);
}
}
}
if(mod==5)
{
if(k4==0)//如果k4=0,则退出设定
{
delay(5);
if(k4==0)
{
while(~k4);
mod=0;
}
}
if(k3==0)
{
delay(5);
if(k3==0)
{
while(~k3);
nian=(nian>>4)*10+(nian&0x0f);
if(nian==0)
nian=100;
nian--;
nian=((nian/10)<<4)+((nian%10)&0x0f);
write(0x8c,nian);
}
}
}
//*################################################################################
if(mod==6)
{
if(k4==0)//如果k4=0,则退出设定
{
delay(5);
if(k4==0)
{
while(~k4);
mod=0;
}
}
if(k3==0)
{
delay(5);
while(~k3);
kaiguan++;
}
if(k2==0)
{
delay(5);
while(~k2);
a_fen=(a_fen>>4)*10+(a_fen&0x0f);
a_fen++;
if(a_fen==60)
a_fen=0;
a_fen=((a_fen/10)