查看: 1311|回复: 0
打印 上一主题 下一主题

单片机数字时钟资料

[复制链接]
跳转到指定楼层
沙发
发表于 2015-9-30 14:03:55 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一、总体概述
本设计采用89S52系列单片机作为时钟的控制核心,电路使用了八个数码管作为时钟显示,用计数器中断程序作为了一秒钟的精确计数,并用按钮实现了调闹钟时间和时钟时间的校对功能。
关键词:单片机、控制、显示、调时。
Abstract
This design's adopting a single slice of the 89 S52 serieses machine is the control core of the clock, theelectric circuit used eight piece code tubes as the clock manifestations,
The precision that used to count the machine interruption procedureconduct and actions for a second count, counteracting a button to carry out toadjust check of the alarm clock time and the clock time function.
二、  竞赛赛题及要求
单片机音乐演奏
基本要求:1、利用单片机演奏一和谐的音乐,音乐时长不少于两分钟;
2、能够随时实现中断;
              3、能够手动调节音乐重复次数。
    发挥部分:1、音乐演奏时同时有彩灯闪烁伴奏。
              2、用按键实现多首音乐间的选择,且任何时间都能选择
本时钟程序采用了C语言与汇编语言相结合的方案,使用C主要是考虑到本人学习单片机的时间很短,而此次竞赛又迫在眉睫,对于开发时间如此紧的竞赛, C语言有着汇编无可比拟的优势。C语言是一种编译型程序设计语言,它兼顾了多种高级语言的特点,并具备汇编语言的功能。C语言有功能丰富的库函数、运算速度快、编译效率高、有良好的可移植性,而且可以直接实现对系统硬件的控制。C语言是一种结构化程序设计语言,它支持当前程序设计中广泛采用的由顶向下结构化程序设计技术。此外,C语言程序具有完善的模块程序结构,从而为软件开发中采用模块化程序设计方法提供了有力的保障。因此,使用C语言进行程序设计已成为软件开发的一个主流。用C语言来编写目标系统软件,会大大缩短开发周期,且明显地增加软件的可读性,便于改进和扩充,从而研制出规模更大、性能更完备的系统。
三、方案选择与论证
    根据题目要求,电路总共可分为以下几个基本模块,对于各个模块的实现,有以下一些设计方案,均进行了可行性分析,最终选择了最实际可行的方案。
软件部分:
1、        计时控制方案
方案一:使用专用时钟芯片。
使用微控制器控制专用时钟芯片实现计时控制,这种方案有着计时精度高、控制简单的优点,而且更易于实现日期/时间显示、定时烹调等计时扩展功能。
方案二:采用MCU内部定时器。
AT89S52内部含有2个定时器,可以利用一个定时器与程序计数器相结合的方式,在系统晶振的驱动下,产生标准时钟频率。
由于方案二具有较好的灵活性、较少的电路器件和较高的性价比,而且通过精确的软件补偿使精度完全可以满足控制需要,所以我们选择该方案完成设计。
2主控制器模块
主控制器的选择对电路功能的实现尤为重要
方案一:单片机和数字芯片结合使用,这样的好处是能减少单片机的工作量,使电路不单纯的只依赖于单片机工作,但是如果使用数字芯片,就有点违背题目初忠,单片机的功能也不能直观的显现出来。而且相对来说成本要高。电路也不够简略。
方案二:单独使用单片机控制,它的好处是外围电路比较简单直观,所有的控制都只需用软件程序来实现,对于单片机来说,时钟程序远不够它自身的承受量,所以只要程序编的合理,就能比较方便的实现。
基于上述理论分析,拟选择方案二。
3、显示电路模块
(1)显示器件的选择:
方案一:采用点阵显示,可做成表盘显示,但是点阵显示成本较高,同时所需资源也较多,控制比较繁琐,编程较繁琐。
方案二:采用数码管显示,这种显示方法比较直观,也比较切合现实生活,而且对于电路的设计来说比较方便,节省了电路板的空间,使用三极管驱动后所需电压也相对较低,稳定性也相对较高,而且编程较简单。
方案三:使用点阵式LCD
点阵液晶可以显示多种字符及图形,拥有友好的人机界面及强大的显示功能。特别适用于智能控制的可编程人性化显示。但是技术含量过高,实现非常复杂,需要完成大量的显示工作,其功能也是最强大的。采用点阵式LCD,可以将用户需求及时显示出来,使用户自定义输入变得非常方便。但由于我们所设计系统无须如此复杂便可加以实现,而且考虑到市场价格问题。
权衡之后方案二作为显示电路的实现。
(2)显示器件个数的选择:
方案一:十六个数码管显示,这样可以把时钟时间和日期分开显示,直观性很强,但是资源比较浪费。
方案二:八个数码管显示,用按键实现对时钟和日期的显示,因为在实际生活中我们对日期显示的需求并不在每时每刻,所以大可在需要时再显示。这样就减少了八个数码管的占用空间和成本。
综上理论分析,拟选择了第二种方案。
(3)数码管与单片机的接口选择
方案一:用741387447集成芯片连接,对输出端口进行扩展,这样可以减少输出端口,但在时钟电路中所需控制的输出设备不多,用这种方案会使外围电路复杂,而且一些P口闲置浪费。
方案二:直接与端口连接,使得外围电路直观简单,在编程序时也会显得简单明了。
基于上述考虑,拟采用方案二。
4、调试按键模块
方案一:使用键盘控制,它的效果比较直观,能直接根据需要按键,直接得出所需的数值,而且对程序的要求也不需很大,但使用的按钮量较多,占的空间也较大,而且实际实用性不强。
方案二:采用独立式按键电路,每个键单独占有一根I/O接口线,每个I/O口的工作状态互不影响,此类键盘采用端口直接扫描方式。缺点是当按键较多时占用单片机的I/O数目较多,优点是电路设计简单,且编程极其容易。考虑到时钟控制在实际使用时的资源量并不大,使用按钮控制可以大大减少按键的使用量。
综上理论分析,由于该系统采用了常规钟表式的校对方式,用键较少,系统资源足够用,拟选择了第二种方案作为调时电路的实现。
5、电源模块
方案一:取用单片三端稳压集成7805,电路简单、稳定可靠,且成本低,稳压效果好。
6、闹钟声光报警模块
方案一:取用蜂鸣器和数只发光二极管组成,电路简单,单片机编程容易,调试简单,但电路的可观性与娱乐性不高。
方案二:取用单片机编程音乐输出,数十只不同颜色的发光二极管排列成不同的图形,利用单片机编程控制发光管作不同的闪烁,可观性与娱乐性都大大提高,又能突出单片机在多功能控制的特点。
四、系统总体结构
                              
电路图
工作原理:利用单片机89S52作为本系统的中控模块。电路设有四个按键,一个为功能选择开关,能够选择调节时间、日期、第一个闹钟、第二个闹钟;第二个为“加”按钮,能够实现数字的累加;第三个为“减”按钮,能够实现数字的递减;第四个为确定选择开关。电路程序取用单片机内部其中一个定时中断系统作为基准秒频,这样能够使CPU达到最大利用。功能调节时显示电路仍然能够达到同步显示。当调节的闹钟时间与时钟显示的时间相等时,声光报警电路动作,取用LM386能够放大单片机输出的音频信号,推动扬声器发出乐耳的音乐;利用80只不同颜色的发光二极管排列成奥运五环,在单片机的驱动下能够以不同方式闪烁发光,使人耳目一新。
三、系统的硬件设计与实现
时钟程序的整体设计方案是用单片机驱动电路控制时钟显示,为显示提供电源,用软件程序控制时种运行和各种调节功能。
1、电源电路
取用单片三端稳压集成7805,电路简单、稳定可靠,且成本低,稳压效果好。
                
          
12 电源电路设计
     
     [/td]    [/tr]
   
   

2、显示电路
采用八只共阳数码管作为时钟电路的显示。数码管的a~h分别并联在一起,由单片机的P0口控制,每只数码管的共阳极分别接一只PNP三极管驱动,三极管具有电流放大作用。
3、单片机基本电路
单片机基本电路是使单片机正常工作所需要的最基本的电路,包括有复位电路,时钟电路,电源电路。
4、按键电路
五、单片机软件程序:
1、时钟程序(单片机一)
#include<reg52.h>
sbit a0=P1^0;
sbit a1=P1^1;
sbit a2=P1^2;
sbit a3=P1^3;
sbit a4=P3^6;
sbit a5=P3^1;
static charJP[10]={0xee,0xde,0xbe,0x7e,0xed,0xdd,0xbd,0x7d,0xeb,0xdb};
static char Lie[4]={0xef,0xdf,0xbf,0x7f};
char LEDXS[8];
static char LEDWEI[8]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
static charLED[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
unsigned char hour,minute,second;
unsigned int C100us;                  //100us计数单元
unsigned intM,H,key,J=1,K=1,KK=1,MO,DA,YE,M1=61,H1=25,M2=61,H2=25;
//////////////////////////////////////////////////////////////////////////
void wait(unsigned int i)           //延时函数
{unsigned int j;
for(j=0;j<i;j++);
}
////////////////////////////////////////////////////
anniu()                            //按钮函数
{key++;
wait(2000);
}
////////////////////////////////////////////////////
void displayled(void)                   //显示函数
{unsigned char i;
for(i=0;i<8;i++)
{P0=LEDXS;
P2=LEDWEI;
wait(100);
}
}
////////////////////////////////////////////////////
void date(void)                    //日期函数
{unsigned int s;
LEDXS[0]=LED[2];
LEDXS[1]=LED[0];
LEDXS[2]=LED[0];
LEDXS[3]=(LED[YE]-0x80);
LEDXS[4]=LED[MO/10];
LEDXS[5]=(LED[MO%10]-0x80);
LEDXS[6]=LED[DA/10];
LEDXS[7]=LED[DA%10];
s=10;
while(s)
{s--;
  displayled();
  }
}
////////////////////////////////////////////////////
void LEDTS(void)                        //调时函数
{unsigned int q=0,a,b,c,w,s,x,y;
if((a1==0)&&(key==1)){q=1;}
if((q==1)&&(key!=3))
{M++;
  if(M==60){M=0;H++;}
  if(H==24){H=0;}
}
if((a2==0)&&(key==1)){x=1;}
if((x==1)&&(key!=3))
{M--;
  if(M==0){M=59;}
}
if((a1==0)&&(key==2)){w=1;}
if((w==1)&&(key!=3))
{H++;
if(H==24){H=0;}
}
if((a2==0)&&(key==2)){y=1;}
if((y==1)&&(key!=3))
{H--;
if(H==0){H=23;}
if(a4==0){key=1;}
}
if(a1==1){q=0;w=0;}
if(a2==1){x=0;y=0;}
LEDXS[0]=LED[H/10];
LEDXS[1]=LED[H%10];
LEDXS[2]=0xbf;
LEDXS[3]=LED[M/10];
LEDXS[4]=LED[M%10];
LEDXS[5]=0xbf;
LEDXS[6]=LED[0];
LEDXS[7]=LED[0];
if(key==5){a=1;}
while(a)
{date();
  if(a1==0){DA++;if(DA==32){DA=0;}}
  if(a2==0){DA--;if(DA==0){DA=31;}}
  if(key!=5){a=0;}
  if(a0==0){anniu();}
  }
if(key==6){b=1;}
while(b)
{date();
  if(a1==0){MO++;if(MO==13){MO=0;}}
  if(a2==0){MO--;if(MO==0){MO=12;}}
  if(key!=6){b=0;}
  if(a0==0){anniu();}}
if(key==7){c=1;}
while(c)
{date();
  if(a1==0){YE++;if(YE==10){YE=0;}}
  if(a2==0){YE--;if(YE==0){YE=9;}}
  if(key!=7){c=0;}
  if(a0==0){anniu();}}
   s=10;
while(s)
{s--;
  displayled();
  }
  K=1;
  J=1;
}
////////////////////////////////////////////////////////////
void T0Int(void) interrupt 1 using 0   //T0中断服务函数
{C100us--;
if(C100us==0)               //100us计数器为0,重置计数器
{C100us=20000;
wait(140);
second++;
if(second==60){second=0;minute++;}
   if(minute==60){minute=0;hour++;}
     if(hour==24){hour=0;DA++;}
       if(DA==30){MO++;DA=0;}
         if(MO==12){YE++;MO=0;}}}
//////////////////////////////////////////////////////////////
void main(void)         //主函数
{unsigned int p,q,w;
TMOD=0X02;         //设置T0工作方式与初值
TH0=0xd2;
TL0=0x00;
IE=0X82;           //开中断
hour=0;
minute=0;
second=0;
w=0;
YE=6;
MO=5;
DA=7;
C100us=20000;
TR0=1;             //启动定时器
P3=0xff;           
while(1)
{LEDXS[0]=LED[hour/10];
LEDXS[1]=LED[hour%10];
LEDXS[2]=0xbf;
LEDXS[3]=LED[minute/10];
LEDXS[4]=LED[minute%10];
LEDXS[5]=0xbf;
LEDXS[6]=LED[second/10];
LEDXS[7]=LED[second%10];
displayled();
if(a0==0){p=1;}
while(p)
  {LEDTS();                                 //调入调时函数
  if(a0==0){anniu();}
  if(key==3)
  {if(a1==0){minute=M;hour=H;second=0;K=0;KK=0;}  //调节时钟时间
           {if(a3==0){M2=M;H2=H;J=0;}
           if(J==1)
           {if(a3==1){M1=M;H1=H;}}}            //调节闹钟时间
            if(minute==M){M1=0;H1=0;M2=0;H2=0;}
            if(a2==0){p=0;key=0;goto hat;}
   }
hat: if(key==4){q=1;}                     //显示年月日
while(q)
{date();
  if(a0==0){anniu();}
  if(key>4){q=0;}
  }
  if(key>7){p=0;}
  }
  w++;
if(w==100){key=0;w=0;}
if(K==1)
      {if((minute==M1)&&(hour==H1))
         {a5=0;a4=1;}}                    //达到闹铃时间响铃
if(KK==1){if((minute==M2)&&(hour==H2))
           {a5=0;a4=1;}}
if(a1==0){a5=1;a4=0;if(minute==M1){K=0;}if(minute==M2){KK=0;}}
  if((minute>=(M1+1))&&(minute!=M2))
   {a5=1;a4=0;K=1;if(a5==1){M=minute;H=hour;}}  //过一分钟后停
  if((minute>=(M2+1))&&(minute!=M1))
  {a5=1;a4=0;KK=1;if(a5==1){M=minute;H=hour;}}
if(a3==0)                                        //显示闹钟时间
   {anniu();if(key==1)
                     {
                      LEDXS[0]=LED[H1/10];
                      LEDXS[1]=LED[H1%10];
                      LEDXS[2]=0xbf;
                      LEDXS[3]=LED[M1/10];
                      LEDXS[4]=LED[M1%10];
                     LEDXS[5]=0xbf;
                      LEDXS[6]=LED[0];
                      LEDXS[7]=LED[0];
                      while(1)
                      {if(a3==1){key=2;gotoaa;}
                       displayled();}}
                    aa: if(key==2)
                     {
                      LEDXS[0]=LED[H2/10];
                      LEDXS[1]=LED[H2%10];
                      LEDXS[2]=0xbf;
                      LEDXS[3]=LED[M2/10];
                      LEDXS[4]=LED[M2%10];
                      LEDXS[5]=0xbf;
                      LEDXS[6]=LED[0];
                      LEDXS[7]=LED[0];
                      while(1)
                      {if(a3==0){key=3;gotoaa;}
                       displayled();}key=0;}
   }
}
}
六、功能测试及结果分析
    时钟最主要的是精度的调节,对此我们做了多次试验来调节时钟的精度。精度的实现主要是由单片机的计数器控制,我们所用的晶振是12M的,即周期为(1/12000000)s,经过计算,将一秒钟分割成20000*600个晶振周期,所以在计数器的高低位参数设定时,用了(FFFF-600)来计数,但是由于实际运用中,这样的计算还是有挺大的误差,因此,在调试过程中,做了多次的修改。
具体测试如下:
    
测试次数
    
  
测试时间
  
  
  
误差
  
  
  
备注
  

    
第一次
    
  
一小时
  
  
  
快三秒
  
  
  
修改
  

    
第二次
    
  
一小时
  
  
  
慢两秒
  
  
  
修改
  

    
第三次
    
  
两小时
  
  
  
快两秒
  
  
  
修改
  

    
第四次
    
  
三小时
  
  
  
快两秒
  
  
  
修改
  

    
第五次
    
  
三小时
  
  
  
快一秒半
  
  
  
修改
  

    
第六次
    
  
三小时
  
  
  
慢一秒
  
  
  
修改
  

    
第七次
    
  
三小时
  
  
  
快不到半秒
  
  
  
修改
  
自行发挥部分:用了奥运五环标志作为闹铃响时的辅助效果,达到了娱乐性。
七、参考书目
1、《单片机原理及应用》主编:万文略 重庆大学出版社
2、《单片及应用技术与实例》主编:沙占友 电子工业出版社
3、《C程序设计》主编:谭浩强 清华大学出版社
八、比赛心得
通过这次竞赛,我们在硬件设计、软件编程方面得到了极大的提高。同时我们小组的三个成员团结一心,通力合作,体现了很好的团队合作精神。为以后走向工作岗位从事科研或管理工作积累了不可多得的经验。在竞赛中碰到了一个接一个的难题,我们经过不屈不挠的刻苦攻关,一一得到了化解,这种体验为我们走好今后的人生路增添了极大的信心。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入因仑

本版积分规则

快速回复 返回顶部 返回列表