资源描述
基于ATs的多功能数字钟完整版
基于AT89s52的多功能数字钟
引言
单片机 (Single—Chip Microcomputer ),是 集 CPU ,RAM ,ROM ,定时,计数和多种接口于一体的微控制器。它体积小,成本低,功能强,广泛应用于工业自动化上和智能产品。
时钟,自从它被发明的那天起,就成为了人类的好朋友,但随着时间的推移,科学技术的不断发展,时钟的应用越来越广范,人们对时间计量的精度要求也越来越高。怎样让时钟更好的为人民服务,怎样让我们的老朋友再次焕发青春呢?这就要求我们不断设计出新型的时钟,来不断满足人们的日常生活需要。然而市场上的时钟便宜的比较笨重,简单实用的又比较昂贵。那么,有没有一款既简单实用价格又便宜的时钟呢?
我们设计小组设想:可不可以利用单片机功能集成化高,价格又便宜的特点设计一款结构既简单,价格又便宜,功能又强大的单片机电子时钟呢?
基于这种情况,我们课程设计小组成员多方查阅资料,反复论证设计出了这款集时钟显示、闹铃提醒和秒表功能于一体的单片机数字时钟。
【摘 要】本设计由数码管显示模块、单片机处理模块、闹铃提醒模块、按键控制模块和电源模块等组成。通过单片机软件运算方式进行时钟计时,外部获得的按键信息进行模式切换和控制,输出到信号数码管显示模块,从而控制数码管显示内容,实现时钟显示、闹铃提醒和秒表等功能。
【关键词】数字钟;AT89s52;PNP9012;数码管
【Abstract】The design consists ofthe digital display module, MCU processing module, alarm reminding module, key control module and power module and other components. Through the way MCU’s software operation to time ,external information on access to key data processing to mode changing and control, output signal to digital display module to control the digital display content, and then, realizing the clock display and alarm reminding and stopwatch, and other functions.
【Keywords】Dgital clock;AT89s52;PNP9012;nixietube
目录
目录3
一、 课程选题及设计目的4
1。 1课程选题及相关设计要求4
1.1.1课程题目4
1.1.2设计要求4
1.1.3本设计功能完成情况4
1.2课程设计目的5
1。3课程设计所用软件5
二、 硬件设计与实现6
2.1课题分析6
2.1.1元件选择6
2.1。2工作原理7
2。1.3系统的硬件构成及功能8
2.2由原理设计实际电路10
2.2.1抢答器实际电路图10
2.2。2 PCB图设计11
3。1软件功能需求12
3.2系统主程序设计12
4.1仿真电路设计19
4。2功能仿真结果19
4.2.1时间显示19
4.2。2 闹铃设定20
4。2。3时间设定20
4.2.4秒表使用20
附录
一、 课程选题及设计目的
1. 1课程选题及相关设计要求
1。1.1课程题目
基于AT89s52的多功能数字钟
1.1.2设计要求
1. 显示时间:用数码管显示 时:分,时间可用硬件调整。
2. 定时功能,可硬件调整(时分)定时,定时到驱动蜂鸣器(或LED)提示.
3。 计时功能:精确到0.1秒,结果在数码管显示.
4。 设计出相应电路并用protel出图。
5. 给出完整的汇编语言(或C语言)源程序。
1.1。3本设计功能完成情况
1. 显示时间:完整实现并自由发挥。用数码管显示,按照时—分-秒的格式显示,时间可用硬件调整,比照设计要求增加了秒显示功能。
2。 定时功能,完整实现。可硬件调整(时分)定时,定时到驱动蜂鸣器(或LED)提示,本设计采用了LED提示(亮1min)。
3. 计时功能:完整实现并自由发挥。精确到0.01秒,结果在数码管显示,比照设计要求秒表精度提高了10倍。
4。 设计出相应电路并用protel出图,完整实现.。
5. 给出完整的汇编语言(或C语言)源程序,完整实现。
6.仿真,此步骤为自行添加,用于验证了设计的可行性。
1。2课程设计目的
(1)学习使用protel设计电子线路原理图和PCB图的方法。
(2)学习使用protues仿真并调试电路及程序的方法。
(3)学习使用以AT89s52为核心设计外围电路及实现预期功能的思想和方法.
(4)学习查找电路所用元件封装方式的查找和自行制作的方法.
(5)学习使用Keil C设计相应程序实现硬件控制和功能的方法。
1.3课程设计所用软件
软件工具:
Altium Designer Summer 09、Protel 99用于设计电路原理图和PCB图。
Keil uVision4用于软件的编写、编译以及hex文件的生成.
Protues7。5用于软件的仿真。
二、 硬件设计与实现
2。1课题分析
2.1。1元件选择
本设计使用到的元器件包括:AT89s52芯片、数码管、PNP9012、电容、电阻、晶振、按键开关、。
AT89s52芯片是系统的核心,它主要负责控制各个部分的协调工作。选择该芯片的原因主要有以下几点:(1)该芯片在以前的电子设计中使用过一次,手头恰好有,便于节省课程设计资金。(2)内部资源丰富,功能强大,片上Flash允许程序存储器在系统可编程,亦适于常规编程器.(3)能工作在3.5~5。5V,其工作电压范围宽泛,便于使用.
在AT89s52芯片外围接上复位电路,外部时序电路、上拉电阻,数码管,按钮等外部设备,通过数码管、PNP9012搭配实现功能的显示。
P3。3为蜂鸣器(用LED代替)输出口,P0为数码管段选显示输出,P2为数码管位选显示输出,P3.0—P3。2为按键控制接口.
原件列表:
AT89s52
1片
四位共阳极数码管
2片
PNP9012三极管
8个
22μF电容
1个
30pF电容
2个
1KΏ电阻
12个
4.7KΏ电阻
8个
12M晶振
1个
导线、焊锡
若干
2.1。2工作原理
基于上述设计要求,根据功能要求,设计中除了必要的单片机复位和时序电路外,还需要有闹铃提醒电路、显示电路、按键控制电路等部分。各个电路都有其自己的功能。
电路进入就绪状态后,开始计时.
然后由按键控制进行模式切换和控制状态。在电路中P3。0-P3。2为按键控制部分的3个按键,P3.0对应模式切换功能,P3。1在时钟显示和闹铃模式下起到加1功能,P3。2在时钟显示和闹铃模式下起到减1功能,在秒表模式下起到控制秒表开始和暂停的功能。
P3.3为闹铃输出口,闹铃时间到,则该输出口置高,保持1min,使LED保持高亮达到闹铃提醒功能。
P0为数码管段选显示输出,同个8个口电平高低不同,控制单个数码管的显示,;P2为数码管位选显示输出,通过8个口的输出电平高低不同,控制相连的PNP9012的导通状态,从而控制共阳数码管的显示.
AT89s52的针脚定义如下:
2.1.3系统的硬件构成及功能
(1)抢答器的电路框图P3.0-3.2 P0口
单片机
P2口
数码管显示模块
外围驱动电路
电源模块
按键控制模块
闹铃提醒模块
复位电路及时序电路
抢答器电路功能框图
2.2由原理设计实际电路
2.2。1抢答器实际电路图
抢答器工作电路原理图
2.2.2 PCB图设计
(注明:因为沟通的原因,实际作出的PCB图未按照此图制作,而是制作了第一版设计的一个PCB,其中有错误,故在实际应用时,自行焊接了设计电路.)
三、电子线路软件设计与实现
3.1软件功能需求
为了能够计时准确,显示无闪烁,按键响应及时无抖动等功能需求,根据设计要求,可以得出相应的软件功能可分为以下部分:(1)初始化部分(2)显示部分(3)键盘扫描判断部分(4)数码管驱动部分(5)主程序(6)定时器计时设计
3.2系统主程序设计
基于以上软件需求,以及ATMega16L指令集特点,编写了如附录程序来实现逾期功能。
(1) 初始化部分.
#include <reg52。h>
sbit KEY1=P3^0;
sbit KEY2=P3^1;
sbit KEY3=P3^2;
sbit led=P3^3;
code unsigned char tab[]={0xc0,0xf9,0xa4,0xb0,0x99,
0x92,0x82,0xf8,0x80,0x90}; //共阴数码管 0-9
unsigned char StrTab[8]; //定义缓冲区
Unsigned
char minute=30,hour=12,second,msecond,miao,key1flag=0,key2flag=0; //定义并且初始化值 12:30:00
unsigned char keytemp1=0,keytemp2=0,clockhor=0,clockmin=0,clocksec=0,clockflag,keycount,keyflag1,t;
(2) 显示部分。
void Displaypro(void)
{ StrTab[0]=tab[hour/10]; //显示正常时间
StrTab[1]=tab[hour%10];
StrTab[2]=0xbf;
StrTab[3]=tab[minute/10];
StrTab[4]=tab[minute%10];
StrTab[5]=0xbf;
StrTab[6]=tab[second/10];
StrTab[7]=tab[second%10];
}
void displaymiao()
{ StrTab[6]=tab[msecond/10]; //显示秒表时间
StrTab[7]=tab[msecond%10];
StrTab[2]=0xbf;
StrTab[3]=tab[miao/10];
StrTab[4]=tab[miao%10];
StrTab[5]=0xbf;
StrTab[0]=tab[0];
StrTab[1]=tab[0];
}
void timing(void)
{ StrTab[0]=tab[hour/10]; //显示正常时间
StrTab[1]=tab[hour%10];
StrTab[2]=0xff;
StrTab[3]=tab[minute/10];
StrTab[4]=tab[minute%10];
StrTab[5]=0xff;
StrTab[6]=tab[second/10];
StrTab[7]=tab[second%10];
}
void clock(void)
{ StrTab[0]=tab[clockhor/10]; //显示闹铃时间
StrTab[1]=tab[clockhor%10];
StrTab[2]=0x7f;
StrTab[3]=tab[clockmin/10];
StrTab[4]=tab[clockmin%10];
StrTab[5]=0x7f;
StrTab[6]=tab[clocksec/10];
StrTab[7]=tab[clocksec%10];
}
void zero (void)
{ StrTab[0]=tab[0]; //显示零时间
StrTab[1]=tab[0];
StrTab[2]=0xbf;
StrTab[3]=tab[0];
StrTab[4]=tab[0];
StrTab[5]=0xbf;
StrTab[6]=tab[0];
StrTab[7]=tab[0];
}
(3) 键盘扫描判断部分.
void keyjudge() //模式切换键扫描
{ keyflag1=0;
delay(1000);
if(keyflag1=1)
{if(key1flag〈=4)
{key1flag++;}
if(key1flag>=4)
{key1flag=0;}
}
keyflag1=0;
}
(4) 数码管驱动部分。
void time1_isr(void) interrupt 3 using 0//定时器1用来动态扫描
{ static unsigned char num;
TH1=0xf8;//重入初值
TL1=0xf0;
switch (num){
case 0:P2=0xfe;P0=StrTab[num];break; //分别调用缓冲区的值进行扫描
case 1:P2=0xfd;P0=StrTab[num];break;
case 2:P2=0xfb;P0=StrTab[num];break;
case 3:P2=0xf7;P0=StrTab[num];break;
case 4:P2=0xef;P0=StrTab[num];break;
case 5:P2=0xdf;P0=StrTab[num];break;
case 6:P2=0xbf;P0=StrTab[num];break;
case 7:P2=0x7f;P0=StrTab[num];break;
default:break;
}
num++; //扫描8次,使用8个数码管
if(num==8)
num=0;
}
(5) 延时程序。
void delay(unsigned int cnt)//延时函数
{
while(--cnt);
}
(6) 主程序。
main()//主函数
{ TMOD |=0x01;//定时器0 用于计时
TH0=0xd8;
TL0=0xf0;
ET0=1;
TR0=1;
TMOD |=0x10; //定时器1用于动态扫描
TH1=0xF8;
TL1=0xf0;
ET1=1;
TR1=1;
EA =1;
EX0=1;
IT0=1;
t=0;
Displaypro();
while(1)//主循环
{
while((key1flag==0))
{Displaypro();
}
while((key1flag==1))
{zero();
if(!KEY3) //按键去抖以及动作
{
delay(10000);
if(!KEY3)
{
msecond=0;miao=0;
}
while((key1flag==1))
{displaymiao();}
}
}
while((key1flag==2))
{ timing();
if(key2flag==0)
{ if(!KEY3) //按键去抖以及动作
{ delay(10000);
if(!KEY3)
{
minute++;if(minute==59)minute=0;//分加1
timing();
}
}
}
if(key2flag==1)
{
if(!KEY3) //按键去抖以及动作
{ delay(10000);
if(!KEY3)
{ hour++;if(hour==24)hour=0; //分减1
timing();
}
}
}
timing();
}
while((key1flag==3))
{ clock();
if(key2flag==0)
{ if(!KEY3) //按键去抖以及动作
{
delay(10000);
if(!KEY3)
{
clockmin++;if(clockmin==59)clockmin=0;//分加1
clock();
}
}
}
if(key2flag==1)
{ if(!KEY3) //按键去抖以及动作
{
delay(10000);
if(!KEY3)
{
clockhor++;if(clockhor==24)clockhor=0; //分减1
clock();
}
}
} clock();
}
}
}
////////////////////////////////////////////////////////////////
void inter() interrupt 0
{
if (key1flag==1)
{if (t==0)
{t=1;}
else t=0;
}
}
(7) 闹铃响应设计
if( (hour==clockhor)&&(minute==clockmin) )
{clockflag=1;}
else {clockflag=0;}
if( clockflag==1 )
{led=1;}
else{led=0;}
(8) 秒表设计
void tim(void) interrupt 1 using 1
{
static unsigned int count;//定义内部静态变量
TH0=0xf8;//重新赋值
TL0=0x30;
count++;
keycount++;
if(!KEY1)
{
keyflag1=1;
keyjudge();
}
if(!KEY2)
{
if(key2flag〈=2)
{key2flag++;}
if(key2flag>=2)
{key2flag=0;}
}
if((count%5)==0)
{
if (t==1)
msecond++;
if (msecond==100)
{
msecond=0;
miao++;//秒加1
if(miao==100)
miao=0;
}
}
(9)走时设计
if (count==500)
{
count=0;
second++;//秒加1
if(second==60)
{
second=0;
minute++; //分加1
if(minute==60)
{
minute=0;
hour++; //时加1
if(hour==24)
hour=0;
}
}
}
}
四、系统功能仿真
4.1仿真电路设计
因为使用Protues7.5进行电路仿真时,默认单片机正常工作同时电路驱动能力无限大,因此可以省略掉复位和时序电路以及三极管驱动部分,仿真电路图设计如下:
4。2功能仿真结果
4。2.1时间显示
4。2.2 闹铃设定
4。2.3时间设定
4。2.4秒表使用
附录:完整程序设计
#include 〈reg52.h〉
sbit KEY1=P3^0;
sbit KEY2=P3^1;
sbit KEY3=P3^2;
sbit led=P3^3;
code unsigned char tab[]={0xc0,0xf9,0xa4,0xb0,0x99,
0x92,0x82,0xf8,0x80,0x90};
//共阴数码管 0-9
unsigned char StrTab[8]; //定义缓冲区
unsigned char minute=30,hour=12,second,msecond,miao,key1flag=0,key2flag=0; //定义并且初始化值 12:30:00
unsigned char keytemp1=0,keytemp2=0,clockhor=0,clockmin=0,clocksec=0,clockflag,keycount,keyflag1,t;
void delay(unsigned int cnt)//延时函数
{
while(-—cnt);
}
void Displaypro(void)
{
StrTab[0]=tab[hour/10]; //显示正常时间
StrTab[1]=tab[hour%10];
StrTab[2]=0xbf;
StrTab[3]=tab[minute/10];
StrTab[4]=tab[minute%10];
StrTab[5]=0xbf;
StrTab[6]=tab[second/10];
StrTab[7]=tab[second%10];
}
void displaymiao()
{
StrTab[6]=tab[msecond/10]; //显示秒表时间
StrTab[7]=tab[msecond%10];
StrTab[2]=0xbf;
StrTab[3]=tab[miao/10];
StrTab[4]=tab[miao%10];
StrTab[5]=0xbf;
StrTab[0]=tab[0];
StrTab[1]=tab[0];
}
void timing(void)
{
StrTab[0]=tab[hour/10]; //显示正常时间
StrTab[1]=tab[hour%10];
StrTab[2]=0xff;
StrTab[3]=tab[minute/10];
StrTab[4]=tab[minute%10];
StrTab[5]=0xff;
StrTab[6]=tab[second/10];
StrTab[7]=tab[second%10];
}
void clock(void)
{
StrTab[0]=tab[clockhor/10]; //显示闹铃时间
StrTab[1]=tab[clockhor%10];
StrTab[2]=0x7f;
StrTab[3]=tab[clockmin/10];
StrTab[4]=tab[clockmin%10];
StrTab[5]=0x7f;
StrTab[6]=tab[clocksec/10];
StrTab[7]=tab[clocksec%10];
}
void zero (void)
{
StrTab[0]=tab[0]; //显示零时间
StrTab[1]=tab[0];
StrTab[2]=0xbf;
StrTab[3]=tab[0];
StrTab[4]=tab[0];
StrTab[5]=0xbf;
StrTab[6]=tab[0];
StrTab[7]=tab[0];
}
void keyjudge()
{ keyflag1=0;
delay(1000);
if(keyflag1=1)
{if(key1flag<=4)
{key1flag++;}
if(key1flag〉=4)
{key1flag=0;}
}
keyflag1=0;
}
main()//主函数
{
TMOD |=0x01;//定时器0 用于计时
TH0=0xd8;
TL0=0xf0;
ET0=1;
TR0=1;
TMOD |=0x10; //定时器1用于动态扫描
TH1=0xF8;
TL1=0xf0;
ET1=1;
TR1=1;
EA =1;
EX0=1;
IT0=1;
t=0;
Displaypro();
while(1)//主循环
{
while((key1flag==0))
{Displaypro();
}
while((key1flag==1))
{zero();
if(!KEY3) //按键去抖以及动作
{
delay(10000);
if(!KEY3)
{
msecond=0;miao=0;
}
while((key1flag==1))
{displaymiao();}
}
}
while((key1flag==2))
{ timing();
if(key2flag==0)
{ if(!KEY3) //按键去抖以及动作
{
delay(10000);
if(!KEY3)
{
minute++;if(minute==59)minute=0;//分加1
timing();
}
}
}
if(key2flag==1)
{
if(!KEY3) //按键去抖以及动作
{
delay(10000);
if(!KEY3)
{
hour++;if(hour==24)hour=0; //分减1
timing();
}
}
}
timing();
}
while((key1flag==3))
{ clock();
if(key2flag==0)
{ if(!KEY3) //按键去抖以及动作
{
delay(10000);
if(!KEY3)
{
clockmin++;if(clockmin==59)clockmin=0;//分加1
clock();
}
}
}
if(key2flag==1)
{ if(!KEY3) //按键去抖以及动作
{
delay(10000);
if(!KEY3)
{
clockhor++;if(clockhor==24)clockhor=0; //分减1
clock();
}
}
} clock();
}
}
}
////////////////////////////////////////////////////////////////
void inter() interrupt 0
{
if (key1flag==1)
{
if (t==0)
{t=1;}
else t=0;
}
}
/********************************/
/* 定时中断1 */
/********************************/
void time1_isr(void) interrupt 3 using 0//定时器1用来动态扫描
{
static unsigned char num;
TH1=0xf8;//重入初值
TL1=0xf0;
if( (hour==clockhor)&&(minute==clockmin) )
{clockflag=1;}
else {clockflag=0;}
if( clockflag==1 )
{led=1;}
else{led=0;}
switch (num){
case 0:P2=0xfe;P0=StrTab[num];break; //分别调用缓冲区的值进行扫描
case 1:P2=0xfd;P0=StrTab[num];break;
case 2:P2=0xfb;P0=StrTab[num];break;
case 3:P2=0xf7;P0=StrTab[num];break;
case 4:P2=0xef;P0=StrTab[num];break;
case 5:P2=0xdf;P0=StrTab[num];break;
case 6:P2=0xbf;P0=StrTab[num];break;
case 7:P2=0x7f;P0=StrTab[num];break;
default:break;
}
num++; //扫描8次,使用8个数码管
if(num==8)
num=0;
}
//////////////////////////////////////////////////////////////////
/********************************/
/* 定时中断0 */
/********************************/
void tim(void) interrupt 1 using 1
{
static unsigned int count;//定义内部静态变量
TH0=0xf8;//重新赋值
TL0=0x30;
count++;
keycount++;
if(!KEY1)
{
keyflag1=1;
keyjudge();
}
if(!KEY2)
{
if(key2flag<=2)
{key2flag++;}
if(key2flag>=2)
{key2flag=0;}
}
if((count%5)==0)
{
if (t==1)
msecond++;
if (msecond==100)
{
msecond=0;
miao++;//秒加1
if(miao==100)
miao=0;
}
}
if (count==500)
{
count=0;
second++;//秒加1
if(second==60)
{
second=0;
minute++; //分加1
if(minute==60)
{
minute=0;
hour++; //时加1
if(hour==24)
hour=0;
}
}
}
}
展开阅读全文