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时,写保护位防止对任一寄存器的写操作。
(2)LCD1302
1602采用标准的16脚接口,其中:
第1脚:
VSS为地电源
第2脚:
VDD接5V正电源
第3脚:
V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度
第4脚:
RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。
第5脚:
RW为读写信号线,高电平时进行读操作,低电平时进行写操作。
当RS和RW共同为低电平时可以写入指令或者显示地址,当RS为低电平RW为高电平时可以读忙信号,当RS为高电平RW为低电平时可以写入数据。
第6脚:
E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
第7~14脚:
D0~D7为8位双向数据线。
第15~16脚:
空脚
指令图
它的读写操作、屏幕和光标的操作都是通过指令编程来实现的。
(说明:
1为高电平、0为低电平)
指令1:
清显示,指令码01H,光标复位到地址00H位置
指令2:
光标复位,光标返回到地址00H
指令3:
光标和显示模式设置 I/D:
光标移动方向,高电平右移,低电平左移 S:
屏幕上所有文字是否左移或者右移。
高电平表示有效,低电平则无效
指令4:
显示开关控制。
D:
控制整体显示的开与关,高电平表示开显示,低电平表示关显示 C:
控制光标的开与关,高电平表示有光标,低电平表示无光标 B:
控制光标是否闪烁,高电平闪烁,低电平不闪烁
指令5:
光标或显示移位 S/C:
高电平时移动显示的文字,低电平时移动光标
指令6:
功能设置命令 DL:
高电平时为4位总线,低电平时为8位总线 N:
低电平时为单行显示,高电平时双行显示 F:
低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符
指令7:
字符发生器RAM地址设置 指令
8:
DDRAM地址设置
指令9:
读忙信号和光标地址 BF:
为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。
指令10:
写数据
指令11:
读数据
液晶显示模块是一个慢显示器件,所以在执行每条指令之前一定要确认模块的忙标志为低电平,表示不忙,否则此指令失效。
1.5.2初始值设置模块
(1)按键
四个按键,一个用于设置项的选择,一个用于数值加一,一个用于将正常显示状态切换到闹钟设置状态,另一个键用于将闹钟显示状态切换到正常显示状态。
1.5.3闹钟及其设置模块
(1)蜂鸣器
蜂鸣器要外加9012作为驱动,使其定点提醒。
1.6软件流程
1.6.1编程算法思想
程序采用模块化设计思想。
以主程序为核心设置功能模块子程序,简化了设计结构。
运行过程中通过主程序调用各功能模块子程序。
该系统的工作软件主要完成以下功能:
单片机不断读取DS1302的数值送给LCD显示,并通过按键设置时间和闹钟的初始值,达到控制时间的目的,实现智能万年历的目的。
1.6.2程序框图
主程序流程图
中断服务流程图
2.系统测试
2.1仿真调试
仿真图
通过软件仿真验证程序的正确性,并对软件程序进行优化,进而完成程序的优化。
2.2硬件焊接的检测
在电路的焊接过程中,不断检测焊接的正确性,并用万用表检测焊接点之间是否导通。
2.3总体调试
将程序下载到硬件单片机中,检测是否可用,当出现问题时,寻找和问题相关的硬件,进而一步步解决问题。
3.结论
本项目本着智能,多功能,人性化的设计理念,智能地实现了万年历的显示、设置和闹钟功能,项目达到了初定的目标。
4.附录
附1:
元器件明细表
序号
元器件名称
元器件型号
数量
1
单片机
STC89S51
1
2
时钟芯片
DS1302
1
3
显示芯片
1602
1
4
零散元件
电阻电容
5
按键
5
6
蜂鸣器
1
7
放大器
9012
1
8
变位器
103
1
附2:
电路图图纸
系统总电路原理图
附3:
程序清单
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
#defineDEC2BCD(X)((X/10)<<4|(X%10))//用于将十进制转成BCD码的宏
#defineBCD2DEC(X)(((X&0x70)>>4)*10+(X&0x0F))//用于将BCD码转成十进制的宏
voidwrite_com(ucharcom);
voidwrite_data(uchardat);
voidinit();
voidwrite_time(ucharadd,uchardat);
voidwrite_riqi(ucharadd,uchardat);
voidwrite_xingqi(uchardat);
voidwrite_byte(uchardat);
ucharread_byte();
voids_write(ucharadd,uchardat);
uchars_read(ucharadd);
voidset_ds1302(uchar*pClock);
voidrw_ds1302();
voidkeyscan();
uchardatatable[]="2009-01-01Mon.";
uchardatatable1[]="00:
00:
00";
ucharcodexingqi[]="Mon.Tue.Wed.Thu.Fri.Sat.Sun.";
ucharcodetime[]={0x00,0x00,0x00,0x01,0x01,0x01,0x09};//sec,min,hour,date,month,week,year
uchardatatime1[]={0x00,0x00,0x00,0x01,0x01,0x01,0x09};//sec,min,hour,date,month,week,year
ucharhour,min,sec,week,day,month,year,num,sfcount=0,flag;
ucharclock_sec=30,clock_min,clock_hour;
uchardisplay_flag;//0显示当前时间1显示闹钟时间
sbitds1302_sclk=P3^4;
sbitds1302_io=P3^5;
sbitds1302_ce=P3^6;
sbitacc0=ACC^0;
sbitacc7=ACC^7;
sbitlcdrs=P1^5;//端口定义
sbitlcdrw=P1^6;
sbitlcde=P1^7;
sbitbeep=P3^7;
sbitfunctionk1=P1^0;//选择设置的项
sbitsup=P1^1;//key2
sbitkey3=P1^2;//加1
sbitkey4=P1^4;
voiddelay(uinta);
voidkeyscan();
voidchoose();
voidbeepp();
voidmain()//main函数
{
s_write(0x8e,0x80);
init();
P0=0xff;
while
(1)
{
keyscan();
choose();
beepp();
if(flag==0){
rw_ds1302();
}
}
}
voidbeepp()
{
if((hour==clock_hour)&&(min==clock_min)&&(sec==clock_sec))
{
beep=0;
delay(100);
}
if((hour!
=clock_hour)||(min!
=clock_min)||(sec!
=clock_sec))
{
beep=1;
}
}
voidchoose()//控制显示的内容
{
if(key3==0)
{
delay
(2);
if(key3==0)
{
display_flag=1;
beep=1;
}
}
if(key4==0)
{
delay
(2);
if(key4==0)
{
display_flag=0;
}
}
}
voidwrite_byte(uchardat)//写入一个字节ds1302
{
uchari;
ACC=dat;
for(i=8;i>0;i--)
{
ds1302_io=acc0;
ds1302_sclk=1;
ds1302_sclk=0;
ACC=ACC>>1;
}
}
ucharread_byte()//读出一个字节ds1302
{
uchari;
for(i=8;i>0;i--)
{
ACC=ACC>>1;
acc7=ds1302_io;
ds1302_sclk=1;
ds1302_sclk=0;
}
return(ACC);
}
voids_write(ucharadd,uchardat)//单字节写入子函数ds1302写入确定地址确定内容
{
ds1302_ce=0;
ds1302_sclk=0;
ds1302_ce=1;
write_byte(add);
write_byte(dat);
ds1302_sclk=1;
ds1302_ce=0;
}
uchars_read(ucharadd)//单字节读出子函数ds1302写入地址读出数据十进制
{
uchartemp;
ds1302_ce=0;
ds1302_sclk=0;
ds1302_ce=1;
write_byte(add);
temp=read_byte();
ds1302_sclk=1;
ds1302_ce=0;
temp=BCD2DEC(temp);
return(temp);
}
voidset_ds1302(uchar*pClock)//设置ds1302的时间将时间写入1302
{
uchari;
ucharadd=0x80;
s_write(0x8e,0x00);//能够写入ds1302
for(i=7;i>0;i--)
{
s_write(add,*pClock);//将时间写入1302
pClock++;
add+=2;
}
s_write(0x8e,0x80);//禁止写入1302
}
voidrw_ds1302()//读写ds1302
{
if(display_flag==0)
{
sec=s_read(0x81);//读出秒
write_time(8,sec);//写入时间子函数add=0x80lcd
write_com(0x80+0x40+9);
min=s_read(0x83);//读出分
write_time(5,min);
write_com(0x80+0x40+6);
hour=s_read(0x85);
write_time(2,hour);
write_com(0x80+0x40+3);
week=s_read(0x8b);
write_xingqi(week);
write_com(0x80+0x0d);
day=s_read(0x87);
write_riqi(8,day);
write_com(0x80+9);
month=s_read(0x89);
write_riqi(5,month);
write_com(0x80+6);
year=s_read(0x8d);//读出年
write_riqi(2,year);
write_com(0x80+3);
}
if(display_flag==1)
{//sec=clock_sec;//读出秒
write_time(8,clock_sec);//写入时间子函数add=0x80lcd
write_com(0x80+0x40+9);
//min=clock_min;//读出分
write_time(5,clock_min);
write_com(0x80+0x40+6);
//hour=clock_hour;
write_time(2,clock_hour);
write_com(0x80+0x40+3);
week=s_read(0x8b);
write_xingqi(week);
write_com(0x80+0x0d);
day=s_read(0x87);
write_riqi(8,day);
write_com(0x80+9);
month=s_read(0x89);
write_riqi(5,month);
write_com(0x80+6);
year=s_read(0x8d);//读出年
write_riqi(2,year);
write_com(0x80+3);
}
}
voidwrite_com(ucharcom)//写命令子函数lcd
{
lcde=0;
lcdrw=0;
lcdrs=0;
delay
(1);
lcde=1;
delay
(1);
P2=com;
delay
(1);
lcde=0;
}
voidwrite_data(uchardat)//写数据子函数lcd
{
lcde=0;
lcdrw=0;
lcdrs=1;
delay
(1);
lcde=1;
delay
(1);
P2=dat;
delay
(1);
lcde=0;
}
voidinit()//LCD1602初始化
{
s_write(0x90,0xa5);
set_ds1302(time);
delay(5);
write_com(0x38);
delay(100);
write_com(0x38);//设置显示模式:
8位2行5x7点阵
delay(50);
write_com(0x38);
delay(10);
write_com(0x08);//关
write_com(0x01);//清屏
write_com(0x0c);//开0x08关
write_com(0x80);//能写
for(num=0;num<15;num++)//在第一行显示“2009-01-01Mon.”
{
write_data(table[num]);
}
write_com(0x80+0x40);
for(num=0;num<10;num++)//在第二行末尾显示“00:
00:
00”
{
write_data(table1[num]);
}
}
voidwrite_time(ucharadd,uchardat)//写入时间子函数lcd
{
ucharshi,ge;
shi=dat/10;
ge=dat%10;
write_com(0x80+0x40+add);
write_data(0x30+shi);
write_data(0x30+ge);
}
voidwrite_riqi(ucharadd,uchardat)//写入日期子函数lcd
{
uchar