基于DS1302的多功能数字钟.docx
《基于DS1302的多功能数字钟.docx》由会员分享,可在线阅读,更多相关《基于DS1302的多功能数字钟.docx(19页珍藏版)》请在冰豆网上搜索。
基于DS1302的多功能数字钟
多功能数字钟
一、多功能数字钟硬件电路简介
该数字钟是一款基于STC89C52单片机控制的多功能数字钟,利用串行时钟芯片DS1302进行精确计时,并有纽扣电池作为其备用电源,保证在单片机系统掉电后,时间依然准确无误。
使用LED数码管作为显示器件,设计简单可靠,外观显示效果清晰明了,使用两片74LS373作为数码管的驱动电路,保证LED数码管的亮度很高,即使在室外强光条件下,显示依然清晰。
该数字钟的声光提示部分,使用了一路继电器控制蜂鸣器和一个高亮度LED,蜂鸣器的驱动方波来源于一个555定时器芯片,并由一个可调电阻来根据需要,调节方波频率。
作息时间或定时闹钟时间到后,可以产生清晰明了的声光提示,并采用了反射式红外发送接收传感器,以实现非接触止闹,通过调试,传感距离可达10cm左右,效果明显,使用方便。
二、多功能数字钟功能简介
该数字钟具有时间,日期,星期显示和调节功能,操作简单可靠,按键都采用了防抖动程序,以防按一次造成多次输入。
该数字钟可对预设的18个作息时间点进行准确声光提示,提示时间为10秒,在该声光提示期间,将手放在电路板上方(与电路板的距离不能大于15cm),可实现非接触止闹,使用相当方便。
该数字钟还带有一个定时闹钟,可以自定闹钟时间与闹钟开关。
该数字钟具有断电时间保护功能,当单片机系统掉电后,纽扣电池可以保持至少两个月的准确时间,一般来说,数字钟的时间设置一次后,以后几乎不用再次设置。
三、多功能数字钟硬件电路图
1、非接触止闹部分
ST178实物图
ST178属于反射式红外传感器,它由一个红外发射管和一个红外三极管组成,工作的时候,红外发射管发射红外线,当它前方一定范围内有障碍物的时候,发射出的红外线遇到障碍物发射回去,被红外三极管接受,红外三极管由断开变为导通,P32端口上的电压变为低电平,从而被单片机检测到。
其中电阻R1作为限流电阻,如果不用限流电阻,ST178会在瞬间被烧毁。
电阻R2作为上拉电阻,其电阻值大小直接决定该传感器的检测范围,其值越小,检测范围越小。
2、串口时钟芯片部分
DS1302实物图
DS1302简介
DS1302是美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周日、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.5V~5.5V。
采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM数据。
DS1302内部有一个31×8的用于临时性存放数据的RAM寄存器。
DS1302是DS1202的升级产品,与DS1202兼容,但增加了主电源/后背电源双电源引脚,同时提供了对后背电源进行涓细电流充电的能力。
DS1302的引脚排列,其中Vcc1为后备电源,VCC2为主电源。
在主电源关闭的情况下,也能保持时钟的连续运行。
DS1302由Vcc1或Vcc2两者中的较大者供电。
当Vcc2大于Vcc1+0.2V时,Vcc2给DS1302供电。
当Vcc2小于Vcc1时,DS1302由Vcc1供电。
X1和X2是振荡源,外接32.768kHz晶振。
RST是复位/片选线,通过把RST输入驱动置高电平来启动所有的数据传送。
RST输入有两种功能:
首先,RST接通控制逻辑,允许地址/命令序列送入移位寄存器;其次,RST提供终止单字节或多字节数据的传送手段。
当RST为高电平时,所有的数据传送被初始化,允许对DS1302进行操作。
如果在传送过程中RST置为低电平,则会终止此次数据传送,I/O引脚变为高阻态。
上电运行时,在Vcc>2.0V之前,RST必须保持低电平。
只有在SCLK为低电平时,才能将RST置为高电平。
3、声光提示部分
555定时器简介
555定时器成本低,性能可靠,只需要外接几个电阻、电容,就可以实现多谐振荡器、单稳态触发器及施密特触发器等脉冲产生与变换电路。
它也常作为定时器广泛应用于仪器仪表、家用电器、电子测量及自动控制等方面。
555定时器的内部电路框图和外引脚排列图分别如图2.9.1和图2.9.2所示。
它内部包括两个电压比较器,三个等值串联电阻,一个RS触发器,一个放电管T及功率输出级。
它提供两个基准电压VCC/3和2VCC/3
555定时器的功能主要由两个比较器决定。
两个比较器的输出电压控制RS触发器和放电管的状态。
在电源与地之间加上电压,当5脚悬空时,则电压比较器C1的同相输入端的电压为2VCC/3,C2的反相输入端的电压为VCC/3。
若触发输入端TR的电压小于VCC/3,则比较器C2的输出为0,可使RS触发器置1,使输出端OUT=1。
如果阈值输入端TH的电压大于2VCC/3,同时TR端的电压大于VCC/3,则C1的输出为0,C2的输出为1,可将RS触发器置0,使输出为0电平。
P34端口用于单片机控制响铃方式,可以根据个人喜好,用软件实现不同的响铃方式,P33用于控制继电器的断开与闭合,该电路中由于使用的继电器的驱动电流比较大,故采用两级放大以实现对继电器的控制。
其中的可调电阻用于调节蜂鸣器的发生声频率调节。
4、主电路部分
该数字钟是以STC89C52单片机为核心控制器件,用来读取DS1302芯片的信息,处理数码管显示控制,处理按键等重要工作。
为了保证数码管的亮度足够,采用了两片74LS373作为驱动电路。
该电路中设计了四个按键开关,用于对数字钟进行调整、设定。
复位电路采用比较常见的上电复位方式,简单可靠。
单片机采用的是24M晶振,这样会使单片机的运算速度较快,即使单片机任务很多的时候,也能够对数码管进行快速扫描,不会出现闪烁的情况。
四、程序控制部分
#include
unsignedcharcodeseg[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
unsignedcharconstdofly[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x40,//0——F
0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef,0xf7,0xfc,0xb9,0xde,0xf9,0xf1,0x40};//带小数点0——F
charyear,mon,day,hour,min,sec,week;
unsignedintms50=0;
unsignedchargn=0;
unsignedcharzuoxi[]={7,50,8,0,8,50,9,0,9,50,10,10,11,0,11,10,12,0,13,30,14,20,14,30,15,20,15,30,16,20,16,30,17,20};//作息时间表
biton_off=1;
charnao[]={12,0,61};
sbitSCK=P3^7;
sbitIO=P3^6;
sbitRST=P3^5;
sbitspeaker=P3^4;
sbitJ=P3^3;
sbitIR=P3^2;
sbitkey1=P1^0;
sbitkey2=P1^1;
sbitkey3=P1^2;
sbitkey4=P1^3;
/*向DS1302写入一字节数据*/
delay(intt)
{
inti,j;
for(i=0;ifor(j=0;j<120;j++)
;
}
voidtime(unsignedcharh,unsignedcharm,unsignedchars,unsignedcharn)
{unsignedcharb[8],i;
b[0]=h/10;
b[1]=h%10;
b[2]=16;
b[3]=m/10;
b[4]=m%10;
b[5]=16;
b[6]=s/10;
b[7]=s%10;
if(s==61)
{b[6]=16;b[7]=12;}
elseif(s==62)
{b[6]=16;b[7]=0;}
switch(n)
{
case1:
b[0]+=17;b[1]+=17;break;
case2:
b[3]+=17;b[4]+=17;break;
case3:
b[6]+=17;b[7]+=17;break;
default:
;
}
for(i=0;i<8;i++)
{
P0=dofly[b[i]];//取显示数据,段码
P2=seg[i];//取位码
delay
(2);
}
P2=0xff;
}
voidds1302_write_byte(unsignedcharaddr,unsignedchard){
unsignedchari;
RST=1;/*启动DS1302总线*/
/*写入目标地址:
addr*/
addr=addr&0xFE;/*最低位置零*/
for(i=0;i<8;i++){
if(addr&0x01){
IO=1;
}
else{
IO=0;
}
SCK=1;
SCK=0;
addr=addr>>1;
}
/*写入数据:
d*/
d=d/10*16+d%10;
for(i=0;i<8;i++)
{
if(d&0x01){
IO=1;
}
else{
IO=0;
}
SCK=1;
SCK=0;
d=d>>1;
}
RST=0;/*停止DS1302总线*/
}
/*从DS1302读出一字节数据*/
unsignedchards1302_read_byte(unsignedcharaddr){
unsignedchari;
unsignedchartemp;
RST=1;/*启动DS1302总线*/
/*写入目标地址:
addr*/
for(i=0;i<8;i++){
if(addr&0x01){
IO=1;
}
else{
IO=0;
}
SCK=1;
SCK=0;
addr=addr>>1;
}
/*输出数据:
temp*/
for(i=0;i<8;i++){
temp=temp>>1;
if(IO){
temp|=0x80;
}
else{
temp&=0x7F;
}
SCK=1;
SCK=0;
}
RST=0;/*停止DS1302总线*/
temp=temp/16*10+temp%16;
returntemp;
}
/*向DS302写入时钟数据*/
ds1302_write_time(unsignedcharyear,mon,day,hour,min,sec,week)
{
ds1302_write_byte(0x8e,0x00);//关闭写保护
ds1302_write_byte(0x80,0x80);//暂停
ds1302_write_byte(0x90,0xa9);//涓流充电
ds1302_write_byte(0x8c,year);//年
ds1302_write_byte(0x8a,week);//周
ds1302_write_byte(0x88,mon);//月
ds1302_write_byte(0x86,day);//日
ds1302_write_byte(0x84,hour);//时
ds1302_write_byte(0x82,min);//分
ds1302_write_byte(0x80,sec);//秒
ds1302_write_byte(0x8e,0x80);//打开写保护
}
/*从DS302读出时钟数据*/
voidds1302_read_time(void)
{
year=ds1302_read_byte(0x8d);//年
week=ds1302_read_byte(0x8b);//周
mon=ds1302_read_byte(0x89);//月
day=ds1302_read_byte(0x87);//日
hour=ds1302_read_byte(0x85);//时
min=ds1302_read_byte(0x83);//分
sec=ds1302_read_byte(0x81);//秒
}
/*DS302初始化函数*/
voidds1302_init(void)
{
RST=0;/*RST脚置低*/
SCK=0;/*SCK脚置低*/
}
//显示部分
voiddisplay()
{
if((key4==0&&gn==0)||(gn>=20&&gn<24))
{ds1302_read_time();
time(mon,day,week,gn%10);
}
elseif(gn>=30&&gn<39)
{ds1302_read_time();
time(nao[0],nao[1],nao[2],gn%10);
}
elseif(gn>=10&&gn<20)
{
time(hour,min,sec,gn%10);
}
else
{ds1302_read_time();
time(hour,min,sec,gn%10);
}
}
//按键防抖动
voidshake()
{
unsignedchari;
for(i=0;i<25;i++)
display();
}
voidmain()
{
unsignedchari;
TH0=0x3c;TL0=0x10;
TH1=0x3c;TL1=0xb0;
TMOD=0x11;
ET0=1;
TR0=1;TR1=1;
EA=1;
ds1302_init();
J=0;
if(key1==0)
ds1302_write_time(11,1,1,12,0,0,1);
while
(1)
{
display();
//作息闹铃开关控制装置
if(key3==0&&key4==0)
{for(i=0;i<50;i++)
display();
while(key3==0&&key4==0){display();J=!
on_off;}
J=0;
on_off=!
on_off;
}
//调整前期处理
if(key1==0)
{
shake();
gn=gn+10-gn%10;
}
if(key2==0&&gn>=10)
{
shake();
gn++;
if((gn%10)>3)gn=gn/10*10+1;
}
//小时调整
if(key3==0&&gn==11)
{
shake();
hour++;
if(hour>23)hour=0;
ds1302_write_time(year,mon,day,hour,min,sec,week);
}
if(key4==0&&gn==11)
{
shake();
hour--;
if(hour<0)hour=23;
ds1302_write_time(year,mon,day,hour,min,sec,week);
}
//分钟调整
if(key3==0&&gn==12)
{
shake();
min++;
if(min>59)min=0;
ds1302_write_time(year,mon,day,hour,min,sec,week);
}
if(key4==0&&gn==12)
{
shake();
min--;
if(min<0)min=59;
ds1302_write_time(year,mon,day,hour,min,sec,week);
}
//秒调整
if(key3==0&&gn==13)
{
shake();
sec+=10;
if(sec>59)sec=0;
ds1302_write_time(year,mon,day,hour,min,sec,week);
}
if(key4==0&&gn==13)
{
shake();
sec-=10;
if(sec<0)sec=59;
ds1302_write_time(year,mon,day,hour,min,sec,week);
}
//月份调整
if(key3==0&&gn==21)
{
shake();
mon++;
if(mon>12)mon=1;
ds1302_write_time(year,mon,day,hour,min,sec,week);
}
if(key4==0&&gn==21)
{
shake();
mon--;
if(mon<1)mon=12;
ds1302_write_time(year,mon,day,hour,min,sec,week);
}
//日期调整
if(key3==0&&gn==22)
{
shake();
day++;
if(day>31)day=1;
ds1302_write_time(year,mon,day,hour,min,sec,week);
}
if(key4==0&&gn==22)
{
shake();
day--;
if(day<1)day=31;
ds1302_write_time(year,mon,day,hour,min,sec,week);
}
//星期调整
if(key3==0&&gn==23)
{
shake();
week++;
if(week>7)week=1;
ds1302_write_time(year,mon,day,hour,min,sec,week);
}
if(key4==0&&gn==23)
{
shake();
week--;
if(week<1)week=7;
ds1302_write_time(year,mon,day,hour,min,sec,week);
}
//定时闹铃小时调整
if(key3==0&&gn==31)
{
shake();
nao[0]++;
if(nao[0]>23)nao[0]=0;
}
if(key4==0&&gn==31)
{
shake();
nao[0]--;
if(nao[0]<0)nao[0]=23;
}
//定时闹铃分钟调整
if(key3==0&&gn==32)
{
shake();
nao[1]++;
if(nao[1]>59)nao[1]=0;
}
if(key4==0&&gn==32)
{
shake();
nao[1]--;
if(nao[1]<0)nao[1]=59;
}
//定时闹铃开关调整
if(key3==0&&gn==33)
{
shake();
nao[2]++;
if(nao[2]>62)nao[2]=61;
}
if(key4==0&&gn==33)
{
shake();
nao[2]--;
if(nao[2]<61)nao[2]=62;
}
//返回
if(gn>39)
gn=0;
//作息打铃
for(i=0;i<18;i++)
{
if((zuoxi[i*2]==hour&&zuoxi[i*2+1]==min&&on_off==1)||(nao[0]==hour&&nao[1]==min&&nao[2]==62))
J=1;
if(sec>10)
{J=0;ET0=1;}
if(IR==0)
{ET0=0;speaker=0;}//
}
}
}
voidbell()interrupt1
{
ET0=0;TR0=0;TH0=0x3c;TL0=0xb0;TR0=1;
ms50++;
if(ms50==1)speaker=1;
if(ms50==10)speaker=0;
if(ms50==20)speaker=1;
if(ms50==25)speaker=0;
if(ms50==30)speaker=1;
if(ms50==35)speaker=0;
if(ms50==45)ms50=0;
ET0=1;
}
//备用
voidshow()interrupt3
{
ET1=0;TR1=0;TH1=0x3c;TL1=0xb0;TR1=1;
ET1=1;
}