电子日历.docx
《电子日历.docx》由会员分享,可在线阅读,更多相关《电子日历.docx(45页珍藏版)》请在冰豆网上搜索。
电子日历
电子日历
————————————————————————————————作者:
————————————————————————————————日期:
湖南人文科技学院
课程设计报告
课程名称:
单片机原理及应用课程设计
本设计是利用单片机的强大的功能,基于AT89C52单片机控制,对时钟芯片DS1302进行初始化和读写,并对数据进行处理,再通过外加六位8段LED数码管显示时间和日期。
而本设计采用共阳极驱动LED灯,利用延时程序实现时间和日期的滚动显示,LED数码管时钟电路采用24h计时方式,时、分、秒用6位8段数码管显示,由单片机控制显示,以完成设计要求:
1、能计时:
秒、分、时、天、周、月、年;2、时间、月、日实现从左至右的滚动显示。
关键词:
DS1302、单片机、8255、LED数码管
电子日历
设计要求
本课题以单片机为核心,设计并制作出智能LED电子钟,具有以下功能:
(1)能计时:
秒、分、时、天、周、月、年;
(2)时间、月、日实现从左至右的滚动显示;
1方案论证与对比
1.1方案一
基于AT89C52单片机的LCD液晶显示模块1602显示的智能LED电子钟。
主要是以单片机来控制,用按键来设定时间和日期的初值,用按键来进行时间和日期的调整,LCD1602液晶作为显示模块来滚动显示时间和日期。
优点:
硬件电路简单,编程比较复杂,能清晰的显示数据。
缺点:
费用较高,且在编写程序实现所要求的功能时较难。
1.2方案二
基于AT89C52单片机的数码管显示模块显示的智能LED电子钟。
主要是以单片机来控制,对时钟芯片DS1302进行初始化和读写,并对数据进行处理,再通过矩阵按键来进行时间和日期的调整。
再通过外加六位8段LED数码管显示时间和日期。
此电路对于智能LED电子钟中的LED数码管示器来说,采用以软件为主的接口方法,即不使用专门的硬件译码器,而采用软件程序使时间和日期滚动显示。
优点:
显示模块是是比较熟悉的数码管,编写程序是相对容易,且电路造价不高。
缺点:
显示模式比较单一。
综上所述,经过对比与分析,决定采用方案二。
2硬件单元电路设计与参数计算
根据电子日历设计要求,能计时,时间、月、日实现从左至右的滚动显示,要想实现上述功能,就必须将硬件系统和软件系统有机的结合在一起。
硬件系统主要由AT89C52单片机为控制核心,具有在线编程功能,低功耗。
时钟电路由DS1302提供,它是一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、星期、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.5~5.5V。
采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM数据。
DS1302内部有一个用于临时性存放数据的RAM寄存器,可产生年、月、日、周、时、分、秒,具有使用寿命长,精度高和低功耗等特点,同时具有掉电自动保存功能。
AT89C52的输入输出口很有限,而又要完成比较复杂的变换时间显示方式,调时,设置日期等功能,因此功能键的设置很重要。
我们选用三个功能按键,根据三个键之间的切换以及按键次数来完成各种功能。
显示部分为6位8段的LED数码管,通过动态扫描进行滚动显示。
电路设计框图如下:
2.1复位电路
复位是单片机的初始化操作,只需给AT89C52的复位引脚RST加上大于2个机器周期(即24个时钟振荡周期)的高电平就可得单片机复位,复位时,PC初始化为0000H,使单片机从OUT单元开始执行程序。
除了进入系统的正常初始化之外由于程序运行出错或操作错误而使系统处于死锁状态,为摆脱死锁状态,也需按复位键使得RST脚为高电平,使单片机重新启动。
在系统中,有时会出现显示不正常,也为了调试方便,我们需要设计一个复位电路,AT89S52单片机复位电路共有上电复位、按键电平复位和按键脉冲复位。
本系统是的复位电路主要完成系统的上电复位和系统在运行时用户的按键复位功能。
复位电路可由简单的RC电路构成,也可使用其它的相对复杂,但功能更完善的电路。
本系统采用的电路如图2所示。
工作原理是:
上电瞬间,RC电路充电,RESET引脚端出现正脉冲,只要RESET保持10ms以上高电平,就能使单片机有效的复位。
当时钟频率选用12MHz时,C取10uF,R取10KΩ。
上电自动复位电路由上电瞬间C与R构成充电电路,RESET端的电位与电源Vcc相同,随着充电电流的减少,RESET的电位逐渐下降。
图中RC时间常数越大,上电时RESET端保持高电平的时间越长,图中这组参数足以保证复位操作。
若复位电路失效,加电后CPU从一个随机的状态开始工作,系统就不能正常运行。
图中的按键S17的功能是按键复位,按下S17键时RST为高电平,只要保持10ms以上的高电平,就可以时单片机复位。
按键复位用在系统运行时的复位,使系统重新运行。
其复位电路原理图如下所示:
2.2DS1302时钟模块
2.2.1DS1302简介
DS1302具有时钟计数功能,可以对秒、分钟、小时、月、星期、年的计数。
年计数可达到2100年,有31*8位的额外数据暂存寄存器,最少I/O引脚传输,通过三引脚控制,工作电压:
2.0-5.5V,工作电流小于320纳安(2.0V),读写时钟寄存器或内部RAM(31*8位的额外数据暂存寄存)可以采用单字节模式和突发模式。
2.2.2DS1302引脚
DS1302引脚图如下:
晶体振荡器的选择:
一个32.768KHz的晶振可以直接接在DS1302的2、3管脚之间,可以设定规定载荷电容位6pf。
电源控制:
Vcc1可提供单电源控制也可以用来作为备用电源,Vcc2为主电源。
在主电源关闭的情况下,也可以保持时钟的连续运行。
DS1302由Vcc1或Vcc2两者中的较大者供电。
当Vcc2大于Vcc1+0.2V时,Vcc2给DS1302供电;当Vcc2小与Vcc1时,DS1302由Vcc1供电。
2.2.3DS1302功能
DS1302包括时钟/日历寄存器和31字节(8位)的数据暂存寄存器,数据通信仅通过一条串行输入输出口。
实时时钟/日历提供包括秒、分、时、日期、月份、年份和星期几的信息。
闰年可自行调整,可选择12小时制和24小时制,可以设置AM、PM。
只通过三根线(SPI总线)进行数据的控制和传递:
RST、I/O、SCLK。
2.2.4时钟电路
时钟电路如下图所示:
单片机必须在时钟的驱动下才能工作。
在单片机内部有一个时钟振荡电路,只要外界一个振荡源就能产生一定的时钟信号送到单片机内部的各个单元,决定单片机的工作速度。
本系统使用的是内部时钟方式。
一般选用石英晶体振荡器。
此电路在加电大约延迟10ms后振荡器起振,在XTAL2引脚产生幅度为3V左右的正弦波时钟信号,其振荡频率主要由石英晶振的频率确定。
电路中两个电容C1、C2的作用有两个:
一是帮助振荡器起振;二是对振荡器的频率进行微调。
本系统的C1、C2的值为30pf。
2.3晶振电路模块
单片机必须在时钟的驱动下才能工作。
在单片机内部有一个时钟振荡电路,只要外界一个振荡源就能产生一定的时钟信号送到单片机内部的各个单元,决定单片机的工作速度。
本系统使用的是内部时钟方式。
一般选用石英晶体振荡器。
此电路在加电大约延迟10ms后振荡器起振,在XTAL2引脚产生幅度为3V左右的正弦波时钟信号,其振荡频率主要由石英晶振的频率确定。
电路中两个电容C1、C2的作用有两个:
一是帮助振荡器起振;二是对振荡器的频率进行微调。
本系统的C1、C2的值为30pf。
其电路图如下所示:
2.48255可编程并行口芯片模块
8255A芯片是通用可编程并行接口电路,广泛用于单片机扩展并行I/O接口。
它具有3个8位并行口PA、PB、PC。
8255A芯片的引脚功能说明如下:
(1)D0-D7:
双向三态数据总线,通常与CPU总线相连;
(2)PA、PB、PC:
3个8位I/O接口。
PC口还可分为高4位和低4位,其中,高4位可与PA口组成A组,低4位可与PB口组成B组。
PC口可按位置位/复位。
(3)CS:
片选信号输入端,低电平有效。
(4)RD:
读选通输入端,低电平有效。
(5)WR:
写选通输入端,低电平有效。
(6)RESET:
复位输入引脚,高电平有效,复位后,PA、PB、PC口均为输入。
(7)A0、A1:
端口地址输入线,通过地址组合选择8255A内部寄存器。
(8)Vcc、GND:
电源+5V、接地。
8255A芯片的内部逻辑结构及引脚如下图所示:
2.6矩阵键盘模块
本系统用到的是4*4矩阵键盘,行线由8255A芯片PC端口的低四位控制,而列线是由PC端口的高四位来控制的,键盘的扫描是动态的低电平扫描,当有个键按下时,相应的行线为高电平,扫描的结果由PC口送回8255A.
在此系统中矩阵键盘的作用是调整电子日历的时间和日期,通过软件设计几个键的功能。
本系统是利用S4来实现时间调整的切换,按第一下是实现时间秒的调整,其后没按下一次是切换到分、时、周、日、月、年的调整,再按下则是滚动显示日历。
软件设定S6键是实现时间调整中的“+”,S7键是实现时间调整中的“-”。
按键电路图如下所示:
2.5LED数码管显示电路
我们使用的是8段数码管显示(包含小数点),通常在显示上我们采用的方法一般包括两种:
一种是静态显示,另一种是动态显示。
其中静态显示的特点是显示稳定不闪烁,程序编写简单,但占用端口资源多,所耗得电能较大。
动态显示的特点是显示稳定性没静态好,程序编写复杂,但是相对静态显示而言占用端口资源少。
在本设计中,为了减少端口资源,降低电能消耗,采用的是动态显示方法。
考虑到数码管的段和位比较多,本系统用8255A作为扩展端口芯片。
数码管有段选和位选控制,在此电路中有6个位选,8个段选(每一个数码管的段选进行并联)。
分别用8255芯片的PA口和PB口进行四位数码管的控制,而用单片机的PB口来控制段。
电路中用了六个PNP来控制数码管的位选的开关,PNP在这起开关的作用。
电路如下图所示。
3系统软件设计
3.1主程序流程图
本设计中主程序主要实现显示的初始化和调用各子程序工作的功能,读取时间的子程序主要实现初始化,时间调整设置信息的采集和显示的位与段码的存取。
分别对各个器件的功能进行编程设计,根据主程序流程图(如下)进行全面的分析。
时间调整主要是通过矩阵键盘按键来完成,当有按键按下时,转入相应的功能程序,再由数码管进行动态显示。
其主程序执行流程图如下图:
3.2键盘扫描程序
本设计采用动态扫描法,动态扫描法不仅扫描键阵,也可以实现显示,是目前应用十分广泛的一种方法。
动态扫描法是采用输出“移动”信号,轮流对各行按键进行检测来实现的。
设置行线为输出,列线为输入,当无按键按下时,列输入全为“1”.设计时,将某一行输出为“0”,读取列线值,若其中某一位为“0”,则表明行、列交叉处的按键按下,否则,无按键按下;继续扫描下一行(将下一行输出为“0”),直至全扫描完为止。
键盘扫描程序流程图如12图所示:
3.3动态显示子程序
时间显示子程序每次显示6个连续内存单元的十进制BCD码数据,由于采用7段共阳LED数码管动态扫描实现数据显示,所以显示用十近制BCD码数据的对应段码存放在ROM表中。
显示时,先取出内存地址中的要显示的数据,然后查得对应的显示段码从PB口输出,PA口将对应的位选将数码管选中,就能显示该地址单元的数据值。
滚动显示程序同样可以通过位选和段选的改变可以实现。
数码管显示子程序流程图如图所示:
4软件调试与测试
5详细仪器清单
表格1仪器清单
仪器名称
数量
8051芯片
1块
8255A芯片
1块
六位8段数码管
1组
DS1302时钟芯片
1块
4x4轻触按钮开关
1个
32.768晶振
1个
12M晶振
1个
1K电阻
28个
104极性电容
1个
30pf电容
6个
6总结与致谢
课程设计是我学习过程中一个十分重要的环节,单片机课程设计是对微机原理、单机原理及应用的实践,我们要学会运用所学知识正确分析和解决实际问题,我们也希望通过这次课程设计学习到尽可能多的知识。
通过这次课程设计不仅巩固了我们的书本知识,同时也加强和锻炼了我们的编程能力。
课程设计中,对流程图的设计尤为重要,它直接影响到了我们整个程序框架,硬件的选择对电子日历功能的实现也有一定影响。
在每一次调试,我们都能从中发现了所编程序的漏洞,从而进一步改善,接下来的调试就比较顺畅了。
这次课程设计让我们学到很多东西,实际应用能力也进一步的得到了提高。
这次课程设计对我们来说有着深远的意义,在此我们要深深的感谢那些传授我们知识的老师们,是你们无私的奉献,才会有如今掌握一定知识的我们,还要感谢同学朋友对我们的鼓励和认可,让我们顺利完成了这次课程设计。
学无止境,我们现在所做的还只是一个开始。
参考文献
【1】张鑫,华臻,陈书谦.单片机原理及应用.北京电子工业出版社,2005
【2】朱定华,戴汝平.单片微机原理与应用.(M)北京:
清华大学出版社,2003
【3】楼然苗,李光飞.单片机课程设计指导.(B).北京航空航天大学出版社,2007
【4】李凤霞,刘桂山,薛庆.C语言程序设计(第二版).北京理工大学出版社,2008
附录一:
系统主电路图
附录二:
程序
#include
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
#definePORTAXBYTE[0xd9ff]
#definePORTBXBYTE[0xdbff]
#definePORTCXBYTE[0xddff]
#defineCONTROLXBYTE[0xdfff]
sbitRST=P2^6;
sbitSCLK=P3^2;
sbitIO=P3^5;
ucharcodeLED_CODE[]={0XA0,0XBB,0X62,0X2A,0X39,0X2C,0X24,0XBA,
0X20,0X28};//不带点的数码管段码0~9
ucharcodeLED_DOT_CODE[]={0x80,0x9b,0x42,0x0a,0x19,0x0c,0x04,0x9a,0x00,0x08};//带点的数码管段码0~9
ucharSEC,MIN,HOUR,DAY,MON,YEAR,WEEK;//分别用来指示秒,分,时,日,月,年,星期
ucharSEC1,SEC2,MIN1,MIN2,HOUR1,HOUR2,DAY1,DAY2,MON1,MON2,YEAR1,YEAR2;
ucharFLAG,COUNT,TEMP;
inti;
uchartable[19];//显示数组,保存得到的时间值
/*------------------------------------------------
uS延时函数,含有输入参数unsignedchart,无返回值
unsignedchar是定义无符号字符变量,其值的范围是
0~255这里使用晶振12M,精确延时请使用汇编,大致延时
长度如下T=tx2+5uS
------------------------------------------------*/
voidDelayUs(unsignedintt)
{
while(--t);
}
/*------------------------------------------------
mS延时函数,含有输入参数unsignedchart,无返回值
unsignedchar是定义无符号字符变量,其值的范围是
0~255这里使用晶振12M,精确延时请使用汇编
------------------------------------------------*/
voidDelayMs(unsignedintt)
{
while(t--)
{
//大致延时1mS
DelayUs(245);
DelayUs(245);
}
}
/*********ds1302驱动程序***************/
voidDs_Write_Data(uchardate)//写数据
{
uchari,j;
for(j=0;j<8;j++)
{
IO=0;
i=date&0x01;
SCLK=0;
if(i==1)
IO=1;
date=date>>1;
SCLK=1;
}
SCLK=1;
}
ucharDs_Read_Data()//读数据
{
uchart,i;
IO=1;
for(i=0;i<8;i++)
{
SCLK=0;
t=t>>1;
if(IO==1)
t=t|0x80;
SCLK=1;
}
SCLK=0;
return(t);
}
voidSet_Time(ucharcom,uchardate)//时间设置函数
{
SCLK=0;
RST=0;
RST=1;
Ds_Write_Data(com);
Ds_Write_Data(date);
RST=0;
}
ucharGet_Time(ucharadd)//时间读取函数
{
uchart;
SCLK=0;
RST=0;
RST=1;
Ds_Write_Data(add);
t=Ds_Read_Data();
RST=0;
return(t);
}
/*********************************
*******************************************/
voidInit()//初始化
{
CONTROL=0X81;//8255端口功能设置
Set_Time(0x8e,0x00);//取消写保护
Set_Time(0x80,0x00);//启动时钟
Set_Time(0x84,0x00);//设置24小时模式
Set_Time(0x90,0xa5);//时钟时钟充电模式
Set_Time(0x8e,0x80);//启动写保护
}
voidDisplay_Time()//第一显示屏显示时,分,秒
{
SEC=Get_Time(0x81);
SEC1=SEC&0x0f;
PORTA=0xdf;
PORTB=LED_CODE[SEC1];
DelayMs
(1);
SEC=SEC>>4;
SEC2=SEC&0x07;
PORTA=0xef;
PORTB=LED_CODE[SEC2];
DelayMs
(1);
MIN=Get_Time(0x83);
MIN1=MIN&0x0f;
PORTA=0Xf7;
PORTB=LED_DOT_CODE[MIN1];
DelayMs
(1);
MIN=MIN>>4;
MIN2=MIN&0x07;
PORTA=0Xfb;
PORTB=LED_CODE[MIN2];
DelayMs
(1);
HOUR=Get_Time(0x85);
HOUR1=HOUR&0x0f;
PORTA=0Xfd;
PORTB=LED_DOT_CODE[HOUR1];
DelayMs
(1);
HOUR=HOUR>>4;
HOUR2=HOUR&0x03;
PORTA=0Xfe;
PORTB=LED_CODE[HOUR2];
DelayMs
(1);
}
voidDisplay_Date()//第二显示屏显示月,日,星期
{
WEEK=Get_Time(0x8b);
PORTA=0Xdf;
PORTB=LED_CODE[WEEK];
DelayMs
(1);
PORTA=0Xef;
PORTB=0X7f;
DelayMs
(1);
DAY=Get_Time(0x87);
DAY1=DAY&0x0f;
PORTA=0Xf7;
PORTB=LED_CODE[DAY1];
DelayMs
(1);
DAY=DAY>>4;
DAY2=DAY&0x03;
PORTA=0Xfb;
PORTB=LED_CODE[DAY2];
DelayMs
(1);
MON=Get_Time(0x89);
MON1=MON&0x0f;
PORTA=0Xfd;
PORTB=LED_DOT_CODE[MON1];
DelayMs
(1);
MON=MON>>4;
MON2=MON&0x01;
PORTA=0Xfe;
PORTB=LED_CODE[MON2];
DelayMs
(1);
}
voidDisplay_Year()//第三显示屏显示年
{
PORTA=0xdf;
PORTB=0xff;
YEAR=Get_Time(0x8d);
YEAR1=YEAR&0x0f;
PORTA=0Xef;
PORTB=LED_CODE[YEAR1];
DelayMs
(1);
YEAR=YEAR>>4;
YEAR2=YEAR&0x0f;
PORTA=0Xf7;
PORTB=LED_CODE[YEAR2];
DelayMs
(1);
PORTA=0xfb;
PORTB=0xa0;
DelayMs
(1);
PORTA=0xfd;
PORTB=0x62;
DelayMs
(1);
PORTA=0xfe;
PORTB=0xff;
}
voidRoll_Display()//滚动显示
{
SEC=Get_Time(0x81);
SEC1=SEC&0x0f;
SEC=SEC>>4;
SEC2=SEC&0x07;
MIN=Get_Time(0x83);
MIN1=MIN&0x0f;
MIN=MIN>>4;
MIN2=MIN&0x07;
HOUR=Get_Time(0x85);
HOUR1=HOUR&0x0f;
HOUR=HOUR>>4;
HOUR2=HOUR&0x03;
WEEK=Get_Time(0x8b);
DAY=Get_Time(0x87);
DAY1=DAY&0x0f;
DAY=DAY>>4;
DAY2=DAY&0x03;
MON=Get_Time(0x89);
MON1=MON&0x0f;
MON=MON>>4;
MON2=MON&0x01;
YEAR=Get_Time(0x8d);
YEAR1=YEAR&0x0f;
YEAR=YEAR>>4;
YEA