基于单片机的电子时钟设计.docx
《基于单片机的电子时钟设计.docx》由会员分享,可在线阅读,更多相关《基于单片机的电子时钟设计.docx(22页珍藏版)》请在冰豆网上搜索。
![基于单片机的电子时钟设计.docx](https://file1.bdocx.com/fileroot1/2022-10/28/80421e50-ca8e-4a76-b77f-16f7c571f0a0/80421e50-ca8e-4a76-b77f-16f7c571f0a01.gif)
基于单片机的电子时钟设计
程序概述
DS1302时钟芯片具有通电自动计时的功能。
向DS1302中写入一个初值,如写入2011-05-0100:
00:
00星期日,在通电时,时间就会自动走:
过60秒分加1;过60分时加1;过24小时天加1,星期日变成星期一;一周有7天,芯片内的周信息每7天一循环;芯片能够自动判断每月有多少天,5月有31天,31天后,月加1。
采用DS1302时钟芯片的单片机时钟,其实质就是读取时钟芯片内的时钟信息并把它显示出来。
只要时间初值正确,时钟就能一直精准的走下去。
调整时间日期,实质就是向DS1302时钟芯片重新写入初值。
电子时钟的主程序框图如图10所示
图4.1主程序框图
4.2延时函数
voiddelay(uintz)
{
uintx,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
由for循环构成的延时函数,z的取值为这个函数的延时ms数,如delay(200);大约延时200ms.delay(500);大约延时500ms。
因下文多次用到,固在此先作说明。
4.3对DS1302读写操作函数
在对DS1302时钟芯片操作前,应对其操作时序有所了解,参看前文DS1302介绍。
DS1302采用串行方式与单片机进行通信,一个机器周期只能读写一个字节的一位,因此,在单片机与DS1302芯片间传输一字节(8位)数据,要分8次进行,且先从低位开始传输。
4.3.1向DS1302写数据
/***************************写数据字节子函数**************************/
voidwrite_1302_byte(uchartemp)//用来发送8位数据信息
{
uchari;
for(i=0;i<8;i++)//循环8次写入数据
{
sck=0;
sda=temp&0x01;//每次传输低字节
temp>>=1;//右移一位
sck=1;//在SCK上升沿的时候字节写入DS1302
}
}
/*************************1302写数据子函数**************************/
voidwrite_1302(ucharaddd,uchardat)
{
rst=0;
_nop_();
sck=0;
_nop_();
rst=1;
_nop_();
write_1302_byte(addd);//发送地址
write_1302_byte(dat);//发送数据
rst=0;
}
4.3.2从DS1302读数据
/***************************读DS1302数据函数*************************/
ucharread_1302(ucharadd)//输入地址add,返回读取的数据
{
uchari,temp=0x00;
rst=0;
sck=0;
rst=1;
write_1302_byte(add);
for(i=0;i<8;i++)//循环8次读取
{
if(sda)
temp|=0x80;//每次传输低字节,等价于temp=temp|0x80
sck=0;
temp>>=1;//右移一位
sck=1;//sck被置高,在其下一次变为0时,数据被写入
}
rst=0;//以下为DS1302复位的稳定时间
sck=0;
sck=1;
sda=0;
sda=1;
return(temp);//将temp值返回
}
4.4显示函数
对1602进行操作前要对其进行初使化,初使化完成后它才能正常显示。
如果想在1602液晶的某一个位置显示一个内容,要先对其写入一个指令:
在什么地方显示。
然后再对其写入一个数据:
要显示什么内容。
对1602的液晶初使化,需要用写入指令的方式完成。
4.4.1向1602液晶中写一个指令
voidwrite_com(ucharcom)
{
lcdwr=0;//lcdwr为读写控制端,lcdwr=0,这里可不写
lcdrs=0;//液晶rs接口为0时,写指令,rs为1时写数据
P0=com;//将要写的指令赋给P0口,
delay(5);//由1602读写操作时序图,先将指令赋给P0口,延时后将使能
lcden=1;端lcden置高,再延时一段时间,然后将lcden置低,这样指令
delay(5);就写入到LCD了
lcden=0;
}
4.4.2向液晶写数据
voidwrite_data(uchardate),与写指令类似,这里lcdrs设为1
{
lcdrs=1;
P0=date;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
4.4.3初使化1602液晶
此函数首先对液晶进行初使化,使其处于待命状态,然后将时钟框架显示出来:
年月日之间的“-”,时分秒之间的“:
”,还有世纪年的高两位。
voidinit_1602()
{
ucharnum;
lcdwr=0;
lcden=0;
write_com(0x38);//设置LCD为16*2显示、5*7点阵、8位数据接口模式
write_com(0x0c);//开显示、不显示光标
write_com(0x06);//写一个字符后,地址指针加1
write_com(0x01);//显示清0
write_com(0x80);//将指针指向初始位置
for(num=0;num<14;num++)//循环函数,用于将"20--"写入液晶
write_data(table[num]);
write_com(0x80+0x40+4);//将指针指向1602液晶的第二行,第四个字段
for(num=0;num<8;num++)//功能与上同,用于将":
:
"写入
write_data(table1[num]);
}
4.4.4如何在液晶上显示时间、日期及周
DS1302中的时间、日期等信息是以BCD码的形式存放的,要先将从1302中读取的数据转化成10进制,然后显示在液晶上相应的位置。
/***************************显示时间、日期子函数***********************/
voidwrite_sfm(ucharadd,uchartime)//用于在1602上显示年、月、日、时、分、秒。
{Add为显示位置,time为要显示的内容
ucharshi,ge;
shi=time/16;//将从DS1302中读取的BCD码数据转化成10进制个位和10
ge=time%16;进制十位
write_com(add+0x80);//定义显示在液晶的什么位置
write_data(0x30+shi);//由1602液晶字库可知,0~9的数据码分别对应0x30~0x39
write_data(0x30+ge);//初使化中设定了写一个字符后,地址指针加1,因此这里
}不用重新光标定位
/**************************显示周子函数*******************************/
voidwrite_zhou(uchartime1),用于在1602上显示周信息,与显示
{时间日期子函数类似
ucharge;
ge=time1%16;//一周七天,因此只需个位
write_com(0x80+13);
write_data(0x30+ge);
}
4.5按键函数
此电子时钟共有4个按键,S1、S2、S3与调时有关图按键程序如图11,S4为12小时切换键
S1功能键:
在24小时显示模式下,该键被第一次按下后进入秒调整,液晶显示器上的时间停止走动。
模式,再次按下后进入分调整模式,接着是调时模式、调年模式、调月模式、调日模式、调周模式,当第八次按下该键后退出
S2调整键:
在调整模式下,该键每按一次,相应时间或日期加1
S3确定键:
在调整模式下,该键被按下后,退出调整模式,并将调整后的时间、日期写入DS1302
S4显示模式调整键用于对时间的12/24小时模式的切换
图4.2按键程序图
4.5.112/24小时显示模式切换键
时钟默认在24小时模式下运行,定义一个标志位flag1。
第一次按下切换键,把瞬时时间转化成12小时制,令flag1=1。
并写入DS1302芯片,此后DS1302芯片在12小时模式下运行。
第二次按下切换键,即返回24小时显示模式,令flag1=0,把瞬时时间转化成24小时模式并写入DS1302芯片。
有关DS1302的时间寄存器存放形式参阅前文。
如24小时模式下的22:
00,存放的形式为00100010。
12小时模式下的22点,也就是10:
00PM,存放形式为10110000,在切换的一瞬间,我们只需要把小时数据0xb0写入到DS1302,这样就能让时钟芯片在12小时模式下运行了。
需要注意的是,12小时模式下,只用到后5位来表示时间,第6位用来表示AM或PM信息,如果真接用24小时模式下的显示方法是会出错的,这里我们需要对时进行转化。
首先提取AM/PM信息,让其显示。
然后提取其后5位时间,显示时间。
在主函数部分如果检测到flag1=1,就进行转换。
12转24小进模式与其类似,不再赘述。
if(s1num==0&&s4==0)//设置键没被按下,且12/24小时模式切换键被按下后
{
delay(5);
if(s4==0)
{
s2num++;
while(!
s4);
if(s2num==1)//24小时切换成12小时
{
intge,shi;
flag1=1;
hour=read_1302(0x85);
ge=hour%16;
shi=hour/16;
if(shi<=1&&ge<=1)//时小于12
{
if(shi==0&&ge==0)
hour=0x92;
else
{
hour=hour&0x9f;
hour=hour+0x80;
}
}
if(shi==1&&ge==2)//12点
{
hour=hour+0x80;
hour=hour+0x20;
}
if(shi>=1&&ge>=3&&ge<=9)//13点~19点
{
hour=hour-0x12;
hour=hour+0x80;
hour=hour+0x20;
}
if(shi==2&&ge==0)//20点
{
hour=0xa8;
}
if(shi==2&&ge==1)
hour=0xa9;
if(shi==2&&ge==2)
{
hour=0xb0;
}
if(shi==2&&ge==3)
hour=0xb1;
write_1302(0x8e,0x00);
write_1302(0x84,hour);
write_1