> 文章列表 > 基于 AT89C51 单片机的数字时钟设计

基于 AT89C51 单片机的数字时钟设计

基于 AT89C51 单片机的数字时钟设计

目录

1.设计目的、作用

2.设计要求

3.设计的具体实现

3.1 设计原理

3.2 硬件系统设计

        3.2.1 AT89C51 单片机原理

3.2.2 晶振电路设计

3.2.3 复位电路设计

3.2.4 LED 数码管显示

3.3 系统实现

3.3.1 系统仿真与调试

3.3.2 演示结果

4.总结

附录

附录 1

附录 2


1.设计目的、作用

(1)掌握 51 系列单片机的基本硬件结构及工作原理;
(2)掌握 51 系列单片机的汇编语言及基本程序设计方法;
(3)学习并掌握使用 51 系列单片机开发控制系统的基本步骤及方法;
(4)  能灵活运用 Keil 进行软件编程调试以及用 proteus 软件仿真;
(5)  设计组成电子时钟系统,画出系统硬件电路图,设计编写程序。

2.设计要求

基于 AT89C51 单片机的 4 位数字时钟主要具有如下功能
基本要求如下:
1)时间计数电路采用 24 进制,从 00 开始到 23 后再回到 00
(2)用数码管显示时、分、秒;
(3)具有手动校时校分功能,可以分别对时、分进行单独校时,使其校正标准时间;
(4)计时过程具有报时功能,当时间达到整点前 10 秒开始,蜂鸣器 1 秒响1 秒停响 5 次;
(5)增加秒表功能,按键按下后进入 60 秒倒计时。

3.设计的具体实现

3.1 设计原理

该电子时钟由 AT89C51,晶振电路,复位电路,数码管,蜂鸣器等构成,采用晶振电路作为驱动电路,由延时程序和循环程序产生的一秒定时,达到时分秒的计时,六十秒为一分钟,六十分钟为一小时,满二十四小时为一天。而电路中的 5 个控制键却拥有多种不同的功能,按键 S1S2 可以实现数码管时间校对,分别进行加 1 和减 1 的操作;按键 S3 实现校对和时间显示的切换,按一次,切换一次,切换功能包括秒校对、分校对、时校对、和时间显示;按键 S4 实现秒表功能,按键 5 实现秒表启动和暂停,按键 S6 实现秒表数字清零。电子时钟可实现整点报时功能,当时间还有 5 秒到达整点,利用延时程序和循环程序通过蜂鸣器鸣响进行报时。

 3-1 硬件框架图

3.2 硬件系统设计

        3.2.1 AT89C51 单片机原理

        AT89C51 是 MCS 51 系列单片机中的一种低功耗、高性能的片内含有 4KB快闪可编程/擦除只读存储器的 8 CMOS 微控制器,使用高密度、非易失存储技术制造,并且与 8OC51 引脚和指令系统完全兼容。主要性能:MCS-51 微控制器产品系列兼容。片内有 4KB 可在线重复编程的快闪擦写存储器存储数据保存时间为 10 年。宽工作电压范围:Vcc 可为 2.7V 6V 全静态工作;可从 OHz 至16MHz 程序存储器具有 3 级加密保护 128*8 位内部
        RAM 32 条可编程 I/0 线、两个 16 位定时器/计数器、中断结构具有 5 个中断源和 2 个优先级、可编程全双工串行通道、空闲状态维持低功耗和掉电状态保存存储内容。
        89C51 单片机是把那些作为控制应用所必需的基本内容都集成在一个尺寸有限的集成电路芯片上。如果按功能划分,它由如下功能部件组成,即微处理器、数据存储器、程序存储器、并行 I/0 口、串行口、定时器/计数器、中断系统及特殊功能寄存器。它们都是通过片内单一总线连接而成,其基本结构依旧是 CPU加上外围芯片的传统结构模式。但对各种功能部件的控制是采用特殊功能寄存器的集中控制方式。
        微处理器、数据存储器、程序存储器、并行 I/0 口、串行口、定时器/计数器、中断系统各部分功能及说明类似于 8051 单片机内部结构说明。特殊功能寄存器共有 21 个,用于对片内的各功能的部件进行管理、控制、监视。实际上是一些控制寄存器和状态寄存器,是一个具有特殊功能的 RAM 区。
        由上可见,89C51 单片机的硬件结构具有功能部件种类全,功能强等特点。特别值得一提的是该单片机 CPU 中的位处理器,它实际上是一个完整的 1 位微计算机,这个 1 位微计算机有自己的 CPU、位寄存器、I/0 口和指令集。1 位机在开关决策、逻辑电路仿真、过程控制方面非常有效;8 位机在数据采集,运算处理方面有明显的长处。MCS-51 单片机中 8 位机和 1 位机的硬件资源复合在一起,二者相辅相承,它是单片机技术上的一个突破,这也是 MCS-51 单片机设
计的精美之处。
        图 3-2 是标准的 40 引脚双列直插式集成电路芯片。

3-2 AT89C51 引脚图 

        (1)引脚说明:
        PO0-PO7 PO 口 8 位双向口线(在引脚的 39-32 号端子)P10-P17 P1 8 位双向口线(在引脚的 1-8 号端子)P20-P27 P2 8 位双向口线(在引脚的 21-28号端子)P30-P37 P3 8 位双向口线(在引脚的 10-17 号端子)
        (2)PO 口三个功能:
        1)外部扩展存储器时,用作数据总线(如图中的 DO-D7 为数据总线接口)
        2)外部扩展存储器时,用作地址总线(如图中的 AO-A7 为地址总线接口>
        3)不扩展时,可做一般的 I/0 口使用,但内部无上拉电阻,作为输入或输出时应在外部接上拉电阻。
        (3)P1 口功能:P1 口只做 I/0 口使用,其内部有上拉电阻。
        (4)P2 口有两个功能:(⑴扩展外部存储器时,当作地址总线使用:(2)做一般 I/0口使用,其内部有上拉电阻。
        (5)P3 口的两个功能:
        除了作为 I/0 口使用外(其内部有上拉电阻),还有一些特殊功能,由特殊寄存器来设置。当作为输入时,上拉电阻将其电位拉高,若输入为低电平则可提供电流源;所以如果 PO 口作为输入时,处在高阻抗状态,只有外接一个上拉电阻才能有效。
        (6)ALE/PROG 地址锁存控制信号:
在系统扩展时,ALE 用于控制把 PO 口的输出低 8 位地址送锁存器锁存起来,以实现低位地址和数据的隔离。PROG 为编程脉冲的输入端,在 89C51 单片机内部有一个 4KB 的程序存储器(ROM)ROM 的作用就是用来存放用户需要执行的程序的,那么我们是怎样把编写好的程序存入进这个 ROM 中的呢?实际上是通过编程脉冲输入才能写进去的,这个脉冲的输入端口就是 PROG
        (7)PSEN 外部程序存储器读选通信号:
在读外部 ROM PSEN 低电平有效,以实现外部 ROM 单元的读操作:1)内部 ROM 读取时,PSEN 不动作;
        2)外部 ROM 读取时,在每个机器周期会动作两次:
        3)外部 RAM 读取时,两个 PSEN 脉冲被跳过不会输出;4)外接 ROM 时,与 ROM EA 脚相接。
        (8)EA/VPP 访问程序存储器控制信号:
        1)接高电平时:CPU 读取内部程序存储器(ROM) 2)接低电平时:CPU 读取外部程序存储器(ROM)。8031 单片机内部是没有ROM 的,那么在应用 8031 单片机时,这个脚是一直接低电平的。
        (9) RST 复位信号:
当输入的信号连续 2 个机器周期以上高电平时即为有效,用以完成单片机的复位初始化操作,当复位后程序计数器 PC=000OH,即复位后将从程序存储器的000OH 单元读取第一条指令码。
        
        (10) XTAL1 XTAL2 :
        外接晶振引脚。当使用芯片内部时钟时,此二引脚用于外接石英晶体和微调电容:当使用外部时钟时,用于接外部时钟脉冲信号。
        (11) VCC:电源端接+5V 电压输入。
        (12)GND:接地端。

3.2.2 晶振电路设计

        下图所示为时钟电路原理图,在 AT89C51 芯片内部有一个高增益反相放大器,其输入端为芯片引脚 XTAL1,输出端为引脚 XTAL2。而在芯片内部,XTAL1和 XTAL2 之间跨接晶体振荡器和微调电容,从而构成一个稳定的自激振荡器。时钟电路产生的振荡脉冲经过触发器进行二分频之后,才成为单片机的时钟脉冲信号。
        单片机 XTAL1 XTAL2 分别接 33pF 的电容,中间再并一个 11.0592MHZ的晶振,形成单片机的晶振电路。

 3-3 晶振电路

3.2.3 复位电路设计

        AT89C51 的上电复位电路,只要在 RST 复位输入引脚上接一电容至 Vcc 端,下接一个电阻到地即可。对于 CMOS 型单片机,由于在 RST 端内部有一个下拉电阻,故可将外部电阻去掉,而将外接电容减至 1UF。上电复位的工作过程是在加电时,复位电路通过电容加给 RST 端一个短暂的高电平信号,此高电平信号随着 Vcc 对电容的充电过程而逐渐回落,即 RST 端的高电平持续时间取决于电容的充电时间。为了保证系统能够可靠地复位,RST 端的高电平信号必须维持足够长的时间。上电时,Vcc 的上升时间约为 10ms,而振荡器的起振时间取决于振荡频率,如晶振频率为 10MHz,起振时间为 1ms:晶振频率为 1MHz,起振时间则为 10ms。在图 3-2 的复位电路中,当 Vcc 掉电时,必然会使 RST 端电压迅速下降到 OV 以下,但是,由于内部电路的限制作用,这个负电压将不会对器件产生损害。另外,在复位期间,端口引脚处于随机状态,复位后,系统将端口置为全“l”态。如果系统在上电时得不到有效的复位,则程序计数器 PC 将得不到一个合适的初值,因此,CPU 可能会从一个未被定义的位置开始执行程序。

3-4 复位电路 

3.2.4 LED 数码管显示

        数码管是一种把多个 LED 显示段集成在一起的显示设备。有两种类型,一种是共阳型,一种是共阴型。共阳型就是把多个 LED 显示段的阳极接在一起,又称为公共端。共阴型就是把多个 LED 显示段的阴极接在一起,即为公共商。阳极即为二极管的正极,又称为正极,阴极即为二极管的负极,又称为负极。通常的数码管又分为 8 段,即 8 LED 显示段,这是为工程应用方便如设计的,分别为 ABCDEFGDP,其中 DP 是小数点位段。而多位数码管,除某一位的公共端会连接在一起,不同位的数码管的相同端也会连接在一起。即,所有的 A 段都会连在一起,其它的段也是如此,这是实际最常用的用法。数码管显示方法可分为静态显示和动态显示两种。静态显示就是数码管的 8 段输入及其公共端电平一直有效。动态显示的原理是,各个数码管的相同段连接在一起,共同占用 8 位段引管线;每位数码管的阳极连在一起组成公共端。利用人眼的视觉暂留性,依次给出各个数码管公共端加有效信号,在此同时给出该数码管加有效的数据信号,当全段扫描速度大于视觉暂留速度时,显示就会清晰显示出来。
        系统采用动态显示方式,用 PO 口来控制 LED 数码管的段控线,而用 P2 口来控制其位控线。动态显示通常都是采用动态扫描的方法进行显示,即循环点亮每一个数码管,这样虽然在任何时刻都只有一位数码管被点亮,但由于人眼存在视觉残留效应,只要每位数码管间隔时间足够短,就可以给人以同时显示的感觉。

3-5 LED 数码管引脚图 

3.3 系统实现

3.3.1 系统仿真与调试

1Keil 软件编译
        Keil C51 是美国 Keil Software 公司出品的 51 系列兼容单片机 C 语言软件开发系统,与汇编相比,C 语言在功能上、结构性、可读性、可维护性上有明显的优势,Keil 提供了包括 C 编译器、宏汇编、连接器、库管理和一个功能强大的仿真调试器等在内的完整开发方案,通过一个集成开发环境(uVision)将这些部分组合在一起。如果使用 C 语言编程,那么 Keil 几乎就是不二之选,即使不使用C 语言而仅用汇编语言编程,其方便易用的集成环境、强大的软件仿真调试工具
也会令你事半功倍。本次设计采用汇编语言编程,生成.hex 文件以供装载到Protues 中的单片机进行仿真。
(2)Protues 仿真平台
        Protues 软件是英国 Labcenterelectronics 公司出版的 EDA 工具软件。它不仅具有其它 EDA 工具软件的仿真功能,还能仿真单片机及外围器件。它是目前最好的仿真单片机及外围器件的工具。Proteus 是世界上著名的 EDA 工具(仿真软件),从原理图布图、代码调试到单片机与外围电路协同仿真,一键切换到 PCB设计,真正实现了从概念到产品的完整设计。迄今为止是世界上唯一将电路仿真软件、PCB 设计软件和虚拟模型仿真软件三合一的设计平台,其处理器模型支持
        8051、HC11PIC10/12/16/18/24/30/DsPIC33AVRARM8086 MSP430等。在编译方面,它也支持 IARKeil MATLAB 等多种编译。
        目标代码的加载方法为,在 Protues 编辑环境双击 AT89C51,弹出下图所示的对话框,在 PROGRAM FILM 一栏中单击打开按钮,选中 Keil 中生成的 1zy.hex文件,CLOCKFREQUENCY 栏中设置系统工作频率为 11.0592MHZ,单击 OK完成目标代码的加载。

3-6 程序代码加载 

3.3.2 演示结果

       (1)时间显示:当时间达到整点前 10 秒,蜂鸣器鸣响,每隔一秒鸣响一次,鸣响 5 次后暂停,起到报时作用。

3-7 时间显示演示结果图 

        (2)时间校对:在那个时间级出现右下角小蓝点闪烁,就是在对那个时间级进行校对,通过“+”“-”按键对该时间级的时间调整,调整完毕按下设置建即可回复显示状态。

3-8 时间校对演示结果图 

        (3)60 秒倒计时:按下秒表键,系统开始 60 秒倒计时,按下秒表启停键,可以开启和暂停秒表,暂停后开启,秒表任然从暂停的时间开始倒计时;按下秒表清零键,秒表时间归位到 60

3-9 60 秒倒计时演示结果图 

4.总结

        经历过这么多天不间断的课程设计,我有很多感触,从最基本上说我看到了,也意识到了自己的不足,对于不断克服的各种阻碍也让我们体会到了课程设计的意义所在。本次课程设计学习的是利用 AT89C51 单片机设计的有调时、整点报时、60s 倒计时功能的电子钟,而且详细说明了软件和硬件设计方法及仿真、硬件实现。在设计过程中可以看出,汇编语言有着其独特的魅力,它简单易学,语法错误容易纠正:用单片机实现电子钟的设计是比较方便和易于实现的。
        对于只接触课本只动笔杆的我们,面临实际的设计尺寸,让我们很是尴尬,都说理论联系实际,真正到联系的时候才发现挺困难的,不过正是理论知识的各种补充才让我们能最终完成任务,然后深深地体会到理论对现实的指导作用。我们现在最缺乏的就是实际工作经验,而理论联系实践并不像我们想象的那么简单,他需要坚实的理论基础和实际工作经验。坚实的理论基础决定了我必须坚持学习新的知识新的理论,完善了自己的知识结构,才能在以后的实际中轻松面对,才能设计出更好的更有益于人们生活与工作的机械,才能跟上时代的步伐,不被淘汰。

        在这个一边边忙着复习忙着考试又要准备课程设计的日子里,真真正正的体会到了时间的宝贵,有点像高中忙忙碌碌的生活,不过能按时完成课程设计对我们来说也是一个莫大的安慰。.严谨和细心是做电子设计的必要态度,要想做好一件事,就必须一丝不苟、态度认真。俗话说:“失之毫厘, 谬之千里。”在设计上尤其应该注意。在以后的工作中,你的很小的一个疏忽将会造成一一个公司很大的损失,甚至给用户带去生命危险,而自已也会为自己的不负责任行为付出代价。再者就是设计中要严谨和细心,对于电子设计是不能出差错的,任何的微小误差都可能产生不可预计的后果,当然对于我们来说就是设计中要走一些弯路,而且在这个严重缺少时间又惦记回家问题的我们来说也是一个很严重的后果。不过,困难虽是难免的,但我们有信心就能并且已经战胜了困难,完成了这个无比揪心的课程设计。
        通过本次课程设计加深了我们对单片机的理解,能够更加熟练地应用单片机实现预期的功能,对以后的学习起到很大的促进作用。因为时间等各种关系设计中难免有些不足还请老师助教给予批评和帮助。

附录

附录 1

表 3-1 元器件清单

 

 

附录 2

程序清单。
#include <reg52.h>
#include <string.h>
#define uchar unsigned char
#define uint unsigned int
sbit key1=P3^2; //定义硬件引脚
sbit key2=P3^3;
sbit key3=P3^4;
sbit key4=P3^5;
sbit key5=P3^6;
sbit key6=P3^7;
sbit bz=P1^6;
sbit w1=P2^0;
sbit w2=P2^1;
sbit w3=P2^2;
sbit w4=P2^3;
sbit w5=P2^4;
sbit w6=P2^5;
#define all_off {P2=0X00;}
uint i,jihour,count,timer,count_ss;
uchar sec=52,min=59,hour=11,set,num,mb,count_mb;
bit flag_mb,flag_mb_run,flag_bs;
code uchar
shuma[11]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff}; //显示段码共阳数码管
//延时函数
void delay(uchar t)
{
uchar i,j;
for(i=0;i<t;i++)
{
for(j=14;j>0;j--);
}
}
void disp() //数码管显示函数
{
if(flag_mb) //显示秒表
{
all_off;P0=shuma[10];w1=1;delay(5); //无显示
all_off;P0=shuma[10];w2=1;delay(5);
all_off;P0=shuma[mb/10];w3=1;delay(5);//显示秒
all_off;P0=shuma[mb%10];w4=1;delay(5);
all_off;P0=shuma[count_mb/10];w5=1;delay(5); //百分秒
all_off;P0=shuma[count_mb%10];w6=1;delay(5);
}
else //显示 时间
{
all_off;P0=shuma[hour/10];w1=1;delay(5); //
all_off;if(set==1)P0=shuma[hour%10]&0x7f;else
P0=shuma[hour%10];w2=1;delay(5);
all_off;P0=shuma[min/10];w3=1;delay(5); //
all_off;if(set==2)P0=shuma[min%10]&0x7f;else
P0=shuma[min%10];w4=1;delay(5);
all_off;P0=shuma[sec/10];w5=1;delay(5); //
all_off;if(set==3)P0=shuma[sec%10]&0x7f;else
P0=shuma[sec%10];w6=1;delay(5);
}
}
void keyscan()
//按键扫描函数
{
if(!key1)
//检测按下
{
delay(10); //延时消抖动
if(!key1) //+
{
switch(set)
{
case 1:if(hour<23)hour++;break; //设置时
case 2:if(min<59)min++;break; //设置分
case 3:if(sec<59)sec++;break; //设置秒
default:break;
}
while(!key1){;}//检测松手
}
}
if(!key2)
//检测按下
{
delay(10); //延时消抖动
if(!key2) //-
{
switch(set)
{
case 1:if(hour>0)hour--;break; //设置时
case 2:if(min>0)min--;break; //设置分
case 3:if(sec>0)sec--;break; //设置秒
default:break;
}
if(flag_mb)flag_mb_run=!flag_mb_run;
while(!key2){;}//检测松手
}
}
if(!key3)
//检测按下
{
delay(10); //延时消抖动
if(!key3) //设置当前时间
{
set++;if(set==4)set=0;
if(set==0)TR0=1;else TR0=0;
while(!key3){;}//检测松手
}
}
if(!key4)
//检测按下
{
delay(10); //延时消抖动
if(!key4) //秒表
{
flag_mb=!flag_mb;count_mb=0;mb=60;
while(!key4){;}//检测松手
}
}
if(!key5)
//检测按下
delay(10); //延时消抖动
if(!key5) //秒表启动或停止
{
flag_mb_run=!flag_mb_run;
while(!key5){;}//检测松手
}
}
if(!key6)
//检测按下
{
delay(10); //延时消抖动
if(!key6) //秒表清零
{
count_mb=0;mb=60;
while(!key6){;}//检测松手
}
}
}
void main()
{
TMOD |= 0x01; //初始化定时器 0
TL0 = 0x00;
//设置定时初值
TH0 = 0xDC;
//设置定时初值 10MS @11.0592MHZ
EA=1;
ET0=1;
TR0=1;
while(1)
{
keyscan(); //按键扫描函数
disp();
if(min==59 && sec==50) //整点前 10
flag_bs=1; //报时
}
}
void Tim() interrupt 1
{
TL0 = 0x00;
//设置定时初值
TH0 = 0xDC;
//设置定时初值 10MS @11.0592MHZ
jihour++;
if(jihour==100) //1
{jihour=0;sec++;}
if(sec==60) //1 分钟
{sec=0;min++;}
if(min==60) //1 小时
{min=0;hour++;}
if(hour==24)
{hour=0;}
if(flag_mb&&flag_mb_run) //秒表
{
count_mb--;
if(count_mb==255) //1S
{
count_mb=99;
mb--;
if(mb==255){mb=flag_mb_run=0;count_mb=0;}
}
}
if(flag_bs) //蜂鸣器响
{
count_ss++;
if(count_ss==100) //1
{
bz=0; //蜂鸣器响
}
if(count_ss==200) //1
{
count_ss=0;
bz=1;
//蜂鸣器不响
num++;if(num==5){num=0;flag_bs=0;}
}
}
}