单片机精确时钟报告1.docx
《单片机精确时钟报告1.docx》由会员分享,可在线阅读,更多相关《单片机精确时钟报告1.docx(28页珍藏版)》请在冰豆网上搜索。
单片机精确时钟报告1
一.摘要
本作品使用STC89C52单片机作为控制核心,在学习板的基础上自行拓展了DS12C887时钟芯片以及1602液晶,蜂鸣器等器件,设计了一款具有多个功能的高精度时钟。
该系统的设计与制作是一次在对单片机基本知识及基本应用掌握基础上的对单片机系统拓展设计的进一步尝试。
二.作品功能
该作品基于SSt89C51单片机并利用液晶显示LCD1602以及DS12C887时钟芯片,通过程序控制实现了以下功能:
1.1602液晶上显示年、月、日、星期、时、分、秒,并且按秒实时更新显示。
2.具有闹铃设定及到时报警功能,报警响起时按任何键取消报警。
3.能够使用板上的按键随时调节各个参数,4个有效键,分别为功能选择键、数值增大键、数值减小键和闹钟查看键。
三工作原理
本系统的工作原理是:
单片机通过对DS12C887时钟芯片内的时间信息进行采集,并将其显示于1602液晶上实现基本时间显示功能;单片机根据用户按键输入的信号通过程序控制实现时间更新功能及闹钟、报警功能。
四.硬件部分
在学习板已有硬件模块基础上我们加入液晶显示模块、、闹钟输出模块、时钟芯片等模块。
此高精度时钟系统所包括的模块如图所示:
1.时钟芯片
DS12C887能够自动产生世纪、年、月、日、时、分、秒等时间信息;对于一天内的时间记录,有12小时制和24小时制两种模式。
在12小时制模式中,用AM和PM区分上午和下午;时间的表示方法也有两种,一种用二进制数表示,一种是用BCD码表示;DS12C887中带有128字节RAM,其中有11字节RAM
用来存储时间信息,4字节RAM用来存储DS12C887的控制信息,称为控制寄存器,113字节通用RAM使用户使用;此外用户还可对DS12C887进行编程以实现多种方波输出,并可对其内部的三路中断通过软件进行屏蔽。
2..液晶显示模块
系统中采用LCD1602作为显示器件输出信息。
与传统的LED数码管显示器件相比,液晶显示模块具有体积小、功耗低、显示内容丰富等优点,而且不需要外加驱动电路,现在液晶显示模块已经是单片机应用设计中最常用的显示器件了。
LCD1602可以显示2行16个字符,具有8位数据总线D0-D7,和RS、R/W、E三个控制端口,工作电压为5V,并且带有字符对比度调节和背光设置。
3.键盘模块
键盘在单片机系统中是一个很重要的部件。
为了输入数据、查询和控制系统的工作状态,都要用到键盘。
本实验用到键盘按键进行时间设置与调整作用
4.闹铃模块
系统采用蜂鸣器作为闹铃输出。
闹铃电路连接如图所示。
软件设计
本系统软件程序主要包括:
液晶LCD1602的底层驱动模块、定时器0定时检查系统变量模块、定时器1按键扫描模块等。
程序过程如图。
主程序是先开始,然后初始化参数设置,定时器启动后在进行按键检测,显示时间。
1主程序MAIN流程框图
否
是
图6主程序MAIN流程框图
2定时器中断流程图
程序开始进行标识位初始化,对时钟闹铃单元进行初始化,开始读取时间信息,通过读取程序,液晶显示器显示时间,当有按键按下时进行键值的处理,没有按键按下时则程序重新读取时间信息。
定时器中断时是先检测1秒是否到,1秒如果到,秒单元就加1;如果没到,就检测1分钟是否到,1分钟如果到,分单元就加1;如果没到,就检测1小时是否到,1小时如果到,时单元就加1,如果没到,就显示时间。
图4-3定时器中断流程图
3时钟调整模式:
4闹铃报时模式:
结束语
通过这次课程设计我发现,只有理论水平提高了;才能够将课本知识与实践相整合,理论知识服务于教学实践,以增强自己的动手能力。
这个实验十分有意义我获得很深刻的经验。
通过这次课程设计,我们知道了理论和实际的距离,也知道了理论和实际想结合的重要性,,也从中得知了很多书本上无法得知的知识。
我们的学习不但要立足于书本,以解决理论和实际教学中的实际问题为目的,还要以实践相结合,理论问题即实践课题,解决问题即课程研究,学生自己就是一个专家,通过自己的手来解决问题比用脑子解决问题更加深刻。
学习就应该采取理论与实践结合的方式,理论的问题,也就是实践性的课题。
这种做法既有助于完成理论知识的巩固,又有助于带动实践,解决实际问题,加强我们的动手能力和解决问题的能力。
课程设计报告
高精度时钟设计
重庆邮电大学
通信与信息工程学院
周礼(08010310)
王一可(08020301)
2010年5月30日
工作在一般时钟模式下:
工作在闹钟模式下:
【附录:
源程序】
#include
#defineucharunsignedchar
#defineuintunsignedint
sbitdula=P1^0;//段选
sbitwela=P1^1;//位选
sbitrs=P3^5;//液晶数据/命令选择
sbitlcden=P3^4;//液晶使能
sbits1=P0^0;//功能键
sbits2=P0^1;//增加键
sbits3=P0^2;//减小键
sbits4=P0^3;//闹钟查看键
sbitoe=P1^3;
sbitbeep=P1^2;//蜂鸣器
sbitdscs=P1^4;//ds时钟芯片片选
sbitdsas=P1^5;//ds地址选通输入端
sbitdsrw=P1^6;//ds读/写输入端
sbitdsds=P1^7;//ds数据选择或读输入脚
sbitdsirq=P3^3;//ds中断请求输出
bitflag1,flag_ri;//定义两个位变量
ucharcount,s1num,flag,t0_num;//变量定义
charmiao,shi,fen,year,month,day,week,amiao,afen,ashi;
ucharcodetable[]="20--";//液晶固定显示内容
ucharcodetable1[]=":
:
";
voidwrite_ds(uchar,uchar);//函数申明
voidset_alarm(uchar,uchar,uchar);
voidread_alarm();
ucharread_ds(uchar);
voidset_time();
//--------
voiddelay(uintz)
{//延时函数
uintx,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
voiddi()
{//蜂鸣器报警声音
beep=0;
delay(300);
beep=1;
}
voidwrite_com(ucharcom)
{//写液晶命令函数
rs=0;
lcden=0;
P2=0xff;
P2=com;
delay(3);
lcden=1;
delay(3);
lcden=0;
}
voidwrite_date(uchardate)
{//写液晶数据函数
rs=1;
lcden=0;
P2=0xff;
P2=date;
delay(3);
lcden=1;
delay(3);
lcden=0;
}
voidinit()
{//初始化函数
ucharnum;
EA=1;//打开总中断
EX1=1;//开外部中断1
IT1=1;//设置负跳变沿触发中断
flag1=0;//变量初始化
dula=1;
P0=0x00;
dula=0;//关闭数码管显示
wela=1;
P0=0xfe;
wela=0;
P0=0x00;
t0_num=0;
s1num=0;
week=1;
lcden=0;
oe=0;
write_com(0x38);//1602液晶初始化
write_com(0x0c);
write_com(0x06);
write_com(0x01);
write_com(0x80);
for(num=0;num<15;num++)//写入液晶固定部分显示
{
write_date(table[num]);
delay
(1);
}
write_com(0x80+0x40);
for(num=0;num<11;num++)
{
write_date(table1[num]);
delay
(1);
}
}
voidwrite_sfm(ucharadd,chardate)
{//1602液晶刷新时分秒函数4为时,7为分,10为秒
charshi,ge;
shi=date/10;
ge=date%10;
write_com(0x80+0x40+add);
write_date(0x30+shi);
write_date(0x30+ge);
}
voidwrite_nyr(ucharadd,chardate)
{//1602液晶刷新年月日函数3为年,6为分,9为秒
charshi,ge;
shi=date/10;
ge=date%10;
write_com(0x80+add);
write_date(0x30+shi);
write_date(0x30+ge);
}
voidwrite_week(charwe)
{//写液晶星期显示函数
write_com(0x80+12);
switch(we)
{
case1:
write_date('M');delay(5);
write_date('O');delay(5);
write_date('N');
break;
case2:
write_date('T');delay(5);
write_date('U');delay(5);
write_date('E');
break;
case3:
write_date('W');delay(5);
write_date('E');delay(5);
write_date('D');
break;
case4:
write_date('T');delay(5);
write_date('H');delay(5);
write_date('U');
break;
case5:
write_date('F');delay(5);
write_date('R');delay(5);
write_date('I');
break;
case6:
write_date('S');delay(5);
write_date('A');delay(5);
write_date('T');
break;
case7:
write_date('S');delay(5);
write_date('U');delay(5);
write_date('N');
break;
}
}
voidkeyscan()
{
if(flag_ri==1)
{//这里用来取消闹钟报警,任一键取消报警
if((s1==0)||(s2==0)||(s3==0)||(s4==0))
{
delay(5);
if((s1==0)||(s2==0)||(s3==0)||(s4==0))
{
while(!
(s1&&s2&&s3&&s4));
di();
flag_ri=0;//清除报警标志
}
}
}
if(s1==0)//检测S1
{
delay(5);
if(s1==0)
{
s1num++;//记录按下次数
if(flag1==1)
if(s1num==4)
s1num=1;
flag=1;
while(!
s1);di();
switch(s1num)
{//光标闪烁点定位
case1:
write_com(0x80+0x40+10);
write_com(0x0f);
break;
case2:
write_com(0x80+0x40+7);
break;
case3:
write_com(0x80+0x40+4);
break;
case4:
write_com(0x80+12);
break;
case5:
write_com(0x80+9);
break;
case6:
write_com(0x80+6);
break;
case7:
write_com(0x80+3);
break;
case8:
s1num=0;
write_com(0x0c);
flag=0;
write_ds(0,miao);
write_ds(2,fen);
write_ds(4,shi);
write_ds(6,week);
write_ds(7,day);
write_ds(8,month);
write_ds(9,year);
break;
}
}
}
if(s1num!
=0)//只有当S1按下后,才检测S2和S3
{
if(s2==0)
{
delay
(1);
if(s2==0)
{
while(!
s2);di();
switch(s1num)
{//根据功能键次数调节相应数值
case1:
miao++;
if(miao==60)
miao=0;
write_sfm(10,miao);
write_com(0x80+0x40+10);
break;
case2:
fen++;
if(fen==60)
fen=0;
write_sfm(7,fen);
write_com(0x80+0x40+7);
break;
case3:
shi++;
if(shi==24)
shi=0;
write_sfm(4,shi);
write_com(0x80+0x40+4);
break;
case4:
week++;
if(week==8)
week=1;
write_week(week);
write_com(0x80+12);
break;
case5:
day++;
if(day==32)
day=1;
write_nyr(9,day);
write_com(0x80+9);
break;
case6:
month++;
if(month==13)
month=1;
write_nyr(6,month);
write_com(0x80+6);
break;
case7:
year++;
if(year==100)
year=0;
write_nyr(3,year);
write_com(0x80+3);
break;
}
}
}
if(s3==0)
{
delay
(1);
if(s3==0)
{
while(!
s3);di();
switch(s1num)
{//根据功能键次数调节相应数值
case1:
miao--;
if(miao==-1)
miao=59;
write_sfm(10,miao);
write_com(0x80+0x40+10);
break;
case2:
fen--;
if(fen==-1)
fen=59;
write_sfm(7,fen);
write_com(0x80+0x40+7);
break;
case3:
shi--;
if(shi==-1)
shi=23;
write_sfm(4,shi);
write_com(0x80+0x40+4);
break;
case4:
week--;
if(week==0)
week=7;
write_week(week);
write_com(0x80+12);
break;
case5:
day--;
if(day==0)
day=31;
write_nyr(9,day);
write_com(0x80+9);
break;
case6:
month--;
if(month==0)
month=12;
write_nyr(6,month);
write_com(0x80+6);
break;
case7:
year--;
if(year==-1)
year=99;
write_nyr(3,year);
write_com(0x80+3);
break;
}
}
}
}
if(s4==0)//检测S4
{
delay(5);
if(s4==0)
{
flag1=~flag1;
while(!
s4);di();
if(flag1==0)
{//退出闹钟设置时保存数值
flag=0;
write_com(0x80+0x40);
write_date('');
write_date('');
write_com(0x0c);
write_ds(1,miao);
write_ds(3,fen);
write_ds(5,shi);
}
else
{//进入闹钟设置
read_alarm();//读取原始数据
miao=amiao;//重新赋值用以按键调节
fen=afen;
shi=ashi;
write_com(0x80+0x40);
write_date('R');//显示标志
write_date('i');
write_com(0x80+0x40+3);
write_sfm(4,ashi);//送液晶显示闹钟时间
write_sfm(7,afen);
write_sfm(10,amiao);
}
}
}
}
voidwrite_ds(ucharadd,uchardate)
{//写12C887函数
dscs=0;
dsas=1;
dsds=1;
dsrw=1;
P2=0xff;
P2=add;//先写地址
dsas=0;
dsrw=0;
P2=0xff;
P2=date;//再写数据
dsrw=1;
dsas=1;
dscs=1;
}
ucharread_ds(ucharadd)
{//读12C887函数
uchards_date;
dsas=1;
dsds=1;
dsrw=1;
dscs=0;
P2=0xff;
P2=add;//先写地址
dsas=0;
dsds=0;
P2=0xff;
ds_date=P2;//再读数据
dsds=1;
dsas=1;
dscs=1;
returnds_date;
}
voidread_alarm()
{//读取12C887闹钟值
amiao=read_ds
(1);
afen=read_ds(3);
ashi=read_ds(5);
}
//-----------------------------------------
voidmain()//主函数
{
init();//调用初始化函数
while
(1)
{
if(flag_ri==1)//当闹钟中断时进入这里
{
di();
delay(200);
di();
delay(500);
}
keyscan();//按键扫描
if(flag==0&&flag1==0)//正常工作时进入这里
{
keyscan();//按键扫描
year=read_ds(9);//读取12C887数据
month=read_ds(8);
day=read_ds(7);
week=read_ds(6);
shi=read_ds(4);
fen=read_ds
(2);
miao=read_ds(0);
write_sfm(10,miao);//送液晶显示
write_sfm(7,fen);
write_sfm(4,shi);
write_week(week);
write_nyr(3,year);
write_nyr(6,month);
write_nyr(9,day);
}
}
}
voidexter()interru