搜索
您的当前位置:首页正文

基于单片机AT89S52控制的数字时钟系统

2023-03-25 来源:独旅网
基于单片机AT89S52控制的数字时钟系统

【摘 要】 本系统的设计电路是以AT89S52单片机为核心控制器,其外围电路主要包括键盘模块、LED显示模块。这种电子钟不仅具有了一般电子钟的基本功能,并且具有以下功能:闹钟时间设置,显示年月日等一系列功能。其中利用单片机中断系统,实现时间的计时功能。通过键盘和LED提示可方便地校对时钟和设置闹钟时间,完成年月日调整等功能。整个系统使用单片机S52语言进行编程,实现其设计的各项功能。

引言…………………………………………………………………………… 3 1、方案论证与比较……………………………………………………………4 1.1显示模块…………………………………………………………………… 4 1.2控制电路模块 ……………………………………………………………… 4 1.3键盘模块…………………………………………………………………… 4 1.4程序编写语言选择……………………………………………………………4 2、数字时钟系统的工作原理…………………………………………………5 3、数字时钟硬件系统设计……………………………………………………5 3.1时钟、复位、键盘接口电路 …………………………………………………………6 3.2显示器接口电路……………………………………………………………………… 6 4、系统软件部分………………………………………………………………8 4.1开发软件及编程语言简介……………………………………………………………8 4.2程序流程图……………………………………………………………………………8 5、功能说明……………………………………………………………………12 6、测试方法及结论……………………………………………………………12 结束语……………………………………………………………………………12 致谢词……………………………………………………………………………12 参考文献…………………………………………………………………………13

引言

数字时钟已成为人们日常生活中必不可少的物品,广泛用于个人家庭以及车站、码头、剧院、办公室等公共场所,给人们的生活、学习、工作、娱乐带来极大的方便。随着技术的发展,人们已不再满足于钟表原先简单的报时功能,希望出现一些新的功能,诸如日历的显示、跑表功能、重要日期倒计时显示等,以带来更大的方便,而所有这些,又都是以数字化的电子时钟为基础的。因此,研究实用电子

[1]

钟及其扩展应用,有着非常现实的意义,具有很大的实用价值。

由于数字集成电路技术的发展和采用了先进的石英技术,使电子钟具有走时准确、性能稳定、携带方便等优点,它还用于计时、自动报时及自动控制等各个领域。虽然现在市场上已有现成的电子钟集成电路芯片出售,价格便宜,使用也灵活,如可以随意设置时、分、秒的输出,改变显示数字的大小等,并且由于集成电路技术的发展,特别是MOS集成电路技术的发展,使电子钟具有体积小、携带方便,但是这里介绍的实用电子钟可以满足使用者的一些特殊要求,输出方式灵活、功耗低、计时准确、性能稳定、维护方便等优点。

1

1、方案论证与比较

1.1显示模块

方案一:采用LED静态显示方式。用此方式编写程序相对比较简单,一旦将欲显示的数据发送出

去,只要当前显示的数据没有变化,就无须理睬数码管显示器,这就是静态数码管显示的好处。但本设计显示的位数比较多,若用此方案则会使硬件的开销多,耗电量大。

方案二:采用LED动态显示方式。此方式可以大幅度地降低硬件成本和电源的功耗,因为某一时刻只有一个数码管工作,也就是所谓的分时显示,故显示所需要的硬件电路可分时复用。本设计即基于

[5]

这种思想而采用动态数码管显示。

1.2控制电路模块

方案一: 纯硬件电路系统。各功能采用分离的硬件电路模块实现。用时序逻辑电路实现时钟功能,用555定时器实现闹钟的设定。但这种实现方法可靠性差、控制精度低,灵活性小、线路复杂、安装调试不方便,而且不方便实现对系统的扩展。

方案二: 用可编程逻辑器件(PLD)实现。这种方案与前一种相比,可靠性增加,同时可以很好的完成时钟的功能。但采用这种方案系统的灵活性不够,不利于各种功能的扩展。

方案三:采用AT89S52单片机作为系统的控制核心。由于使用了单片机,整个系统可编程,系统

[7][9]

的灵活性、可靠性大大增加了,单片机还可进行软件抗干扰功能。另外,本方案可以方便的实现其他功能的扩展。

经过以上的比较论证,选用方案三来完成项目设计的要求。

1.3键盘模块

方案一:采用阵列式键盘,此类键盘是采用行列扫描方式,优点是当按键较多时可以降低占用单片

[2]

机的I/O口数目,缺点是电路复杂且会加大编程难度。

方案二:采用独立式按键电路,每个键单独占有一根I/O接口线,每个I/O口的工作状态互不影响,此类键盘采用端口直接扫描方式。缺点是当按键较多时占用单片机的I/O数目较多,优点是电路设计简

[3]

单,且编程极其容易。

由于该系统采用了常规钟表式的校对方式,用键较少,系统资源足够用,故采用了方案二。

1.4程序编写语言选择

方案一:采用汇编语言编写。汇编语言具有能够直接操作机器硬件、指令的执行速度快,但由于

汇编语言不是结构化的程序设计语言,用它编写的程序可读性较差,不便于资料的交流和移植,调试也

[4]

比较麻烦。

方案二:采用S52语言编写。在单片机开发应用中引用S52语言可以使单片机有很好的移植性,应用S52语言编写系统软件不仅大大缩短开发周期、增加程序的可读性,而且便于修改和扩充。且S52语言编译器可以自动完成变量的存储单元分配,编程者可以专注于应用软件部分的设计,从而大大加快

[10]

了开发速度。所以本设计程序编写语言采用S52语言。

2、数字时钟系统的工作原理

数字时钟的设计有多种方法,本设计采用单片机技术。数字时钟设计的关键是如何产生秒的时间

基准。本设计利用了单片机的定时器/计数器和中断系统,通过软件计数的方法,获得了秒的时间基准。具体方法如下:单片机晶振频率fosc=6MHZ,设定定时器/计数器0的工作方式为工作方式1,软件控制定时器/计数器0的运行、停止,定时时间100ms,则定时器/计数器0溢出中断10次即可得到1秒的时间基准,前0.5秒时使显示秒的发光二极管暗,后0.5秒时使显示秒的发光二极管亮,定时器/计数

2

器0计数初值X应满足(2-X)*2=100000us,X=15536(十进制),3CB0(十六进制)。定时器/计数器0采用中断控制方式,溢出次数在定时器/计数器0的中断服务程序中,通过软件计数器累计,累计次数满10次,则表明产生了1秒的时间基准。另外,时钟从秒到分、分到时、时到日期的计时是通过累加和数值比较实现的。

数字时钟的显示器采用LED数码管显示器,由7个LED数码管组成,从左至右依次显示为时/年(十位、个位)、分/月(十位、个位)、秒/日(十位、个位)、星期,同时秒的显示也由两个串接的发光二极管闪烁表示。数字时钟的键盘由5个按键构成(系统复位键除外)。一个按键作功能键,用于控制时钟的运行显示、调整状态,一个按键用与闹铃的开关,其它三个按键用于调整数字时钟的时/年、分/月、星期/日的值。

16

3、数字时钟硬件系统设计

数字时钟硬件系统的设计,关键是其键盘、显示器接口电路的设计,本设计采用直接利用单片机AT89S52的并行I/O口构成数字钟的键盘、显示接口电路,其硬件系统原理图如图3-1所示,主要包括单片机、时钟电路、复位电路、键盘及显示接口电路。

时钟电路 复位电路

3.1时钟、复位、键盘接口电路

单 片 机 图3-1 硬件系统原理

驱动电路 LED显示器 键 盘

如图3-2所示,时钟电路由片外石英晶振、微调电容与片内相应电路组成。石英晶振Y1的振荡频率fosc=6MHZ,微调电容C6、C7一般取20pF。复位电路具有上电复位和按键复位两种复位功能。电解电容C5一般取10uF,电阻R30、R31分别取200Ω、2KΩ。

数字时钟的键盘采用独立式键盘结构,由5个按键组成(复位键除外)。S0键为数字时钟功能键,接至P1.0,用于改变数字钟的工作状态;S1键为调时/年键,S2键为调分/月键,S3键为调星期/日键,它们分别接至P1.1、P1.2、P1.3;S4键为闹铃开关键,用函数表达式S=(S+1)%2来判断闹铃的开和

3

关,按下S4键若S值为1则闹铃处于开状态,再按下S4键若S值为0则闹铃处于关状态。R20—R24是上拉电阻,这里取10K。

图3-2 时钟、复位、键盘接口电路

3.2显示器接口电路

数字时钟的显示器由7位LED共阳极数码管和两个串接的发光二极管组成。两个串接的发光二极管的闪烁用来表示秒的跳动,7位LED共阳极数码管从左到右依次显示时/年、分/月、秒/日、星期的信息,具体电路如图3-3所示。该显示器以动态显示的方式工作,单片机的P0口作LED显示器的段控口,其口线(P0.7—P0.0)经过74LS244接至每位LED数码管的dp—a端,提供段控码信息;单片机的P2口作LED显示器的位控口,其口线(P2.7—P2.1)经过74LS244分别接至LED数码管LED7—LED1的

[6]

公共端C7—C1,提供位控码信息。74LS244为同相驱动器,在此提高P0、P2口的驱动能力,R10—R16为限流电阻,用于保护LED数码管。

4

图3-3 显示器接口电路

4、系统软件部分

4.1开发软件及编程语言简介

5

数字时钟的程序设计语言采用C语言。以往,人们研制单片机应用系统,几乎都是使用汇编语言编

写应用程序。尽管汇编语言具有能够直接操作机器硬件、指令的执行速度快等优点,但由于汇编语言不是结构化的程序设计语言,用它编写的程序可读性较差,不便于资料的交流和移植,调试也比较麻烦。而C语言恰好克服了汇编语言的缺点,而且又具有汇编语言的优点。开发软件采用美国Keil Software

[8]

公司出品的52系列兼容单片机Keil S52语言软件开发系统。

4.2程序流程图

为实现系统功能,系统软件共设三个运行状态和一个中断处理程序。数字钟的软件系统主要包括系统监控程序、键功能程序、定时器/计数器0的中断服务程序、显示子程序、闹铃子程序以及键盘扫描子程序等。

(1)监控程序 数字时钟的监控程序main()主要完成数字钟的初始化、时钟的显示以及键盘的管理工作,其程序设计流程图如图4-1所示。

开 始 数字初始化 调用走时转换子程序 调用键盘扫描子程序 调用闹铃子程序 结 束 图4-1 监控程序流程图 (2)键盘扫描子程序 键盘扫描子程序KEY用于完成按键的判断、按键的去抖动以及按键键值的处理,其中调用了显示子程序scan(),按键的释放在各键的键功能程序中处理,其流程图如图4-2所示。

6

图4-2 键盘扫描程序流程图

(3)显示子程序 显示子程序scan()用于完成时间信息及年、月、日期信息的显示,采用动

态扫描的方法从左至右进行,显示信息的字型代码通过查表获得。为了能够稳定显示时钟的相关信息,在每次送出段控码和位控码信息后,延时2ms的时间,其流程图如图4-3所示。

7

图4-3 显示子程序流程图

(4)闹铃子程序 时间值与闹钟设置值比较,若定时到,则进入闹铃状态。 (5)定时器/计数器0的中断服务程序 中断服务程序用于完成定时器/计数器0溢出中断次数的计数,时间秒、分、时的累加、比较、清0、进位操作,其流程图如图4-4所示。

8

图4-4 定时器/计数器0的中断服务程序流程图

9

5、功能说明

通电后即显示预设时间及星期。按功能键key0一次后,指示灯L1亮,其功能为对时间和星期进

行调节:再按key1键调节小时,按key2键调节分钟,按key3键调节星期。按功能键key0两次后,指示灯L2亮,其功能为显示日历并可对其进行调节:再按key1键调节年,按key2键调节月,按key3键调节日。按功能键key0三次后,指示灯L3亮,其功能为显示闹铃时间并可对其进行调节:再按key1键调节闹铃小时,按key2键调节闹铃分钟,按key3键调节闹铃秒。若再按key0键则又回到显示正常时间状态。Key4键为闹铃开关键,按下若指示灯L4亮,表示闹铃开;反之,则表示闹铃关。

6、测试方法及结论

采用先分别调试各单元模块,调通后再进行整机调试的方法,以提高调试效率。

时钟测试 在带有单片机的电路板上编程调试时钟,使其在数码管上显示,并可以通过键盘控制设定实时时间、日历和闹铃时间。利用仿真机调试成功后通过编程器将程序写入芯片中调试。

闹钟测试 通过键盘控制设定闹钟开关和闹钟响的时间,并通过单片机程序驱动发光二极管闪烁。 测试数据表(1): 次数 1 2 3 4 5 测试时间 时钟时间 1000秒 1000秒 1000秒 1000秒 1000秒 1000秒 1000秒 1000秒 1000秒 1000秒 测试数据表(2): 次数 1 测试时间 时钟时间 24小时 23时59分 59秒 2 24小时 23时59分 58秒 3 24小时 23时59分 58秒 4 24小时 23时59分 59秒 5 24小时 23时59分 59秒 测量误差分析:由于各元器件精度不同,使数字钟产生误差,但都在误差允许范围内,符合要求。

结束语

本系统以AT89S52为控制部件,利用S52语言编程,通过键盘控制和LED数码管显示实现了时间、日历和闹钟功能。它性能稳定,价格低廉,有很好的性价比,有利于工厂的大规模生产。

附录1 主要元器件清单

序号 1 2 3 4 5 名称、型号及规格 电阻 RJ14-0.25W-10KΩ±5% 电阻 RJ14-0.25W-330Ω±5% 电阻 RJ14-0.25W-240Ω±5% 电阻 RJ14-2W-180Ω±5% 电阻 RJ14-0.25W-560Ω±5% 数量 6 4 1 1 9 备注 10

6 7 8 9 10 11 12 13 14 15 16 电阻 RJ14-0.25W-47KΩ±5% 瓷片电容-30pF 电解电容-100uF/25V 电解电容-10uF/25V 单片机AT89S52 74ls244 发光二极管 按键 石英晶体振荡器-6M 共阴级8段数码显示管-5101AG-N3 腐蚀板-14.55*9.3 1 1 1 1 1 2 7 6 1 7 1

附录2:

/*数字时钟:

采用7位LED软件译码动态显示,P0为字段码,P2为位选码,数码管共阴; key0为功能键,key1、key2、key3为调节键,key4为闹铃开关键。*/

#include #include sbit key0=P1^0; sbit key1=P1^1; sbit key2=P1^2; sbit key3=P1^3; sbit P1_4=P1^4; sbit P1_5=P1^5; sbit P1_6=P1^6; sbit P1_7=P1^7; sbit P3_0=P3^0;

11

sbit P3_1=P3^1; sbit P3_7=P3^7;

unsigned char code dispcode[]={0x3f,0x06,0x5b,0x4f,

0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,

0x39,0x5e,0x79,0x71,0x00}; unsigned char dispbitcode[]={0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; unsigned char dispbuf[7];

unsigned char dispbuf0[7]={7,0,2,0,5,2,1}; //时间缓存 unsigned char dispbuf1[7]={7,1,0,4,0,7,0}; //年月缓存 unsigned char dispbuf2[7]={7,0,0,1,0,2,1}; //闹铃时间缓存 unsigned char dispbitcnt; unsigned char second=20; unsigned char minite=50; unsigned char hour=12; unsigned char day=1; unsigned char week=7; unsigned char month=4; unsigned char year=7; unsigned char second1; unsigned char minite1=1; unsigned char hour1=12; unsigned int tcnt; unsigned int con; unsigned int s; unsigned char i,j; void day_28(); void day_29(); void day_30(); void day_31(); delay1ms(int t); void keyscan(); nl(); main() {

TMOD=0x02; TH0=0x06; TL0=0x06; TR0=1; ET0=1; EA=1; P1_5=0; P1_6=0; P1_7=0; P3_7=1; while(1) { keyscan(); nl(); } }

/*按键处理子程序*/ void keyscan(void)

{ //EA=0; if(key0==0)

{ delay1ms(10); while(key0==0);

{con=(con+1)%4;} //TR0=0;ET0=0; //TR0=1;ET0=1;}

12

//按键调节时停止计时 } if(con==1) //功能选择1,时间调节 { P1_5=1; if(key1==0) { delay1ms(10); while(key1==0); //K1按一次小时加1 {hour=(hour+1)%24;} dispbuf0[5]=hour%10; dispbuf0[6]=hour/10; }

if(key2==0) { delay1ms(10); while(key2==0); //K2按一次分钟加1 {minite=(minite+1)%60;} dispbuf0[3]=minite%10; dispbuf0[4]=minite/10;; }

if(key3==0) { delay1ms(10); while(key3==0); //K3按一次星期加1 {week=(week)%7+1;} dispbuf0[0]=week; } P1_5=0; }

if(con==2) //功能选择2,年月日显示及调节 { P1_6=1; if(key1==0) { delay1ms(10); while(key1==0); //K1按一次年加1 year=(year+1)%100; dispbuf1[5]=year%10; dispbuf1[6]=year/10; }

if(key2==0) { delay1ms(10); while(key2==0); //K2按一次月加1 month=(month)%12+1; dispbuf1[3]=month%10; dispbuf1[4]=month/10; }

if(key3==0) { delay1ms(10); while(key3==0); //K3按一次日加1 switch(month) //年和月份检测 { case 1: day=(day%31)+1; break; case 3: day=(day%31)+1; break; case 5: day=(day%31)+1; break; case 7: day=(day%31)+1; break; case 8: day=(day%31)+1; break; case 10: day=(day%31)+1;break; case 12: day=(day%31)+1; break;

case 2: if(year%4==0) //如果是闰年 { day=(day%29)+1; break;} else

{day=(day%28)+1; break;} default: day=(day%30)+1; break; } dispbuf1[1]=day%10;

13

dispbuf1[2]=day/10; }

P1_6=0; } if(con==3) //闹钟时间设置 { P1_7=1; if(key1==0) { delay1ms(10); while(key1==0); //K6按一次小时加1 { hour1=(hour1+1)%24;} dispbuf2[5]=hour1%10; dispbuf2[6]=hour1/10; }

if(key2==0) { delay1ms(10); while(key2==0); //K3按一次分钟加1 { minite1=(minite1+1)%60;} dispbuf2[3]=minite1%10; dispbuf2[4]=minite1/10; } if(key3==0) { delay1ms(10); while(key3==0); //K3按一次秒加1 { second1=(second1+1)%60;} dispbuf2[1]=second1%10; dispbuf2[2]=second1/10; }

P1_7=0; } //EA=1; }

void t0(void) interrupt 1 using 0 { dispbuf[dispbitcnt]=dispbuf0[dispbitcnt]; P0=dispcode[dispbuf[dispbitcnt]]; P2=dispbitcode[dispbitcnt]; if(con==1)

{ dispbuf[dispbitcnt]=dispbuf0[dispbitcnt]; P0=dispcode[dispbuf[dispbitcnt]]; P2=dispbitcode[dispbitcnt]; } if(con==2)

{ dispbuf[dispbitcnt]=dispbuf1[dispbitcnt]; P0=dispcode[dispbuf[dispbitcnt]]; P2=dispbitcode[dispbitcnt]; } if(con==3)

{ dispbuf[dispbitcnt]=dispbuf2[dispbitcnt]; P0=dispcode[dispbuf[dispbitcnt]]; P2=dispbitcode[dispbitcnt]; }

dispbitcnt++; if(dispbitcnt==7) {

dispbitcnt=0; } tcnt++;

if(tcnt==1000) {

14

P3_1=0; }

if(tcnt==2000) {

tcnt=0; P3_1=1; second++; if(second==60) {

second=0; minite++; if(minite==60) {

minite=0; hour++; if(hour==24) {

hour=0; week=(week)%7+1; switch(month) //年和月份检测 { case 1: day_31(); break; case 3: day_31(); break; case 5: day_31(); break; case 7: day_31(); break; case 8: day_31(); break; case 10: day_31(); break; case 12: day_31(); break;

case 2: if(year%4==0) //如果是闰年 { day_29(); break;} else

{day_28(); break;} default: day_30(); break; } } } } if(con==0) { dispbuf0[0]=week;

dispbuf0[1]=second%10; dispbuf0[2]=second/10; dispbuf0[3]=minite%10; dispbuf0[4]=minite/10; dispbuf0[5]=hour%10; dispbuf0[6]=hour/10; } if(con==1) { P3_1=0; dispbuf0[0]=week;

dispbuf0[1]=second%10; dispbuf0[2]=second/10; dispbuf0[3]=minite%10; dispbuf0[4]=minite/10; dispbuf0[5]=hour%10; dispbuf0[6]=hour/10; } if(con==2) { P3_1=0;

15

dispbuf1[0]=week; dispbuf1[1]=day%10; dispbuf1[2]=day/10; dispbuf1[3]=month%10; dispbuf1[4]=month/10; dispbuf1[5]=year%10; dispbuf1[6]=year/10; } if(con==3) { P3_1=0; dispbuf2[0]=week;

dispbuf2[1]=second1%10; dispbuf2[2]=second1/10; dispbuf2[3]=minite1%10; dispbuf2[4]=minite1/10; dispbuf2[5]=hour1%10; dispbuf2[6]=hour1/10; } } }

/*月与天的关系*/

void day_28(void) { day=(day%28)+1; if(day==1)

{ month=(month%12)+1;} }

void day_29(void) { day=(day%29)+1; if(day==1)

{ month=(month%12)+1;} }

void day_30(void) { day=(day%30)+1; if(day==1)

{ month=(month%12)+1; } }

void day_31(void) { day=(day%31)+1; if(day==1)

{ month=(month%12)+1; if(month==1)

year=(year+1)%100; } }

/*延时子程序*/ delay1ms(int t) {

for(i=0;i/*闹铃*/ nl() {

if(P1_4==0)

{ delay1ms(10); while(P1_4==0); {s=(s+1)%2; if(s==0)

16

{P3_0=1;} else {P3_0=0;} } } if((hour==hour1)&&(minite==minite1)&&(s==0)) { P3_7=0; delay1ms(500); P3_7=1; delay1ms(500); } //LED闪烁 }

17

因篇幅问题不能全部显示,请点此查看更多更全内容

Top