基于52单片机的电子时钟课程设计.docx
《基于52单片机的电子时钟课程设计.docx》由会员分享,可在线阅读,更多相关《基于52单片机的电子时钟课程设计.docx(29页珍藏版)》请在冰豆网上搜索。
基于52单片机的电子时钟课程设计
前言
时钟,自从它发明的那天起,就成为人类的朋友,但随着时间的推移,科学技术的不断发展,人们对时间计量的精度要求越来越高,应用越来越广。
怎样让时钟更好的为人民服务,怎样让我们的老朋友焕发青春呢?
这就要求人们不断设计出新型时钟。
现今,高精度的计时工具大多数都使用了石英晶体振荡器,由于电子钟,石英表,石英钟都采用了石英技术,因此走时精度高,稳定性好,使用方便,不需要经常调校,数字式电子钟用集成电路计时,译码代替机械式传动,用LED显示器代替显示器代替指针显示进而显示时间,减小了计时误差,这种表具有时,分,秒显示时间的功能,还可以进行时和分的校对,片选的灵活性好。
时钟电路在计算机系统中起着非常重要的作用,是保证系统正常工作的基础。
在一个单片机应用系统中,时钟有两方面的含义:
一是指为保障系统正常工作的基准振荡定时信号,主要由晶振和外围电路组成,晶振频率的大小决定了单片机系统工作的快慢;二是指系统的标准定时时钟,即定时时间,它通常有两种实现方法:
一是用软件实现,即用单片机内部的可编程定时/计数器来实现,但误差很大,主要用在对时间精度要求不高的场合;二是用专门的时钟芯片实现,在对时间精度要求很高的情况下,通常采用这种方法,典型的时钟芯片有:
DS1302,DS12887,X1203等都可以满足高精度的要求。
本文主要介绍用单片机内部的定时/计数器来实现电子时钟的方法,本设计由单片机AT89S51芯片和LED数码管为核心,辅以必要的电路,构成了一个单片机电子时钟。
电子时钟作为单片机基础学习的一个重要的典型,是很多初学的学习单片机的很好的例子,是对单片机的定时器的一个重要的应用。
可以说,学习单片机的两个重点就是中断和定时器,学会了数字时钟的编程就是对单片机学习的一个很好的综合应用。
1.设计任务和要求
1.1设计要求
应用知识:
I/O口应用、数码显示、定时/计数器、中断、按键。
基本要求:
该时钟系统具有时钟功能,能准确显示时、分、秒。
系统还应具有校正功能,如准点报时,能够修改当前的时间。
扩展部分:
具备设定闹钟和定时闹钟响功能。
1.2设计思路
通过软件程序的编程,硬件电路的调试,实现了简单时钟系统的设定,使得该系统具有正常走时,能够正确的显示时、分、秒;能够进行调时,修改当前的时间,并且能够设定闹钟,使闹钟能够定时响。
首先是时间的调试:
若要进行正常的时间调试,需要有进入时间的调时试状态按键以及调试是加或者是减的按键,即每个状态要3个按键,共有时、分、秒三个状态,,可通过同一个按键来控制定时器的走与停,以及通过按键的次数来控制所进入的调试状态是时、分还是秒。
当调试进入某一状态时,需要分别通过两个按键来控制时间的加与减,而此时的加与减的按键相当于是局部变量,可以在三个状态中分别使用。
这样一共就只需要3个按键,大大节省了硬件并且简化了软件的编程。
其次是闹钟设定:
基于时间调试的设置思路,同样将进入闹钟状态以及闹钟设定的按键分开,考虑到此时闹钟设置时,数码管的显示问题以及定时器的走时问题,故将进入闹钟的设定状态和时设定、分设定的按键分开,key4为进入闹钟状态按键,key4键切换时分秒和闹铃时间的显示。
2.总体设计方案
2.1方案论证
2.1.1核心控制模块
方案1:
采用FPGA作为核心控制模块。
由于FPGA具有强大的资源,使用方便灵活,易于进行功能扩展,特别是结合了EDA,可以达到很高的效率。
此方案逻辑虽然简单一点,但是一块FPGA的价格很高,对于做数字钟来说有一点浪费,而且FPGA比较难掌握,本设计中不作过多研究,不采用此方案。
方案2:
采用AT89C51作为核心控制模块。
此方案中AT89C51单片机的入门学习相对交容易,易于理解,外围电路比较简单,成本比较低,此系统控制灵活能很好地满足本课题的基本要求和扩展要求。
因此选用该方案。
2.1.2显示模块
方案1:
采用LCD1602液晶显示屏。
液晶极其省电,但是使用有温度范围限制,且因是反光式的,在外界光线很明亮的情况下很容易看不清楚。
液晶是分子偏转引起的暗影效果,显示不是很清晰。
方案2:
采用LED数码管显示。
数码管在低电压小电流的驱动下就能够发光,发光响应时间短,高频性好,单色性好,亮度高,显示相对而言比较清晰。
而且体积小,重量轻,抗冲击性能好,寿命长,成本低。
因此选用该方案。
2.1.3计时模块
方案1:
采用实时时钟芯片。
现在市场上有很多实时时钟集成电路,如DS1287、DS12887、DS1302等。
这些实时时钟芯片具备年、月、日、时、分、秒计时功能和多点定时功能,计时数据的更新每秒自动进行一次,不需要程序干预。
因此,在工业实时测控系统中多采用这一类专用芯片来实现实时时钟功能。
方案2:
使用单片机内部的可编程定时器。
利用单片机内部的定时计数器进行中端定时,配合软件延时实现时、分、秒的计时。
该方案节省硬件成本,但程序设计较为复杂。
因此选用该方案。
2.1.4按键模块
方案1:
采用矩阵按键,矩阵按键需要通过扫描控制和译码,设计时需要有数值移位寄存器对已有数值进行存储和调用。
软件程序设计比较繁琐,硬件连接复杂。
方案2:
采用独立按键。
单片机仿真板上有专用独立按键,连接方便,使用简单。
且易于软件编程,适合本系统的设计。
因此选用该方案。
2.2系统框图和原理分析
本电子钟的所有的软件、参数均存放咋AT98C52的FlashROM和内部RAM中减少了芯片的使用数量简化了整体电路也降低了整机的工作电流。
由于AT98C52芯片内部的FlashROM有8KB,RAM有256个字节,故软件下载编译时有足够的存储空间。
键盘采用动态扫描方式。
利用单片机定时器及计数器产生定时效果通过编程形成数字钟效果,再利用数码管动态扫描显示单片机内部处理的数据,同时通过端口读入当前外部控制状态来改变程序的不同状态,实现不同功能。
3.硬件设计
3.1单片机最小系统
单片机最小化模块由时钟电路、复位电路和AT89S52单片机构成。
时钟电路由振荡电路和分频电路组成。
其中振荡电路由高增益反相器以及并联外接的石英晶体和电容构成产生振荡脉冲。
而分频电路则用于把振荡脉冲分频,已得到所需的时钟信号。
振荡电路由单片机芯片的XTAL1端输入,XTAL2端输出。
通过这两个引脚并接一个石英晶体振荡器和两个电容(电容一般取22pF)。
而AT89S52中自带有分频电路所以不需要外接电路对脉冲信号进行分频。
复位是单片机的硬件初始化操作,经复位操作后,单片机系统才能开始正常工作。
复位电路用于产生复位信号,通过RET引脚送入单片机,进行复位操作。
图2单片机最小系统
3.2按键控制电路
输入模块由六个按键构成,一个电源开关键,一个复位键,。
键盘通过程序控制来完成电子钟的启、停及时间调整。
电源开关键控制电源的闭合和断开。
复位键控制单片机系统的复位操作。
(1)key1用于设置时钟和闹钟时间。
时钟:
key1按下第1次,时间停止,可调节秒;key1按下第2次,可调节分;key1按下第3次,可调节时;
key1按下第4次,退出时间设置,时间以设置时间为起始。
闹钟:
当key4按下后,key1按下第1次,可调节秒;key1按下第2次,可调节分;key1按下第3次,可调节时;
(2)A.key2用于调节时间的加;B.key2还可用于查看设置的闹钟。
key2按下第1次,从时钟界面切换到闹钟界面,查看第1组闹钟;key2按下第2次,查看第2组闹钟;key2按下第3次,查看第3组闹钟;key2按下第4次,退出查看闹钟界面,时间回到时钟界面。
(3)key3用于调节时间的减。
(4)key4用于时钟界面和闹钟界面的切换。
key4按下,进入闹钟设置界面,当key4再次按下时回到时钟界面。
图3按键
3.3时钟显示电路
时钟显示电路为2个四位一体的LED所组成的八位数码管显示器。
数码管都为共阳极接法,由74LS2573芯片进行驱动和阻值都为510Ω的八个电阻进行限流,提高显示亮度,数码管显示电路采用动态显示方式。
图4数码管显示电路
3.4电源模块
直流稳压电源一般由电源变压器、整流滤波电路及稳压电路组成。
直流稳压电源设计的主要内容是根据性能指标,选择合适的电源变压器、集成稳压器、整流二极管及滤波电容。
本设计中所需要的电源有PC机的USB口直接供电。
图5电源电路
4.软件设计
4.1键盘扫描程序流程图
时钟开始计时后,如果有按键按下,则进行按键消抖,否则结束程序。
再一次进行判断,如果没有按键按下就结束本次循环,如果确实有按键按下,保存按键的值,然后判断按键是否松开,如果按键松开,结束本次程序循环。
如果按键没有松开,系统调用显示程序,进行按键操作。
图6键盘扫描程序流程图
4.2数码管显示程序流程图
程序开始运行进入中断时采取保护现场,由程序选择寄存器组存放相关数据,通过查表的方法获得段码和位码,由延时程序进行延时,又通过延时,改变段码和位码,实现数码管动态显示时间,如果数码管显示到达最高位,则回到选择数据,否则恢复现场。
结束循环。
图7数码管显示流程图
4.3中断服务程序流程图
进入中断服务函数首先保护现场,选择相关的寄存器存放数据。
把计数器重装初值进行计数,打开中断。
计数器是否计数到20,如果到20则秒加一,如果秒到60,把秒清零,分加一。
否则退出循环,如果分到达60分,就把分清零,时加一。
否则退出循环,如果小时到达24时,小时清零,否则退出循环。
最后恢复现场,结束中断。
5.关键代码分析
5.1闹钟程序
/****************闹钟判断函数*****************************/
voidalarm_judgement(void)
{
if(flag==1)//判断是否设置有闹钟
{
if(((miao==xx1)&&(fen==yy1)&&(shi==zz1))||((miao==xx2)&&(fen==yy2)&&(shi==zz2))||((miao==xx3)&&(fen==yy3)&&(shi==zz3)))
{//判断时间是否到达设置闹钟的时间,如果是就打开蜂鸣器、继电器。
一共可设三组闹钟。
shu=1;buzzer
(1);relay
(1);//shu=1闹铃已响标志
}
}
}
5.2显示程序
/****************显示函数*****************************/
voiddisplay(ucharge,ucharshi)
{
HC138Set(6);P0=0x00;HC138Set(0);//消隐
delay
(1);
HC138Set(7);P0=duan[ge];HC138Set(0);//把数值入数码管
HC138Set(6);P0=wei[cc];HC138Set(0);
delay
(1);
cc++;
HC138Set(7);P0=duan[shi];HC138Set(0);
HC138Set(6);P0=wei[cc];HC138Set(0);
delay
(1);
}
/****************显示函数,数的分离和位的改变*****************************/
voidshow(ucharmiao,ucharfen,ucharshi)
{
display(miao%10,miao/10);
cc++;
display(fen%10,fen/10);
cc++;
display(shi%10,shi/10);
if(cc==5)
{
cc=0;
}
}
5.3中断服务函数
/****************中断函数*****************************/
voidtimer0(void)interrupt1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
t0++;
if(t0==20)//1s到,秒加1
{
t0=0;
miao++;
if((shu==1)&&(fen!
=0))//如果闹铃响5s后关闭
{
aa++;
if(aa==5)
{
aa=0;shu=0;
buzzer(0);relay(0);
}
}
if(fen==0)//如果闹钟设置时间为整点,闹铃优先
{
if(shu==1)
{
aa++;
if(aa==5)
{
aa=0;shu=0;
buzzer(0);relay(0);
6.软件调试
通过keiluVision4编写源程序并进行编译,当出现零错误、零警告时程序基本没有问题(如图9),然后软件调试出现图10界面进行调试,当程序全速运行时。
可以看到P0口数据不断改变则程序正常
图9keiluVision4编译界面
图10程序调试界面
7.设计总结
在此次的课程设计中,我了解到了自己能力的不足之处,在PCB制板过程中,我体会到了自己所学的知识是远远的不够,需要学习的方面还有很多。
在PCB制板过程中我遇到了一些问题,有的是我不会的或者是容易忽略的东西,导致结果不理想,通过资料的收集和文件的检索以及组员和同学的帮助,我找到了设计过程中出现的问题及问题的解决方法,从而完成了此次课程设计的任务。
此次的课程设计使我学到了很多新的,课堂上无法学到的知识,同时也加深了课堂上学到的知识,并且增强了自己理论联系实际的操作能力。
我取得了一些宝贵的经验,比如,理论必须和实际结合才能承购,知识必须通过应用才能实现其价值。
我要感谢在这次制板设计过程中组员和同学给了我很大的帮助,让我完成了这次实验。
参考文献
[1]张毅刚.单片机原理及应用(第二版)[M].北京:
高等教育出版社.2004
[2]郭天祥.新概念51单片机C语言教程[M].北京:
电子工业出版社.2007
[3]杨欣.电子设计从零开始[J].北京.清华大学出版社.2005
[4]谢自美.电子线路设计·实验·测试[M].武汉:
华中理工大学出版社,1992
[5]何立民.单片机应用系统设计[M].北京:
北京航空航天大学出版社,1993
[6]李光才.单片机课程设计实例指导[M].北京:
北京航空航天大学出版社,2004
附录一:
电路图和PCB图
图12系统硬件电路
图13系统硬件PCB图
附录二:
源程序
#include
#defineucharunsignedchar
#defineuintunsignedint
sbitkey1=P3^0;
sbitkey2=P3^1;
sbitkey3=P3^2;
sbitkey4=P3^3;
ucharxx1,yy1,zz1,xx2,yy2,zz2,xx3,yy3,zz3;//用于寄存闹钟
uchart0,aa,bb,cc,dd,shu,num,flag,temp,scan,table;
charmiao,fen,shi,amiao,afen,ashi;
ucharcodewei[]={0x80,0x40,0x10,0x08,0x02,0x01};
ucharcodeduan[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
//****************延时函数*****************************
voiddelay(uintx)
{
inta,b;
for(a=x;a>0;a--)
for(b=123;b>0;b--);
}
/****************38译码***********************************/
voidHC138Set(ucharx)
{
P2=(x<<5)|(P2&0x1f);
}
/****************继电器控制函数*****************************/
voidrelay(bitStatus)
{
if(Status)
table|=0x10;
else
table&=~0x10;
P0=table;
HC138Set(5);
HC138Set(0);
}
/****************蜂鸣器控制函数*****************************/
voidbuzzer(bitStatus)
{
if(Status)
table|=0x40;
else
table&=~0x40;
P0=table;
HC138Set(5);
HC138Set(0);
}
/****************分隔线函数*****************************/
voidSeparator(void)
{
HC138Set(7);P0=0xbf;HC138Set(0);
HC138Set(6);P0=0x24;HC138Set(0);
delay
(1);
}
/****************闹钟判断函数*****************************/
voidalarm_judgement(void)
{
if(flag==1)//判断是否设置有闹钟
{
if(((miao==xx1)&&(fen==yy1)&&(shi==zz1))||((miao==xx2)&&(fen==yy2)&&(shi==zz2))||((miao==xx3)&&(fen==yy3)&&(shi==zz3)))
{//判断时间是否到达设置闹钟的时间,如果是就打开蜂鸣器、继电器。
一共可设三组闹钟。
shu=1;buzzer
(1);relay
(1);//shu=1闹铃已响标志
}
}
}
/****************初始化函数*****************************/
voidinit(void)
{
t0=0,aa=0,bb=0,cc=0,dd=0,num=0,shu=0,flag=0,table=0,temp=0;
miao=55,fen=59,shi=23;//时钟的初始化时间
amiao=0,afen=0,ashi=0;
buzzer(0);relay(0);
TMOD=0x01;//定时器的初始化设置
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
ET0=1;TR0=1;EA=1;
}
/****************显示函数*****************************/
voiddisplay(ucharge,ucharshi)
{
HC138Set(6);P0=0x00;HC138Set(0);//消隐
delay
(1);
HC138Set(7);P0=duan[ge];HC138Set(0);//把数值入数码管
HC138Set(6);P0=wei[cc];HC138Set(0);
delay
(1);
cc++;
HC138Set(7);P0=duan[shi];HC138Set(0);
HC138Set(6);P0=wei[cc];HC138Set(0);
delay
(1);
}
/****************显示函数,数的分离和位的改变*****************************/
voidshow(ucharmiao,ucharfen,ucharshi)
{
display(miao%10,miao/10);
cc++;
display(fen%10,fen/10);
cc++;
display(shi%10,shi/10);
if(cc==5)
{
cc=0;
}
}
/****************按键控制函数*****************************/
voidkey_control(void)
{
if(key4==0)//如果key4被按下,进入闹钟设置模式
{
delay(5);
if(key4==0)
{
while(!
key4);delay(5);while(!
key4);
temp++;//控制操作界面
bb=1;//bb=1用于查看设置闹钟时间标志
if(temp==0)//时钟界面
{
show(miao,fen,shi);
}
if(temp==1)//闹钟界面
{
show(amiao,afen,ashi);
flag=1;//flag=1说明已经设置了闹钟
scan++;//scan用于寄存闹钟组数
}
if(temp==2)
{
temp=0;num=0;
if(scan==1)//寄存第1组闹钟
{
xx1=amiao,yy1=afen,zz1=ashi;
}
if(scan==2)//寄存第2组闹钟
{
xx2=amiao,yy2=afen,zz2=ashi;
}
if(scan==3)//寄存第3组闹钟
{
xx3=amiao,yy3=afen,zz3=ashi;
scan=0;
}
}
}
}
if((temp==1)||(temp==2)||(temp==3))//闹钟界面
{
Separator();
show(amiao,afen,ashi);
}
if(temp==0)//时钟界面
{
Separator();
show(miao,fen,shi);
}
if(key1==0)//如果key1被按下,进入调时模式
{
delay(5);
if(key1==0)
{
num++;//如果key4被按下一次,调秒。
如果key4被按下两次,调分。
如果key4被按下三次,调小时。
如果key4被按下四次,退出调时模式。
while(!
key1);delay(5);while(!
key1);
if(temp==0)
{
if(num==1)
{
TR0=0;
}
if(num==4)
{
num=0;
TR0=1;
}
}
}
}
if(num!
=0)//判断key1是否有按下
{
if(key2==0)//key2用于时间的加,按下一次加1
{
delay(5);
if(key2==0)
{
while(!
key2);delay(5);while(!
key2);
if(temp=