51单片机DS1302时钟1602显示可调时钟剖析.docx
《51单片机DS1302时钟1602显示可调时钟剖析.docx》由会员分享,可在线阅读,更多相关《51单片机DS1302时钟1602显示可调时钟剖析.docx(22页珍藏版)》请在冰豆网上搜索。
51单片机DS1302时钟1602显示可调时钟剖析
基于proteus的51单片机仿真实例八十一、实时时钟芯片DS1302应用实例
1、DS1302引脚排列:
如下图
引脚说明:
1)Vcc1:
后备电源,VCC2:
主电源。
在主电源关闭的情况下,也能保持时钟的连续运行。
DS1302由Vcc1或Vcc2两者中的较大者供电。
当Vcc2大于Vcc1+0.2V时,Vcc2给DS1302供电。
当Vcc2小于Vcc1时,DS1302由Vcc1供电。
2)X1、X2:
振荡源,外接32.768kHz晶振。
3)RST:
复位/片选线,通过把RST输入驱动置高电平来启动所有的数据传送。
RST输入有两种功能:
首先,RST接通控制逻辑,允许地址/命令序列送入移位寄存器;其次,RST提供终止单字节或多字节数据的传送手段。
当RST为高电平时,所有的数据传送被初始化,允许对DS1302进行操作。
如果在传送过程中RST置为低电平,则会终止此次数据传送,I/O引脚变为高阻态。
上电运行时,在Vcc>2.0V之前,RST必须保持低电平。
只有在SCLK为低电平时,才能将RST置为高电平。
4)I/O为串行数据输入输出端(双向)。
5)SCLK为时钟输入端。
2、 DS1302的控制字节
DS1302的控制字如下图所示。
控制字节的最高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入DS1302中,位6如果为0,则表示存取日历时钟数据,为1表示存取RAM数据;位5至位1指示操作单元的地址;最低有效位(位0)如为0表示要进行写操作,为1表示进行读操作,控制字节总是从最低位开始输出。
3、数据输入输出(I/O)
在控制指令字输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位即位0开始。
同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0位到高位7。
DS1302的寄存器
DS1302有12个寄存器,其中有7个寄存器与日历、时钟相关,存放的数据位为BCD码形式,其日历、时间寄存器及其控制字见数据手册。
此外,DS1302还有年份寄存器、控制寄存器、充电寄存器、时钟突发寄存器及与RAM相关的寄存器等。
时钟突发寄存器可一次性顺序读写除充电寄存器外的所有寄存器内容。
DS1302与RAM相关的寄存器分为两类:
一类是单个RAM单元,共31个,每个单元组态为一个8位的字节,其命令控制字为C0H~FDH,其中奇数为读操作,偶数为写操作;另一类为突发方式下的RAM寄存器,此方式下可一次性读写所有的RAM的31个字节,命令控制字为FEH(写)、FFH(读)。
下面是其C程序(独家转售):
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
#defineLCDIOP2
sbitrs=P3^0;
sbitrd=P3^1;
sbitlcden=P3^2;
sbitacc0=ACC^0;//移位时的第0位
sbitacc7=ACC^7;//移位时用的第7位
ucharsecond,minute,hour,day,month,year,week,count=0;
ucharReadValue,num,time;
ucharcodetable[]={"2010-11-29MON"};
ucharcodetable1[]={"15:
45:
00"};
ucharcodetable2[]="THUFRISATSUNMONTUEWES";
sbitDATA=P0^1;
sbitRST=P0^2;
sbitSCLK=P0^0;
sbitmenu=P3^5;//菜单
sbitadd=P3^6;//加一
sbitdec=P3^7;//减一
voiddelay(uintz)
{
uintx,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
voiddelay1(uintz)
{
for(;z>0;z--);
}
voidwrite_com(ucharcom)
{
rs=0;
rd=0;
lcden=0;
P2=com;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
voidwrite_date(uchardate)
{
rs=1;
rd=0;
lcden=0;
P2=date;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
voidinit()
{
ucharnum;
lcden=0;
write_com(0x38);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
write_com(0x80);
delay(5);
write_com(0x80);
for(num=0;num<15;num++)
{
write_date(table[num]);
delay(5);
}
write_com(0x80+0x40);
for(num=0;num<10;num++)
{
write_date(table1[num]);
delay(5);
}
}
voidWrite1302(uchardat)
{
uchari;
SCLK=0;//拉低SCLK,为脉冲上升沿写入数据做好准备
delay1
(2);//稍微等待,使硬件做好准备
for(i=0;i<8;i++)//连续写8个二进制位数据
{
DATA=dat&0x01;//取出dat的第0位数据写入1302
delay
(2);//稍微等待,使硬件做好准备
SCLK=1;//上升沿写入数据
delay1
(2);//稍微等待,使硬件做好准备
SCLK=0;//重新拉低SCLK,形成脉冲
dat>>=1;//将dat的各数据位右移1位,准备写入下一个数据位
}
}
voidWriteSet1302(ucharCmd,uchardat)
{
RST=0;//禁止数据传递
SCLK=0;//确保写数居前SCLK被拉低
RST=1;//启动数据传输
delay1
(2);//稍微等待,使硬件做好准备
Write1302(Cmd);//写入命令字
Write1302(dat);//写数据
SCLK=1;//将时钟电平置于已知状态
RST=0;//禁止数据传递
}
ucharRead1302(void)
{
uchari,dat;
delay
(2);//稍微等待,使硬件做好准备
for(i=0;i<8;i++)//连续读8个二进制位数据
{
dat>>=1;//将dat的各数据位右移1位,因为先读出的是字节的最低位
if(DATA==1)//如果读出的数据是1
dat|=0x80;//将1取出,写在dat的最高位
SCLK=1;//将SCLK置于高电平,为下降沿读出
delay1
(2);//稍微等待
SCLK=0;//拉低SCLK,形成脉冲下降沿
delay1
(2);//稍微等待
}
returndat;//将读出的数据返回
}
ucharReadSet1302(ucharCmd)
{
uchardat;
RST=0;//拉低RST
SCLK=0;//确保写数居前SCLK被拉低
RST=1;//启动数据传输
Write1302(Cmd);//写入命令字
dat=Read1302();//读出数据
SCLK=1;//将时钟电平置于已知状态
RST=0;//禁止数据传递
returndat;//将读出的数据返回
}
voidInit_DS1302(void)
{
WriteSet1302(0x8E,0x00);//根据写状态寄存器命令字,写入不保护指令
WriteSet1302(0x80,((0/10)<<4|(0%10)));//根据写秒寄存器命令字,写入秒的初始值
WriteSet1302(0x82,((45/10)<<4|(45%10)));//根据写分寄存器命令字,写入分的初始值
WriteSet1302(0x84,((15/10)<<4|(15%10)));//根据写小时寄存器命令字,写入小时的初始值
WriteSet1302(0x86,((29/10)<<4|(29%10)));//根据写日寄存器命令字,写入日的初始值
WriteSet1302(0x88,((11/10)<<4|(11%10)));//根据写月寄存器命令字,写入月的初始值
WriteSet1302(0x8c,((10/10)<<4|(10%10)));//nian
WriteSet1302(0x8a,((4/10)<<4|(4%10)));
}
voidDisplaySecond(ucharx)
{
uchari,j;
i=x/10;
j=x%10;
write_com(0xc8);
write_date(0x30+i);
write_date(0x30+j);
}
voidDisplayMinute(ucharx)
{
uchari,j;
i=x/10;
j=x%10;
write_com(0xc5);
write_date(0x30+i);
write_date(0x30+j);
}
voidDisplayHour(ucharx)
{
uchari,j;
i=x/10;
j=x%10;
write_com(0xc2);
write_date(0x30+i);
write_date(0x30+j);
}
voidDisplayDay(ucharx)
{
uchari,j;
i=x/10;
j=x%10;
write_com(0x89);
write_date(0x30+i);
write_date(0x30+j);
}
voidDisplayMonth(ucharx)
{
uchari,j;
i=x/10;
j=x%10;
write_com(0x86);
write_date(0x30+i);
write_date(0x30+j);
}
voidDisplayYear(ucharx)
{
uchari,j;
i=x/10;
j=x%10;
write_com(0x83);
write_date(0x30+i);
write_date(0x30+j);
}
voidDisplayWeek(ucharx)
{uchari;
x=x*3;
write_com(0x8c);
for(i=0;i<3;i++)
{
write_date(table2[x]);
x++;
}
}
voidread_date(void)
{
ReadValue=ReadSet1302(0x81);
second=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);
ReadValue=ReadSet1302(0x83);
minute=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);
ReadValue=ReadSet1302(0x85);
hour=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);
ReadValue=ReadSet1302(0x87);
day=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);
ReadValue=ReadSet1302(0x89);
month=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);
ReadValue=ReadSet1302(0x8d);
year=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);
ReadValue=ReadSet1302(0x8b);//读星期
week=ReadValue&0x07;
DisplaySecond(second);
DisplayMinute(minute);
DisplayHour(hour);
DisplayDay(day);
DisplayMonth(month);
DisplayYear(year);
DisplayWeek(week);
}
voidturn_val(charnewval,ucharflag,ucharnewaddr,uchars1num)
{
newval=ReadSet1302(newaddr);//读取当前时间
newval=((newval&0x70)>>4)*10+(newval&0x0f);//将bcd码转换成十进制
if(flag)//判断是加一还是减一
{
newval++;
switch(s1num)
{case1:
if(newval>99)newval=0;
DisplayYear(newval);
break;
case2:
if(newval>12)newval=1;
DisplayMonth(newval);
break;
case3:
if(newval>31)newval=1;
DisplayDay(newval);
break;
case4:
if(newval>6)newval=0;
DisplayWeek(newval);
break;
case5:
if(newval>23)newval=0;
DisplayHour(newval);
break;
case6:
if(newval>59)newval=0;
DisplayMinute(newval);
break;
case7:
if(newval>59)newval=0;
DisplaySecond(newval);
break;
default:
break;
}
}
else
{
newval--;
switch(s1num)
{case1:
if(newval==0)newval=99;
DisplayYear(newval);
break;
case2:
if(newval==0)newval=12;
DisplayMonth(newval);
break;
case3:
if(newval==0)newval=31;
DisplayDay(newval);
break;
case4:
if(newval<0)newval=6;
DisplayWeek(newval);
break;
case5:
if(newval<0)newval=23;
DisplayHour(newval);
break;
case6:
if(newval<0)newval=59;
DisplayMinute(newval);
break;
case7:
if(newval<0)newval=59;
DisplaySecond(newval);
break;
default:
break;
}
}
WriteSet1302((newaddr-1),((newval/10)<<4)|(newval%10));//将新数据写入寄存器
}
//键盘扫描程序
//*******************************************
voidkey_scan(void)
{ucharmiao,s1num=0;
if(menu==0)
{
delay(5);
if(menu==0)
{
while(!
menu);
s1num++;
while
(1)
{
if(menu==0)
{
delay(5);
if(menu==0)
{
while(!
menu);
s1num++;
}
}
rd=0;
miao=ReadSet1302(0x81);
second=miao;
WriteSet1302(0x80,miao|0x80);
write_com(0x0f);//光标闪射
if(s1num==1)
{year=ReadSet1302(0x8d);
write_com(0x80+4);//年光标
if(add==0)
{
delay(3);
if(add==0)
{while(!
add);
turn_val(year,1,0x8d,1);
}
}
if(dec==0)
{
delay(3);
if(dec==0)
{while(!
dec);
turn_val(year,0,0x8d,1);
}
}
}
if(s1num==2)
{
month=ReadSet1302(0x89);
write_com(0x80+7);//月光标
if(add==0)
{
delay(3);
if(add==0)
{while(!
add);
turn_val(month,1,0x89,2);
}
}
if(dec==0)
{
delay(3);
if(dec==0)
{while(!
dec);
turn_val(month,0,0x89,2);
}
}
}
if(s1num==3)
{day=ReadSet1302(0x87);
write_com(0x80+10);//日光标
if(add==0)
{
delay(3);
if(add==0)
{while(!
add);
turn_val(day,1,0x87,3);
}
}
if(dec==0)
{
delay(3);
if(dec==0)
{while(!
dec);
turn_val(day,0,0x87,3);//写入日寄存器
}
}
}
if(s1num==4)
{week=ReadSet1302(0x8b);
write_com(0x80+14);//星期光标
if(add==0)
{
delay(3);
if(add==0)
{while(!
add);
turn_val(week,1,0x8b,4);
}
}
if(dec==0)
{
delay(3);
if(dec==0)
{while(!
dec);
turn_val(week,0,0x8b,4);
}
}
}
if(s1num==5)
{hour=ReadSet1302(0x85);
write_com(0x80+0x40+3);//时光标
if(add==0)
{
delay(3);
if(add==0)
{while(!
add);
turn_val(hour,1,0x85,5);
}
}
if(dec==0)
{
delay(3);
if(dec==0)
{while(!
dec);
turn_val(hour,0,0x85,5);
}
}
}
if(s1num==6)//调时间分
{minute=ReadSet1302(0x83);
write_com(0x80+0x40+6);
if(add==0)
{
delay(5);
if(add==0)
{while(!
add);
turn_val(minute,1,0x83,6);//写入分寄存器
}
}
if(dec==0)
{
delay(3);
if(dec==0)
{while(!
dec);
turn_val(minute,0,0x83,6);//写入分寄存器
}
}
}
if(s1num==7)//调时间秒
{second=ReadSet1302(0x81);
write_com(0x80+0x40+9);//秒光标
if(add==0)
{
delay(3);
if(add==0)
{while(!
add);
if(second==0x60)
second=0x00;
turn_val(second,1,0x81,7);
}
}
if(dec==0)
{
delay(3);
if(dec==0)
{while(!
dec);
turn_val(second,0,0x81,7);
}
}
}