单片机电子钟实训报告

单片机电子钟实训报告

                                     学院:河南工程学院

                                      系别:电气信息工程系

                                      专业班级:通信技术1032

                              姓名:叶永柏

                                    学号:201020707259

前言

单片机自20世纪70年代问世以来,以其极高的性能价格比,受到人们的重视和关注,应用很广、发展很快。单片机体积小、重量轻、抗干扰能力强、环境要求不高、价格低廉、可靠性高、灵活性好、开发较为容易。由于具有上述优点,在我国,单片机已广泛地应用在工业自动化控制、自动检测、智能仪器仪表、家用电器、电力电子、机电一体化设备等各个方面,而51单片机是各单片机中最为典型和最有代表性的一种。这次毕业设计通过对它的学习、应用,以AT89S51芯片为核心,辅以必要的电路,设计了一个简易的电子时钟,它由直流电源供电,通过数码管能够准确显

数字时钟是现代社会应用广泛的计时工具,在航天、电子等科研单位,工厂、医院、学校等企事业单位,各种体育赛事及至我们每个人的日常生活中都发挥着重要的作用。本系统是基于AT89C51单片机设计的一个具有六位LED显示的数字时实时钟,采用独立式按键进行时间调整,同时引入一个内部充电电源在停止外部供电时,仍具有内部计时的功能。该系统同时具有硬件设计简单、工作稳定性高、价格低廉等优点。

本文以对单片机的学习和认识,并通过本次课程设计加以应用,从而达到一个对所学知识的巩固、更深一步的理解,面对一个电子设计,应对出系统的方案,分析出各个板块来,再对各个板块进一步的具体的设计,先进行硬件电路设计,此时一定要考虑好要用什么元件、各个元件的具体参数、是否能实现应有功能,从而得到一个完整的硬件电路。

目录

第一章  设计任务

1.1设计目的

1.2设计要求

第二章 总体设计

2.1 硬件部分

2.2 电子时钟电路图

2.3 电子时钟程序设计

第三章 电子时钟调试

3.1 软件调试

3.2硬件调试

第四章 总结

第五章 参考文献

第一章  设计任务

1.1设计目的

   课程设计的主要目的是通过对电子时钟的设计实践,了解单片机系统控制过程、设计要求、应完成的工作内容和具体设计方法。通过设计也有助于复习、巩固以往所学的知识,达到灵活应用的目的。课程设计应强调能力培养为主,在独立完成设计任务的同时,还要注意其他方面的能力的培养与提高,如独立工作能力与创造力;综合运用专业及基础知识的能力,解决实际工程技术问题的能力;差于图书资料、产品手册和各种工具书的能力;工程绘图的能力;书写技术报告和编制技术资料的能力。

1.2设计要求

在课程设计中,学生是主体,应充分发挥他们的主动性和创造性。教师的主导作用是引导其掌握完成设计内容的方法。为保证顺利完成设计任务还应做到以下几点:

1、在接受设计任务后,应根据设计要求和应完成的设计内容进度计划,确定各阶段应完成的工作量,妥善安排时间。

2、在方案确定过程中应主动提出问题,以取得指导老师的帮助,同时要广泛讨论,依据充分。在具体设计过程中要多思考,尤其是主要参数,要经过计算论证。

3、说明书要求文字通顺、简练,字迹端正、整洁。

4、应在规定的时间内完成所有的设计任务。

5、如果条件允许,应对自己的设计线路进行实验讨论,考虑进一步改进的可能性。

第二章 总体设计

2.1 硬件部分

1、系统设计总框图

 

图2-1 设计总框图

此次课程设计的的电子钟由单片机AT89C51、时钟电路、动态数码管显示电路组成。运用C语言来控制单片机AT89C51来实现动态数码管显示,并在此基础上综合运用,时间电子钟的设计(包括时钟、秒表、显示)。

2、电路组成及工作原理

   本文数字时钟设计原理主要利用AT89C51单片机, P2口控制LCD1602显示,P1口与按键相接用于时间的校正。整个系统工作时,秒信号产生器是整个系统的时基信号,它直接决定计时系统的精度,将标准秒信号送入“秒计数器”,“秒计数器”采用60进制计数器,每累计60秒发出一个“分脉冲”信号,该信号将作为“分计数器”的时钟脉冲。“分计数器”也采用60进制计数器,每累计60分钟,发出一个“时脉冲”信号,该信号将被送到“时计数器”。“时计数器”采用24进制计时器,可实现对一天24小时的累计。显示电路将“时”、“分”、“秒”计数器的输出,通过LCD1602显示器显示出来。校时电路是直接加一个脉冲信号到时计数器或者分计数器或者秒计数器来对“时”、“分”、“秒”显示数字进行校对调整。

3、单片机AT89C51

(1) AT89C51简介

   单片机是一种集成电路芯片,采用超大规模技术把具有数据处理能力(如算术运算,逻辑运算、数据传送、中断处理)的微处理器(CPU),随机存取数据存储器(RAM),只读程序存储器(ROM),输入输出电路(I/O口),可能还包括定时计数器,串行通信口(SCI),显示驱动电路(LCD或LED驱动电路),脉宽调制电路(PWM),模拟多路转换器及A/D转换器等电路集成到一块单块芯片上,构成一个最小然而完善的计算机系统。这些电路能在软件的控制下准确、迅速、高效地完成程序设计者事先规定的任务。

(2)AT89C51的主要性能参数

与MCS-51产品指令系统完全兼容,4k 字节可重擦写FLASH闪速存储器。1000次擦写周期。全静态操作:0Hz—24MHz。三级加密程序存储器,128×8字节内部RAM32个可编程I/O口线,2个16位定时/计数器6个中断源,可编程串行URAR通道,低功耗空闲和掉电模式。

AT89C51提供以下标准功能:4k 字节FLASH闪速存储器,128字节内部RAM,32个I/O口线,2个16位定时/计数器,一个5向量两级中断结构,一个全双工串行通信口,片内振荡器及时钟电路。同时,AT89C51降至0Hz的静态逻辑操作,并支持两种可选的节电工作模式。空闲方式体制CPU的工作,但允许RAM,定时/计数器,串行通信口及中断系统继续工作。掉电方式保存RAM中的内容,但振荡器体制工作并禁止其他所有不见工作直到下一个硬件复位。下图为单片机AT89C51各管脚图:

 

图2-2 单片机AT89C51管脚图

4、1602LCD显示部分

1602LCD 分为带背光和不带背光两种,基控制器大部分为 HD44780,带背光的比不带背光

的厚,是否带背光在应用中并无差别

1602LCD 主要技术参数:

显示容量:16×2 个字符

芯片工作电压:4.5—5.5V

工作电流:2.0mA(5.0V)

模块最佳工作电压:5.0V

字符尺寸:2.95×4.35(W×H)mm

引脚功能说明

1602LCD 采用标准的 14脚(无背光)或 16脚(带背光)接口,各引脚接口说明如表 10-13

所示:

编号  符号  引脚说明     编号  符号  引脚说明

1     VSS     电源地       9   D2     数据

2     VDD   电源正极      10   D3    数据

3     VL   液晶显示偏压    11   D4    数据

4     RS   数据/命令选择    12   D5    数据

5     R/W  读/写选择        13   D6    数据

6     E     使能信号        14   D7    数据

7     D0    数据            15   BLA  背光源正极

8     D1    数据            16   BLK  背光源负极

表 10-13:引脚接口说明表

第 1 脚:VSS 为地电源。

第 2 脚:VDD接 5V正电源。

第 3 脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对

比度过高时会产生“鬼影”,使用时可以通过一个 10K 的电位器调整对比度。

第 4 脚:RS 为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。

第 5 脚:R/W 为读写信号线,高电平时进行读操作,低电平时进行写操作。当 RS和 R/W

共同为低电平时可以写入指令或者显示地址,当 RS 为低电平 R/W 为高电平时可以读忙信

号,当 RS 为高电平 R/W为低电平时可以写入数据。

第 6 脚:E端为使能端,当 E 端由高电平跳变成低电平时,液晶模块执行命令。

第 7~14脚:D0~D7为 8 位双向数据线。

第 15脚:背光源正极。

第 16脚:背光源负极。

2.2 电子时钟电路图

图2-3 线路连接图

2.3 电子时钟程序设计

1、程序流程图

如图2-4所示

 


流程图: 决策: 秒中断 流程图: 决策: 键盘中断                                   

图2-4

2、电路元器件清单

3、电子时钟C语言源程序

/***********************************

   使用LCD1602与单片机实现的时钟与日期

   显示年、月、日、时、分、秒(24小时制)

   时间可调, 年份20##——9999

                jiahuhenan

               20##年10月9日

***********************************/

#include<reg51.h>

/******全局变量的定义与设置******/

sbit key_mean=P1^0;                                                //按键的定义

sbit key_ok  =P1^1;

sbit key_set =P1^2;

sbit RS      =P1^5; //LCD控制端口

sbit RW      =P1^6;

sbit E       =P1^7;

sfr  PORT    =0xA0;

//flag

char flag_sec=0;                                                           //值为20代表1s

char flag_en_ok=0;

char flag_en_key=0;                                                    //值为1表示键盘有效,否则无效

char flag_ok=0;                                                              //key_up与key_down的功能选择

char flag_mean=0;

char flag_set=0;                                                           //key_up与key_down的功能标识

char flag_year_leap=0;

//短语

 //code char string_time[]=  "Setting time  ?  \0";

 code char string_year[]=  "Setting year  ?  \0";

 code char string_month[]= "Setting month ?  \0";

 code char string_mday[]=  "Setting day   ?  \0";

 code char string_week[]=  "Setting week  ?  \0";

 code char string_hour[]=  "Setting hour  ?  \0";

 code char string_minute[]="Setting minute?  \0";

 code char string_second[]="Setting second?  \0";

//年月日时分秒的定义

struct DATA_TIME

{

                                                                                  short year;      //待选

                                                                                  char month;

                                                                                  char mday ;

                                                                                  char week ;

                                                                                  char hour ;

                                                                                  char minute;

                                                                                  char second;

}time;

struct time_char        //time的字符型

{

    char ch_year[4];

    char ch_month[2];

    char ch_mday[2];

    char ch_week[1];

    char ch_hour[2];

    char ch_minute[2];

    char ch_second[2];

}time_ch;

/***************子函数****************/

//LCD的延时程序

void LCD_delay(void)

{

  char i;

  for(i=123;i>=0;i--);

}

//向写指令函数

void wcmd(char cmd )

{

  RS=0;

  RW=0;

  E=1;

  LCD_delay();

  PORT=cmd;

  LCD_delay();

  E=0;

}

//向LCD写数据函数

void wdata(char DATA)

{

  RS=1;

  RW=0;

  E=1;

  LCD_delay();

  PORT=DATA;

  LCD_delay();

  E=0;

}

//写字符串

void wstring(char *pt,char i)//i为字符的个数,不带\0

{

    char j;

   for(j=0;j<i;j++)

   {

       wdata(pt[j]);

   }

}

//时间数据的格式转换

void tran_2_ch(char *pt,char DATA)

{

  pt[0]=DATA/10+0x30;

  pt[1]=DATA-pt[0]*10+0x10;

}

void tran_4_ch(char *pt,int DATA)

{

    pt[0]=DATA/1000;

    pt[1]=DATA/100-pt[0]*10;

    pt[2]=DATA/10-pt[0]*100-pt[1]*10;

    pt[3]=DATA-pt[0]*1000-pt[1]*100-pt[2]*10;

    pt[0]+=0x30;

    pt[1]+=0x30;

    pt[2]+=0x30;

    pt[3]+=0x30;

}

//格式转换的实现

void tran_ch(void)

{

  tran_4_ch(time_ch.ch_year ,time.year );

  tran_2_ch(time_ch.ch_month,time.month);

  tran_2_ch(time_ch.ch_mday ,time.mday );

  //tran_2_ch(time_ch.ch_week ,time.week*10+1);

  time_ch.ch_week[0]=time.week+0x30;

  tran_2_ch(time_ch.ch_hour ,time.hour );

  tran_2_ch(time_ch.ch_minute,time.minute);

  tran_2_ch(time_ch.ch_second,time.second);

}

//是否是闰年

char leep_year(int year)//如果是闰年则flag_year_leep=1,否则=0

{

    if((year%400==0)||year%4==0&&year%100!=0)return 1;

    else return 0;

}

//星期的判断

void de_week(void)

{

    int i,j,day=0;

    char mweek;

    for(i=2000;i<time.year;i++)

    {

        if(leep_year(i))day+=366;

        else day+=365;

    }

    for(j=1;j<time.month;j++)

    {

        if(j==1||j==3||j==5||j==7||j==8||j==10||j==12)

        day+=31;

        if(j==4||j==6||j==9||j==11)

        day+=30;

        if(flag_year_leap&&j==2)day+=29;

        if((!flag_year_leap)&&j==2)day+=28;

    }

    day+=time.mday;

    mweek=day%7;

    switch(mweek)

    {

        case 0:time.week=5;break;

        case 1:time.week=6;break;

        case 2:time.week=7;break;

        case 3:time.week=1;break;

        case 4:time.week=2;break;

        case 5:time.week=3;break;

        case 6:time.week=4;break;

    }

                                                                                  time_ch.ch_week[0]=time.week+0x30;

//月份的进位处理

void time_carry_mon_year(void)

{

    flag_year_leap=leep_year(time.year);//判断闰年

    if(time.mday>=30)

    {

        if(time.month==1||time.month==3||time.month==5||time.month==7\

           ||time.month==8||time.month==10||time.month==12)

                                  //天数为31天的月,1、3、5、7、8、10、12

        {

            if(time.mday==32)

            {time.mday=1;time.month++;}

        }

        if(time.month==4||time.month==6||time.month==9||time.month==11)

        {

            if(time.month==31)

            {time.mday=1;time.month++;}

        }

        tran_ch();

    }

    if(time.month==2&&time.mday>=28)

    {

        if(flag_year_leap&&(time.mday==30))

        {    time.mday=1;time.month++;}

        if((!flag_year_leap)&&(time.mday==29))

        {    time.mday=1;time.month++;}

        tran_ch();

    }

    if(time.month==13)

    {time.month=1;time.year++;tran_ch();}//年的进位

}

//时间的进位

void time_carry(void)

{

    if(time.second==60)

    {time.minute++;time.second=0;}

    if(time.minute==60)

    {time.hour++  ;time.minute=0;}

    if(time.hour  ==24)

    {time.mday++   ;time.hour=0 ;time_carry_mon_year();de_week();}

}

//屏幕的显示函数

void dsp(void)

{

    if(flag_en_key==0)//非设置模式下的显示

    {

        tran_ch();

        wcmd(0x02);//return cursor

        wstring(time_ch.ch_hour,2);

        wdata(':');

        wstring(time_ch.ch_minute,2);

        wdata(':');

        wstring(time_ch.ch_second,2);

        wstring("   ",3);

        wcmd(0x80+0x40);

        wstring("   ",3);

        wstring(time_ch.ch_year,4);

        wdata('-');

        wstring(time_ch.ch_month,2);

        wdata('-');

        wstring(time_ch.ch_mday,2);

        wstring("WK",2);

        wdata(time_ch.ch_week[0]);

    }

    if(flag_en_key==1)//设置模式下的显示

    {

        if(flag_set<=2)

        {

            tran_ch();

            wcmd(0x02);//return cursor

            wstring(time_ch.ch_year,4);

            wdata('-');

            wstring(time_ch.ch_month,2);

            wdata('-');

            wstring(time_ch.ch_mday,2);

        }

        if(flag_set>2)

        {

            tran_ch();

            wcmd(0x02);//return cursor

            wstring(time_ch.ch_hour,2);

            wdata(':');

            wstring(time_ch.ch_minute,2);

            wdata(':');

            wstring(time_ch.ch_second,2);

            wstring("   ",3);

        }

    }

}

//显示字符串

void dsp_string(char *pt)

{

    char i=0;

    wcmd(0x80+0x40);//将光标调整至第二行

    while(pt[i])

    {

        wdata(pt[i]);

        i++;

    }

}

//退出按键模式

void exit_key(void)

{

   char i;

   flag_en_key=0;

   flag_en_ok=0;

   flag_ok=0;

   flag_mean=0;

   flag_set=0;

   wcmd(0x80+0x40);

   for(i=0;i<=16;i++)

   wdata('\0');

}

//按键的处理

int solve_key(void)

{

   //if(key_mean==0);

   if(key_ok==0)//确定或退出

   {

      if(flag_ok)

                                                                                    {

                                                                                        exit_key();

                                                                                      time_carry_mon_year();

                                                                               de_week();

                                                                                      return 0;

                                                                                    }

                                                                                    else flag_ok=1;

   }

   if(key_set ==0)

   {

       if(flag_ok==0)//时分秒的选择

       {

           flag_set++;

           if(flag_set==6)flag_set=0;

           switch(flag_set)

           {

               case 0:dsp_string(string_year);break;

               case 1:dsp_string(string_month);break;

               case 2:dsp_string(string_mday);break;

               case 3:dsp_string(string_hour);break;

               case 4:dsp_string(string_minute);break;

               case 5:dsp_string(string_second);break;

           }

       }

       if(flag_ok==1)//时分秒的设置

       {

          switch(flag_set)

          {

              case 0:{time.year++  ;if(time.year==10000)time.year=2000;break;}

              case 1:{time.month++ ;time_carry_mon_year();break;}

              case 2:{time.mday++  ;time_carry_mon_year();break;}

              case 3:{time.hour++  ;if(time.hour==24)time.hour=0;break;}

              case 4:{time.minute++;if(time.minute==60)time.minute=0;break;}

              case 5:{time.second++;if(time.second==60)time.second=0;break;}

          }

       }

   }

   if(flag_ok==1)//是否更改数据                         是显示 OK  否显示 ?

   {

       wcmd(0x80+0x4e);

       wdata('O');

       wdata('K');

   }

   else

   {

       wcmd(0x80+0x4e);

       wdata('\0');

       wdata('?');

   }

   return 0;

}

//MCU的秒中断函数与显示函数的执行

void INT_sec() interrupt 1 using 0

{

   if(flag_sec==20)//flag_sec==20代表1s

   {

       flag_sec=0;

       TH0=0x3c;

       TL0=0xb0+2;//定时器再次进入0.05s的中断

       time.second++;

       flag_en_ok=0;//去掉key_ok的特殊优先权

       time_carry();

       dsp();

   }

   else

   {

      flag_sec++;

      TH0=0X3C;

      TL0=0XB0+2;//定时器再次进入0.05s的中断

   }

}

//外中断0,键盘中断

 INT_X0(void)  interrupt 0  using 0

{

   LCD_delay();                                                      //去抖

   TR0=0;//关闭定时计数器0

   if(key_mean==0)

   {

      flag_en_ok=1;

      flag_ok=0;

      dsp_string(string_year);

   }

   if(flag_en_ok&&key_ok==0)

   {flag_en_key=1;flag_en_ok=0;}

   if(flag_en_key==1)

   {

      solve_key();

   }

   TR0=1;//启动定时计数器0

}

//LCD  的初始化

void init(void)

{

  E=0;//确定E在初始化时为0

  wcmd(0x01);

  wcmd(0x06);

  wcmd(0x0c);

  wcmd(0x38);

}

/************main函数*****************/

int main()

{

  //单片机的初始化

  EA=1;

  ET0=1;//定时计数器0的使能

  EX0=1;//外中断0的使能

  IT0=1;//下降沿触发中断

  IP=0x02;//定时计数器0的中断优先级最高

  TMOD=0x01;//定时计数器0为工作模式1

  TH0=0x3c;

  TL0=0xb0;//定时计数器参数为0x3cb0,0xffff-0x3cb0=50000,一个中断中期为0.05s

  TR0=1;//MCU初始化后直接启动定时计数器0

  time.year=2000;

  time.month=1;

  time.mday=1;

  time.week=6;

  time.hour=0;

  time.minute=0;

  time.second=0;

  init(); //LCD 初始化

  while(1);//单片机等待中断

}

第三章 电子时钟调试

调试的主要过程包括硬件调试和软件调试,其中软件调试,也即程序编译与仿真过程处于本次设计调试过程的核心环节。由于本设计已经制作出液晶显示电子钟,所以硬件调试也很重要。两种调试过程并非孤立或者分开的,而是紧密相关。在此我们用到的开发工具是仿真器。

3.1 软件调试

软件调试:

系统仿真分析电路原理图在ISIS里设计完成,并将系统软件编译成.Hex文件,再进行电子时钟的系统虚拟仿真 。

(1)在ISIS的原理图中,右键单击AT89C51将其选中,然后单击左键打开AT89C51的Edit Component 对话框,如下图所示。(2)选择相应的.Hex文件,再在Proteus ISIS 编辑窗口的File菜单中选择Save Design 选项,保存设计,生成.DSN文件。

本次实训主要在仿真软件Proteus7.8进行调试,仿真电路如图所示:

图3-1 电子时钟仿真电路

3.2硬件调试

硬件调试

完成仿真器软件仿真后,就要连接上硬件也即液晶显示电子钟成品板进行硬件调试。

将仿真器通过串行电缆连接计算机上,将仿真头接到仿真器,检查接线是否有误,确信没有接错后,接上电源,打开仿真器的电源开关。再进行仿真器和通信设置。

仿真器和仿真头设置正确,并且硬件连接没有错误,出现 “硬件仿真”的对话框,并显示仿真器、仿真头的型号及仿真器的序列号。表明仿真器初始化正确。

硬件调试很重要也很麻烦,由于本次设计硬件非PCB制板,而是手工焊板,焊点质量、布线是否合理等对系统的影响比较大,这无疑增加硬件调试的难度。由于此前没有很多的练习,本次设计我所制作的液晶显示电子钟在质量工艺上很难达到满意程度,不过在调试中还算稳定,基本功能都能较稳定地实现。

总结

在设计过程中,通过针对性地查找资料,了解了些电子方面的资料,既增长了自己见识,补充最新的专业知识,又提高了自己的应用能力。

这次对AT89C51有了一个全面的认识,在此基础上结合以前所学的专业知识,从而把我所学的知识贯穿到一起,对电子专业有了一个更全面的认识!

总之这次毕业设计让我把理论设计和工程实践相结合、巩固基础知识与培养创新意识相结合、个人作用和集体协作相结合等方面全面的培养学生的全面素质。这些在我今后的学习和工作当中都会有很大的帮助。

在试验中,我们同组人员之间相互合作、默契配合,遇到问题一起加以讨论解决,不同的思路与意见两个人在一起分享讨论,并最终采用得到的最为理想与完善的方案。在这个分享与讨论的过程中,我们锻炼了我们自己的团队协作能力与沟通能力,能够让这次课程设计在跟同事的协作配合下很好地完成,让自己的创作激情与工作热情在默契和谐的团队配合下得以充分的燃烧。

参考文献

[1] 华成英,童诗白.  模拟电子技术基础.高等教育出版社,20##年8月

[2] 李群芳,张士军,黄建. 单片微型计算机.电子工业出版社,20##年2月

[3] 赵辉,刘印华 .PROTEL 99电子线路CAD.北京邮电大学出版社.20##年1月

[4] 实用单片机电子钟的设计/丁辉、姚庆文    无线电20##年合订本(下)             

[5] 于海生.微型计算机控制技术[M] .清华大学出版社.1999-6

相关推荐