基于单片机的多功能电子钟设计Proteus仿真程序.docx
《基于单片机的多功能电子钟设计Proteus仿真程序.docx》由会员分享,可在线阅读,更多相关《基于单片机的多功能电子钟设计Proteus仿真程序.docx(24页珍藏版)》请在冰点文库上搜索。
基于单片机的多功能电子钟设计Proteus仿真程序
#include
#defineucharunsignedchar
#defineuintunsignedint
#definelcddataP0
#definereadalarmsecond0xc7 //定义从DS1302中读闹钟秒值的命令字节.
#definewritealarmsecond0xc6 //定义往DS1302中写闹钟秒值的命令字节.
#definereadalarmminute0xc5 //定义从DS1302中读闹钟分值的命令字节.
#definewritealarmminute0xc4 //定义往DS1302中写闹钟分值的命令字节.
#definereadalarmhour0xc3 //定义从DS1302中读闹钟小时值的命令字节.
#definewritealarmhour0xc2 //定义往DS1302中写闹钟小时值的命令字节.
sbitlcdrs=P2^0; //LCD数据/命令选择端(H/L)
sbitlcdrw=P2^1; //LCD读/写选择端(H/L)
sbitlcden=P2^2; //LCD使能控制
sbitDQ=P3^4;
sbitbeep=P2^3; //蜂鸣器控制端
sbitkmenu=P3^0; //功能键
sbitkup=P3^1; //增大键
sbitkdown=P3^2; //减小键
sbitkalarm=P3^3; //闹钟查看键
sbitdsclk=P1^1; //ds1302的时钟信号端
sbitdsdata=P1^0; //ds1302的数据I/O端
sbitdsrst=P1^2; //ds1302的复位端
sbitACC7=ACC^7; //定义累加器的最高和最低位。
sbitACC0=ACC^0;
bitflagalarm,flagseta,flagset;//分别定义闹钟响标志位,闹钟设置标志位,
//和时间设置标志位.
ucharkmenunum,s,m,h; //功能键被按次数的计数器.
charsecond,minute,hour,year,month,day,week;
ucharinittime[7]={0x00,0x00,0x16,0x01,0x05,0x07,0x11}; //初始化后设置为:
//11年5月1日星期日,16点0分0秒,
//从左往右的数据依次是,秒,分,时,日,月,星期,年。
ucharcodet1[]="20 - - "; //液晶固定显示部分。
ucharcodet2[]=" :
:
";
ucharcodet3[]="CLOCKALARM:
";
//各函数声明.
voiddelay(uintz); //毫秒级延时函数。
voiddi(); //蜂鸣器发声函数。
voidwritecom(ucharcom); //液晶写命令函数。
voidwritedata(uchardat); //液晶写数据函数。
voidwritetime(ucharadd,chardat);//液晶刷新时分秒。
voidwritenyr(ucharadd,chardat);//液晶刷新日期。
voidwriteweek(charweek);//液晶星期几显示函数。
voidkeyscan();//键盘扫描函数。
voiddswritebyte(uchard);//往DS1302写入一个字节。
uchardsreadbyte();//从DS1302读出一个字节。
voiddswrite(ucharadd,uchardat);//向DS1302的指定地址写入一个字节。
uchardsread(ucharadd); //从DS1302的指定地址读出一个字节.
voidinit1302time(uchar*pClock);//DS1302时间初始化函数.
voidinit(); //初始化函数。
ds18b20_delay(ucharxus); //延时xus
voidwrite_onechar(uchardat); //向18B20写一字节
ucharread_onechar(); //从18B20读一字节
uintread_wendu(); //DS18B20读温度
voidwendu_desplay(uintdat);//温度值送液晶显示函数
voiddelay(uintz) //毫秒级延时函数。
{
uintx,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
ds18b20_delay(ucharxus) //延时xus
{
while(xus--);
}
/**********************ds18b20***********************/
voidds18b20_init() //DS18B20初始化
{
ucharx=0;
DQ=1;
ds18b20_delay(8);
DQ=0;
ds18b20_delay(80);
DQ=1;
ds18b20_delay(14);
x=DQ;
ds18b20_delay(20);
}
voidwrite_onechar(uchardat) //写一字节
{
uchari;
for(i=8;i>0;i--)
{
DQ=0;
if(dat&0x01==0x01)
DQ=1;
else
DQ=0;
ds18b20_delay(5);
DQ=1;
ds18b20_delay
(1);
dat>>=1;
}
}
ucharread_onechar() //读一字节
{
ucharvalue=0,i;
for(i=8;i>0;i--)
{
value>>=1;
DQ=0;
ds18b20_delay
(1);
DQ=1;
if(DQ==1)
value|=0x80;
else
value&=0x7f;
ds18b20_delay(4);
}
returnvalue;
}
uintread_wendu() //DS18B20读温度
{
uchara=0,b=0;
uintwen=0x0000;
ds18b20_init(); //初始化
write_onechar(0xcc); //跳过读序号列号的操作
write_onechar(0x44); //启动温度转换
ds18b20_delay(150);
ds18b20_init(); //初始化
write_onechar(0xcc); //跳过读序号列号的操作
write_onechar(0xbe); //读取温度寄存器等(共可读9个寄存器)前两个就是温度
ds18b20_delay(150);
b=read_onechar(); //读取温度值低位
a=read_onechar(); //读取温度值高位
wen=a;
wen=(wen<<8)|b;
returnwen;
}
voidwendu_desplay(uintdat) //温度转换后送显示
{
floattemp;
unsignedchartemp_shi,temp_ge,temp_shu;
temp=dat*0.625; //dat*0.0625*10
temp_shi=temp/100; //取十位 temp除不用定义类型
temp_ge=((uint)temp)%100/10;//取个位 temp求模要定义类型,为16位,故定义uint
temp_shu=((uint)temp)%100%10;//取小数
writecom(0x80+0x40+10); //送显示
writedata(0x30+temp_shi);
writedata(0x30+temp_ge);
writedata(0x2e);
writedata(0x30+temp_shu);
writedata(0xdf); //温度符号
writedata(0x43);
}
voiddi() //蜂鸣器发声函数。
{
beep=0;
delay(100);
beep=1;
}
voidwritecom(ucharcom) //液晶写命令函数。
{
lcden=0;
lcdrw=0;
lcdrs=0;
lcddata=com;
delay(3);
lcden=1;
delay(3);
lcden=0;
}
voidwritedata(uchardat) //液晶写数据函数。
{
lcden=0;
lcdrw=0;
lcdrs=1;
lcddata=dat;
delay(3);
lcden=1;
delay(3);
lcden=0;
}
voidwritetime(ucharadd,chardat)//液晶刷新时分秒。
{ //0为时的开始位置,3为分,6为秒。
charshi,ge;
shi=dat/10;
ge=dat%10;
writecom(0x80+0x40+add);
writedata(0x30+shi);
writedata(0x30+ge);
}
voidwritenyr(ucharadd,chardat)//液晶刷新日期。
{ //2为年,5为月,8为日。
charshi,ge;
shi=dat/10;
ge=dat%10;
writecom(0x80+add);
writedata(0x30+shi);
writedata(0x30+ge);
}
voidwriteweek(charweek)//液晶星期几显示函数。
{
writecom(0x80+12);
switch(week)
{
case1:
writedata('M');delay(5);
writedata('O');delay(5);
writedata('N');
break;
case2:
writedata('T');delay(5);
writedata('U');delay(5);
writedata('E');
break;
case3:
writedata('W');delay(5);
writedata('E');delay(5);
writedata('D');
break;
case4:
writedata('T');delay(5);
writedata('H');delay(5);
writedata('U');
break;
case5:
writedata('F');delay(5);
writedata('R');delay(5);
writedata('I');
break;
case6:
writedata('S');delay(5);
writedata('A');delay(5);
writedata('T');
break;
case7:
writedata('S');delay(5);
writedata('U');delay(5);
writedata('N');
break;
}
}
voidkeyscan()//键盘扫描函数。
{
uchari;
if(flagalarm==1)//如果闹钟在响,任意键停止闹钟响。
{
if((kmenu==0)||(kup==0)||(kdown==0)||(kalarm==0))
{
delay(4);
if((kmenu==0)||(kup==0)||(kdown==0)||(kalarm==0))
{
while(!
(kmenu&&kup&&kdown&&kalarm));
di();
flagalarm=0;//清除闹钟标志。
}
}
}
if(kmenu==0) //检测功能键。
{
delay(4);
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+7);//秒闪烁。
writecom(0x0f);//开光标闪烁。
break;
case2:
writecom(0x80+0x40+4);//分闪烁。
break;
case3:
writecom(0x80+0x40+1);//时闪烁。
break;
case4:
writecom(0x80+12); //星期闪烁.
break;
case5:
writecom(0x80+9); //日闪烁.
break;
case6:
writecom(0x80+6); //月闪烁.
break;
case7:
writecom(0x80+3); //年闪烁.
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
(2);
if(kup==0)
{
while(!
kup);
di();
switch(kmenunum) //根据功能键被按下的次数,调节相应数值。
{
case1:
second++;
if(second==60)
second=0;
writetime(7,second);
writecom(0x80+0x40+7);//因为,上面送液晶显示
break; //一次,光标后移一位,所以要将光标复位.
case2:
minute++;
if(minute==60)
minute=0;
writetime(4,minute);
writecom(0x80+0x40+4);
break;
case3:
hour++;
if(hour==24)
hour=0;
writetime(1,hour);
writecom(0x80+0x40+1);
break;
case4:
week++;
if(week==8)
week=1;
writeweek(week);
writecom(0x80+12);
break;
case5:
day++;
if(day==32)
day=1;
writenyr(9,day);
writecom(0x80+9);
break;
case6:
month++;
if(month==13)
month=1;
writenyr(6,month);
writecom(0x80+6);
break;
case7:
year++;
if(year==100)
year=0;
writenyr(3,year);
writecom(0x80+3);
break;
}
}
}
if(kdown==0)
{
delay
(2);
if(kdown==0)
{
while(!
kdown);
di();
switch(kmenunum) //根据功能键被按次数调节相应数值.
{
case1:
second--;
if(second==-1)
second=59;
writetime(7,second);
writecom(0x80+0x40+7);
break;
case2:
minute--;
if(minute==-1)
minute=59;
writetime(4,minute);
writecom(0x80+0x40+4);
break;
case3:
hour--;
if(hour==-1)
hour=23;
writetime(1,hour);
writecom(0x80+0x40+1);
break;
case4:
week--;
if(week==0)
week=7;
writeweek(week);
writecom(0x80+12);
break;
case5:
day--;
if(day==0)
day=31;
writenyr(9,day);
writecom(0x80+9);
break;
case6:
month--;
if(month==0)
month=12;
writenyr(6,month);
writecom(0x80+6);
break;
case7:
year--;
if(year==-1)
year=99;
writenyr(3,year);
writecom(0x80+3);
break;
}
}
}
}
if(kalarm==0)//检测闹钟调节键是否按下,此条if语句与if(kmenunum!
=0)
{ //在同一个层次。
delay
(2);
if(kalarm==0)
{
flagseta=~flagseta;
while(!
kalarm);
di();
if(flagseta==0) //此时,退出闹钟设置,保存各相关数值。
{
flagset=0;//清除时间设置标志,在if(kalarm==0)这个if语句
writecom(0x80+0x40);//中,不用flagset=1这条语句来设置
//flagset标志位,因为,如果进行了闹钟时间的设置
//,就会执行前面if(kmenunum==0)语句中的flagset=1这条语句。
writedata('');//清除液晶上的“Ri”闹钟调节标志。
//writedata('');
/*for(i=0;i<13;i++)
{
writedata(t3[i]);
}*/
writecom(0x0c); //取消光标闪烁。
dswrite(0x8e,0x00); /*允许写操作*/
dswrite(writealarmsecond,second/10*16+second%10);//往DS1302中保存闹钟的时分秒值。
dswrite(writealarmminute,minute/10*16+minute%10);
dswrite(writealarmhour,hour/10*16+hour%10);
dswrite(0x8e,0x80); /*禁止写操作*/
}
else //进入闹钟设置。
{
s=dsread(readalarmsecond)/16*10+dsread(readalarmsecond)%16; //读取DS1302中闹钟的原始时间,转化为十进制数存进s,m,h保存,用以后面判断闹钟时间是否到达。
m=dsread(readalarmminute)/16*10+dsread(readalarmminute)%16;
h=dsread(readalarmhour)/16*10+dsread(readalarmhour)%16;
second=s; //把闹钟时间的十进制数据传送给变量second,minute,hour,用以调节其值。
minute=m;
hour=h;
writecom(0x80+0x40);
writedata('C');//液晶显示闹钟调节标志。
//writedata('L');
writecom(0x80+0x40+3);
writetime(1,hour);//送液晶显示闹钟时间。
writetime(4,minute);
writetime(7,second);
}
}
}
}
voiddswritebyte(uchard)//往DS1302写入一个字节。
{
uchari;
ACC=d;
for(i=8;i>0;i--)
{
dsdata=ACC0;
dsclk=1; //为什么这里时钟先为1后为0,因为dsclk初始化为0,而,每次循环最后,都将其置0,这样就形成一个从0开始的上升沿,恰好满足ds1302写数据在上升沿,但是,时钟必须从0开始的要求.
dsclk=0;
ACC=ACC>>1;
}
}
uchardsreadbyte()//从DS1302读出一个