7、SCLK:
串行时钟,输入;
6、I/O:
数据输入输出口;
5、CE/RST:
复位脚
23、X1、X2是外接晶振脚(32.768KHZ的晶振)
4、地(GND)
(4)DS1302有关日历、时间的寄存器
寄存器的说明如下:
1、秒寄存器(81h、80h)的位7定义为时钟暂停标志(CH)。
当初始上电时该位置为1,
时钟振荡器停止,DS1302处于低功耗状态;只有将秒寄存器的该位置改写为0时,时钟才能开
始运行。
2、小时寄存器(85h、84h)的位7用于定义DS1302是运行于12小时模式还是24小时模式。
当为
高时,选择12小时模式。
在12小时模式时,位5是,当为1时,表示PM。
在24小时模式时,
位5是第二个10小时位
3、控制寄存器(8Fh、8Eh)的位7是写保护位(WP),其它7位均置为0。
在对任何的时钟和
RAM的写操作之前,WP位必须为0。
当WP位为1时,写保护位防止对任一寄存器的写操作。
也就是说在电路上电的初始态WP是1,这时是不能改写上面任何一个时间寄存器的,
只有首先将WP改写为0,才能进行其它寄存器的写操作。
(5)DS1302控制字介绍
控制字的最高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入到DS1302中。
位6:
如果为0,则表示存取日历时钟数据,为1表示存取RAM数据;
位5至位1(A4~A0):
指示操作单元的地址;
位0(最低有效位):
如为0,表示要进行写操作,为1表示进行读操作。
读数据:
读数据时在紧跟8位的控制字指令后的下一个SCLK脉冲的下降沿,读出DS1302的数据,
读出的数据是从最低位到最高位。
写数据:
控制字总是从最低位开始输出。
在控制字指令输入后的下一个SCLK时钟的上升沿时,
数据被写入DS1302,数据输入也是从最低位(0位)开始。
位0(最低有效位):
为1表示进行读操作。
如为0,表示要进行写操作,
控制字后SCLK下降沿读数据SCLK上升沿写数据
(6)DS1302单字节读写时序介绍
DS1302的数据读写是通过I/O串行进行的。
当进行一次读写操作时最少得读写两个字节,第一个字节是控制字节,就是一个命令,告诉DS1302是读还是写操作,是对RAM还是对CLOK寄存器操作,以及操作的址。
第二个字节就是要读或写的数据了。
我们先看
单字节写:
在进行操作之前先得将CE(也可说是RST)置高电平,然后单片机将控制字的位0放到I/O上,当I/O的数据稳定后,将SCLK置高电平,DS1302检测到SCLK的上升沿后就将I/O上的数据读取,然后单片机将SCLK置为低电平,再将控制字的位1放到I/O上,如此反复,将一个字节控制字的8个位传给DS1302。
接下来就是传一个字节的数据给DS1302,当传完数据后,单片机将CE置为低电平,操作结束。
单字节读操作的一开始写控制字的过程和上面的单字节写操作是一样,但是单字节读操作在写控制字的最后一个位,SCLK还在高电平时,DS1302就将数据放到I/O上,单片机将SCLK置为低电平后数据锁存,
单机机就可以读取I/O上的数据。
如此反复,将一个字节的数据读入单片机。
读与写操作的不同就在于,写操作是在SCLK低电平时单片机将数据放到IO上,当SCLK上升沿时,DS1302读取。
而读操作是在SCLK高电平时DS1302放数据到IO上,将SCLK置为低电平后,单片机就可从IO上读取数据。
(7)DS1302操作指令介绍
操作说明:
1首先要通过8EH将写保护去掉,将日期,时间的初值写时各个寄存器。
2然后就可以对80H、82H、84H、86H、88H、8AH、8CH进行初值的写入。
同时也通过秒寄存器将位7的CH值改成0,这样DS1302就开始走时运了。
3将写保护寄存器再写为80H,防止误改写寄存器的值。
4不断读取80H-8CH的值,将它们格式化后显示到1602LCD液晶上
(8)DS1302与单片机接口电路
3、键盘模块设计
按键在单片机系统中是一个很重要的部件。
为了输入数据、查询和控制系统的工作状态,都要用到按键。
本实验用到按键进行时间设置与调整作用。
4、闹铃模块设计
系统采用蜂鸣器作为闹铃输出。
闹铃电路连接如图所示。
系统软件设计
软件设计是本设计的关键,软件程序编写的好坏直接影响着系统运行情况的良好。
因本程序涉及的模块较多,所以程序编写也采用模块化设计,C语言具有编写灵活、移植方便、便于模块化设计的特点,所以本系统的软件采用C51编写。
程序框图如下:
程序如下:
#include
#include"define.h"
voiddelay(uintz)//毫秒级延时函数。
{
uintx,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
voiddi()//蜂鸣器发声函数。
{
beep=0;
delay(100);
beep=1;
}
voidwritecom(ucharcom)//液晶写命令函数。
{
lcdrs=0;//置为写入命令
lcddata=com;//送入数据
delay
(1);
lcden=1;//拉高使能端
delay
(1);
lcden=0;//完成高脉冲
}
voidwritedata(uchardat)//液晶写数据函数。
{
lcdrs=1;//置为写入数据
lcddata=dat;//送入数据
delay
(1);
lcden=1;
delay
(1);
lcden=0;
}
voidwritetime(ucharadd,uchardat)//液晶刷新时分秒。
{//4为时的开始位置,7为分,10为秒。
ucharshi,ge;
shi=dat/10;
ge=dat%10;
writecom(0x80+0x40+add);
writedata(0x30+shi);
writedata(0x30+ge);
}
voidwritenyr(ucharadd,uchardat)//液晶刷新日期。
{//3为年,6为月,9为日。
ucharshi,ge;
shi=dat/10;
ge=dat%10;
writecom(0x80+add);
writedata(0x30+shi);
writedata(0x30+ge);
}
voidwriteweek(ucharweek)//液晶星期几显示函数。
{
writecom(0x80+12);//从第一行隔十二个字符后开始写星期
switch(week)
{
case1:
writedata('M');
writedata('O');
writedata('N');
break;
case2:
writedata('T');
writedata('U');
writedata('E');
break;
case3:
writedata('W');
writedata('E');
writedata('D');
break;
case4:
writedata('T');
writedata('H');
writedata('U');
break;
case5:
writedata('F');
writedata('R');
writedata('I');
break;
case6:
writedata('S');
writedata('A');
writedata('T');
break;
case7:
writedata('S');
writedata('U');
writedata('N');
break;
}
}
voidkeyscan()//键盘扫描函数。
{
key=0;
if(flagalarm==1)//如果闹钟在响,任意键停止闹钟响。
{
if((kmenu==0)||(kup==0)||(kdown==0)||(kalarm==0))
{
delay(5);
if((kmenu==0)||(kup==0)||(kdown==0)||(kalarm==0))
{
while(!
(kmenu&&kup&&kdown&&kalarm));
di();
flagalarm=0;//清除闹钟标志。
}
}
}
if(kmenu==0)//检测功能键。
{
delay(5);
if(kmenu==0)
{
kmenunum++;//记录功能键按下次数。
if(flagseta==1)//检测是否在进行闹钟设置。
if(kmenunum==4)kmenunum=1;//因为进行闹钟设置时,只调节
//时分秒,所以,kmenunum只能等于1,2,3。
flagset=1;//设置标志位,表示在进行各种时间设置。
while(!
kmenu);
di();
switch(kmenunum)//定位光标闪烁点。
{
case1:
writecom(0x80+0x40+11);//秒闪烁。
writecom(0x0f);//开光标闪烁。
break;
case2:
writecom(0x80+0x40+8);//分闪烁。
break;
case3:
writecom(0x80+0x40+5);//时闪烁。
break;
case4:
writecom(0x80+14);//星期闪烁.
break;
case5:
writecom(0x80+10);//日闪烁.
break;
case6:
writecom(0x80+7);//月闪烁.
break;
case7:
writecom(0x80+4);//年闪烁.
break;
case8:
kmenunum=0;
writecom(0x0c);//取消光标闪烁。
flagset=0;//取消时间调节标志。
dswrite(0x8e,0x00);/*允许写操作*/
dswrite(0x80,second/10*16+second%10);//退出时间设置功能时,往DS1302
dswrite(0x82,minute/10*16+minute%10);//中保存所有时间变量的值。
dswrite(0x84,hour/10*16+hour%10);
dswrite(0x8a,week/10*16+week%10);
dswrite(0x86,day/10*16+day%10);
dswrite(0x88,month/10*16+month%10);
dswrite(0x8c,year/10*16+year%10);
dswrite(0x8e,0x80);/*禁止写操作*/
break;
}
}
}
if(kmenunum!
=0)//只有当功能键按下时,才检测增大,减小键.
{
if(kup==0)
{
delay(5);
if(kup==0)
{
while(!
kup);
di();
switch(kmenunum)//根据功能键被按下的次数,调节相应数值。
{
case1:
second++;
if(second==60)
second=0;
writetime(10,second);
writecom(0x80+0x40+11);//因为,上面送液晶显示
break;//一次,光标后移一位,所以要将光标复位.
case2:
minute++;
if(minute==60)
minute=0;
writetime(7,minute);
writecom(0x80+0x40+8);
break;
case3:
hour++;
if(hour==24)
hour=0;
writetime(4,hour);
writecom(0x80+0x40+5);
break;
case4:
week++;
if(week==8)
week=1;
writeweek(week);
writecom(0x80+14);
break;
case5:
day++;
if(day==32)
day=1;
writenyr(9,day);
writecom(0x80+10);
break;
case6:
month++;
if(month==13)
month=1;
writenyr(6,month);
writecom(0x80+7);
break;
case7:
year++;
if(year==100)
year=0;
writenyr(3,year);
writecom(0x80+4);
break;
}
}
}
if(kdown==0)
{
delay(5);
if(kdown==0)
{
while(!
kdown);
di();
switch(kmenunum)//根据功能键被按次数调节相应数值.
{
case1:
second--;
if(second==-1)
second=59;
writetime(10,second);
writecom(0x80+0x40+11);
break;
case2:
minute--;
if(minute==-1)
minute=59;
writetime(7,minute);
writecom(0x80+0x40+8);
break;
case3:
hour--;
if(hour==-1)
hour=23;
writetime(4,hour);
writecom(0x80+0x40+5);
break;
case4:
week--;
if(week==0)
week=7;
writeweek(week);
writecom(0x80+14);
break;
case5:
day--;
if(day==0)
day=31;
writenyr(9,day);
writecom(0x80+10);
break;
case6:
month--;
if(month==0)
month=12;
writenyr(6,month);
writecom(0x80+7);
break;
case7:
year--;
if(year==-1)
year=99;
writenyr