资源描述
毕业实践报告
专业班级 自动化1004班
学生姓名
学 号
实践性质 课程设计
实践成绩
指导教师
长江职业学院工学院
二○一○年十一月印制
基于51单片机的万年历设计
单片机经过几十年的发展,已经广泛应用于生活中的各个领域。单片机以其体积小、功能全、性价比高等诸多优点,在许多行业都得到了广泛应用。在工业控制、家用电器、通信设备、信息处理、尖端武器等各种测控领域的应用中独占鳌头,单片机开发技术已成为电子信息、电气、通信、自动化、机电一体化等专业技术人员必须掌握的技术。 矚慫润厲钐瘗睞枥庑赖。
基于单片机的万年历作为设计的课题,因为它有很好的开放性和可发挥性,对作者的要求比较高,不仅考察了对单片机的掌握能力而且强调了对单片机扩展的应用。另外液晶显示的万年历已经越来越流行,特别适合在家庭居室、办公室、大厅、会议室、车站和广场等地方使用,它具有显示清晰直观、走时准确、可以进行夜视等功能,并且还可以扩展出其它多种功能。所以,电子万年历作为设计课题很有价值。聞創沟燴鐺險爱氇谴净。
现在对于电子万年历的设计大多运用51单片机。主要是因为51单片机种类齐全、结构体系完整、指令系统功能完善、性能优越、具有较高可靠性和高性价比等特点。残骛楼諍锩瀨濟溆塹籟。
本篇论文主要介绍了运用单片机实现电子万年历的设计,万年历系统拟用STC89C51单片机控制,以DS1302时钟芯片计时、1602液晶屏显示。系统主要由单片机控制电路,显示电路以及校正电路三个模块组成。本文阐述了系统的硬件工作原理,所应用的各个接口模块的功能以及其工作过程,论证了设计方案理论的可行性。酽锕极額閉镇桧猪訣锥。
目 录
第一章 绪论 1彈贸摄尔霁毙攬砖卤庑。
1.1 本课题主要的研究工作 1謀荞抟箧飆鐸怼类蒋薔。
第二章 系统的硬件设计与实现 2厦礴恳蹒骈時盡继價骚。
2.1 电路设计框图 2茕桢广鳓鯡选块网羈泪。
2.2 系统硬件概述 2鹅娅尽損鹌惨歷茏鴛賴。
2.3 主要单元电路的设计 2籟丛妈羥为贍偾蛏练淨。
2.3.1 单片机主控制模块的设计 2預頌圣鉉儐歲龈讶骅籴。
2.3.2时钟电路模块的设计 3渗釤呛俨匀谔鱉调硯錦。
2.3.3独立式键盘设计 4铙誅卧泻噦圣骋贶頂廡。
2.3.4显示模块的设计 4擁締凤袜备訊顎轮烂蔷。
第三章 系统的软件设计 6贓熱俣阃歲匱阊邺镓騷。
3.1程序流程图 6坛摶乡囂忏蒌鍥铃氈淚。
3.1.1 系统总流程图 6蜡變黲癟報伥铉锚鈰赘。
3.1.2 DS1302时钟程序流程图 7買鲷鴯譖昙膚遙闫撷凄。
3.1.3 LCD显示程序流程图 8綾镝鯛駕櫬鹕踪韦辚糴。
3.2 程序的设计 9驅踬髏彦浃绥譎饴憂锦。
3.2.1 DS1302读写程序 9猫虿驢绘燈鮒诛髅貺庑。
3.2.2 数码管显示程序 11锹籁饗迳琐筆襖鸥娅薔。
第四章 仿真与调试 13構氽頑黉碩饨荠龈话骛。
4.1 Keil软件调试流程 13輒峄陽檉簖疖網儂號泶。
4.2 Proteus软件运行流程 13尧侧閆繭絳闕绚勵蜆贅。
4.3 万年历的功能仿真 13识饒鎂錕缢灩筧嚌俨淒。
致 谢 15凍鈹鋨劳臘锴痫婦胫籴。
参考文献 16恥諤銪灭萦欢煬鞏鹜錦。
附录:主程序 17鯊腎鑰诎褳鉀沩懼統庫。
第一章 绪论
1.1 本课题主要的研究工作
本项目是一种基于AT89C51片机的万年历设计,本方案以AT89C51片机作为主控核心,与时钟芯片DS1302、按键、LCD1602液晶显示器组成硬件系统。在硬件系统中设有独立按键和LCD1602显示器,能显示丰富的信息,根据使用者的需要可以随时对时间进行更改,读取方便、显示直观。硕癘鄴颃诌攆檸攜驤蔹。
当程序执行后,LCD显示即时时间、年月日、星期。设置4个操作键:K1:选择键;K2:加键;K3:减键;K4:确定键。阌擻輳嬪諫迁择楨秘騖。
1本设计的主要内容:
(1)熟悉万年历各模块的工作原理;
(2)选择适当的芯片和元器件,确定系统电路,绘制电路原理图,尤其是各接口电路;
(3)熟悉单片机使用方法和C语言,编写出相应模块的应用程序;
(4)分别在各自的模块中调试出对应的功能,在Proteus软件上进行仿真,并实现各种功能。
2设计目标:万年历实现以下三个功能:
(1)具有年、月、日、星期、时、分、秒等功能;
(2)具备年、月、日、星期、时、分、秒校准功能,具备自动调节闰年的功能;
(3)具有与即时时间同步的功能。
第二章 系统的硬件设计与实现
2.1 电路设计框图
根据设计方案给出了系统总体的设计框图,如图1所示:
主控制模块
STC89C51
LCD液晶模块
DS1302模块
键盘模块
图1
为使时钟走时与标准时间一致,校时电路是必不可少的,键盘模块用来校正液晶上显示的时间; STC89C51单片机通过输出各种电脉冲信号来驱动控制各部分正常工作;而系统的时间、等数据则最终通过液晶模块显示出来。氬嚕躑竄贸恳彈瀘颔澩。
2.2 系统硬件概述
本电路是以STC89C51单片机为控制核心,该芯片具有在线编程功能,功耗低,能在3.3V的超低压下工作;釷鹆資贏車贖孙滅獅赘。
时钟芯片采用DS1302,它是一款高性能、低功耗、自带RAM的实时时钟芯片,具有掉电自动保存功能。可自动对秒、分、时、日、周、月、年进行计数,具有闰年补偿功能,而且精度高位的RAM做为数据暂存区,工作电压2.5V~5.5V范围内,2.5V时耗电小于300nA。怂阐譜鯪迳導嘯畫長凉。
显示模块采用1602显示屏,它内置192种字符,可显示32个符号或数字,清晰可见,而且功率消耗小寿命长抗干扰能力强。其工作电压为5v。谚辞調担鈧谄动禪泻類。
2.3 主要单元电路的设计
2.3.1 单片机主控制模块的设计
一个典型的单片机最小系统一般由时钟电路、复位电路、电源指示灯和外部扩展接口等部分组成。
单片机的最小系统如下图所示,单片机的XTAL0和XTAL1引脚用于连接晶振电路。RESET为复位引脚,连接复位电路,用于初始化MCU。嘰觐詿缧铴嗫偽純铪锩。
2.3.2时钟电路模块的设计
DS1302内含有一个实时时钟/日历和31字节静态RAM,通过简单的串行接口与单片机进行通信。图中VCC1为后备电源,VCC2为主电源。DS1302由VCC1或VCC2两者中的较大者供电。所以在主电源关闭的情况下,也能保持时钟的连续运行。X1和X2是振荡源,外接32.768KHz晶振用来为芯片提供计时脉冲。RST是复位/片选线,通过把RST输入驱动置高电平来启动所有的数据传送。DS1302熒绐譏钲鏌觶鷹緇機库。
的硬件接线图如图2所示:
图2
时钟芯片DS1302的工作原理:
(1) DS1302的控制字节:DS1302控制字节的高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入DS1302中,位6如果为0,则表示存取日历时钟数据,为1表示存取RAM数据;位5至位1指示操作单元的地址;最低有效位(位0)如为0表示要进行写操作,为1表示进行读操作,控制字节总是从最低位开始输出鶼渍螻偉阅劍鲰腎邏蘞。
(2) 数据输入输出(I/O):在控制指令字输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位即位0开始。同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0位到高位7。纣忧蔣氳頑莶驅藥悯骛。
(3) DS1302的寄存器:DS1302有12个寄存器,其中有7个寄存器与日历、时钟相关,存放的数据位为BCD码形式。“CH”是时钟暂停标志位,当该位为1时,时钟振荡器停止,DS1302处于低功耗状态;当该位为0时,时钟开始运行。“WP”是写保护位,在任何的对时钟和RAM的写操作之前,“WP”必须为0。当“WP”为1时,写保护位防止对任一寄存器的写操作。颖刍莖蛺饽亿顿裊赔泷。
2.3.3独立式键盘设计
独立式键盘每个键单独占用一根I/O口线。键盘的工作方式可分为编程控制方式和中断控制方式。CPU在一个工作周期内,利用完成其他任务的空余时间,调用键盘扫描子程序,经程序查询,若无键操作,则返回;若有键操作,则进而判断是哪个键,并执行相应的键处理程序。这种方式为编程扫描方式。由于单片机在正常应用过程中,可能会经常进行键操作,因而编程控制方式使CPU经常处于工作状态, 在进行本次设计中,只涉及到了选择、加、减、确定四个功能。因此采用独立式键盘。濫驂膽閉驟羥闈詔寢賻。
2.3.4显示模块的设计
3-8译码器的输入是3个脚,输出时8个脚,用高低电平表示输入和输出。输入是二进制。P1.0,P1.1,P1.2分别表示三位二进制数。二进制最大数位111,输出时十进制。8个输出脚刚好对应数码管的八个选位。銚銻縵哜鳗鸿锓謎諏涼。
点亮第0位,给P1.2,P1.1,P1.0赋值000.写程序P1=0x00
点亮第1位,给P1.2,P1.1,P1.0赋值001.写程序P1=0x01
点亮第2位,给P1.2,P1.1,P1.0赋值002.写程序P1=0x02
点亮第3位,给P1.2,P1.1,P1.0赋值003.写程序P1=0x03
点亮第4位,给P1.2,P1.1,P1.0赋值004.写程序P1=0x04
点亮第5位,给P1.2,P1.1,P1.0赋值005.写程序P1=0x05
点亮第6位,给P1.2,P1.1,P1.0赋值006.写程序P1=0x06
点亮第7位,给P1.2,P1.1,P1.0赋值007.写程序P1=0x07
数码管从左到右编号0~7,共八位,其八个选位分别接到3-8译码器的八个输出上。数码管是共阴极的,高电平有效。。挤貼綬电麥结鈺贖哓类。
第三章 系统的软件设计
3.1程序流程图
3.1.1 系统总流程图
系统总流程图分析:首先系统初始化,系统开始运行,当有设置键按下时进入修改时间模式,无按键按下时读取时间、温度等数据送入液晶屏显示;在修改时间模式下设置时间完成后再送数据到液晶屏显示,如图4所示:赔荊紳谘侖驟辽輩袜錈。
图4
3.1.2 DS1302时钟程序流程图
入液晶屏显示。这时若有设置键按下时,进行时间修改,完成后将数据送入时钟芯片;若没有按键按下,则直接存入EPROM,送入液晶屏显示。时钟程序S1302开始计时时,首先进行初始化,当有中断信号时,读取时钟芯片的数据,如图5所示:塤礙籟馐决穩賽釙冊庫。
3.2 程序的设计
3.2.1 DS1302读写程序
DS1302是SPI总线驱动方式。它不仅要向寄存器写入控制字,还需要读取相应寄存器的数据。要想与DS1302通信,首先要先了解DS1302的控制字。DS1302的控制字如图7: 裊樣祕廬廂颤谚鍘羋蔺。
图7
控制字总是从最低位开始输出。在控制字指令输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从最低位(0位)开始。同样,在紧跟8位的控制字指令后的下一个SCLK脉冲的下降沿,读出DS1302的数据,读出的仓嫗盤紲嘱珑詁鍬齊驁。
数据也是从最低位到最高位。依据读写时序如图8和图9:
图8 单字节读
图9 单字节写
在进行任何数据传输时,RST必须被置高电平,每个SCLK为上升沿时数据被输入,下降沿时数据被输出。先把RST置低,禁止数据传输,SCLK置低,清零时钟总线,RST再置高,允许数据传输。传送完成后,RST置低,禁止字节的传送。部分源程序如下:绽萬璉轆娛閬蛏鬮绾瀧。
void write_byte(uchar dat) //写一个字节
{
ACC=dat;
RST=1;
for(a=8;a>0;a--)
{
IO=ACC0;
SCLK=0;
SCLK=1;
ACC=ACC>>1;
}
}
uchar read_byte() //读一个字节
{
RST=1;
for(a=8;a>0;a--)
{
ACC7=IO;
SCLK=1;
SCLK=0;
ACC=ACC>>1;
}
return (ACC);
}
void write_1302(uchar add,uchar dat) //向1302芯片写函数,指定写入地址,数据骁顾燁鶚巯瀆蕪領鲡赙。
{
RST=0;
SCLK=0;
RST=1;
write_byte(add);
write_byte(dat);
SCLK=1;
RST=0;
}
uchar read_1302(uchar add) //从1302读数据函数,指定读取数据来源地址瑣钋濺暧惲锟缟馭篩凉。
{
uchar temp;
RST=0;
SCLK=0;
RST=1;
write_byte(add);
temp=read_byte();
SCLK=1;
RST=0;
return(temp);
}
第四章 仿真与调试
4.1 Keil软件调试流程
建立新工程并保存,保存后会弹出一个设备选择对话框,选择MCU后点确定返回主界面。新建文件并保存,以.C为后缀。接着选择Source Group1,右击鼠标弹出快捷菜单,选择“Add File to Group ‘Source Group1’”,出现一个对话框,加入文件后点close返回主界面。再打开工程属性设置对话框,主要设置工作包括在Target选项卡中设置晶振频率、在Debug选项卡中设置生成hex文件等。然后编写程序并调试。在模拟调试程序后,还须通过编程器将.hex目标文件写入单片机中才能观察仿真的效果。鎦诗涇艳损楼紲鯗餳類。
4.2 Proteus软件运行流程
运行Proteus程序后,进入软件的主界面,过左侧工具栏中的P(从库中选择元件命令)命令,在Pick Devices 左侧窗口中选择所需元件的关键字,然后放置元件并调整方向和位置以及参数设置,最后进行连线。按P在库中查找元器件,将所需要的元器件放置好后,绘制成原理图。栉缏歐锄棗鈕种鵑瑶锬。
4.3 万年历的功能仿真
当电路搭建好之后,选中单片机STC89C51,左键点击STC89C51,在出现的对话框里点击Program File按钮,找到刚才Keil软件编译得到的HEX文件,载入然后点击“OK”按钮就可以模拟了。点击模拟调试按钮的运行按钮,进人调试状态。按相应的按键可调节分,时,星期,日期,月份,年份,并且可以自动闰年调整。按键功能自上而下依次为:选择键、加、减、确定。在Protues中仿真,如图10,图11,图12所示:辔烨棟剛殓攬瑤丽阄应。
图10 电路图
图11 键盘调节
致 谢
至此,关于毕业设计的所有内容就介绍完了,系统的仿真电路和程序设计合理。
在整个设计过程中,充分发挥了人的主观能动性,自主学习,学到了许多没学到的知识。程序编写中,由于思路不清晰,开始时遇到了很多的问题,经过静下心来思考查资料,和同学讨论,理清了思路,完成对程序的编写。通过设计提高了对单片机的认识,进一步熟悉和掌握单片机的结构及工作原理。通过实际程序设计和调试,逐步掌握模块化程序设计方法和调试技术,提高软件设计、调试能力;通过这次设计熟悉以单片机核心的应用系统开发的全过程,掌握硬件电路设计的基本方法和技术,掌握相关电路参数的计算方法。最终较好的完成了设计,达到了预期的目的,完了最初的设想。但是由于时间和个人暂时的能力的原因,整个系统看起来还是显得非常的简单,只实现了一些最基本的功能,还有许多不足和可以扩展的地方。峴扬斕滾澗辐滠兴渙藺。
毕业综合实践的完成,为我的大学学习生活画下了最后一笔。应该感谢的人很多,首先感谢学院给我们提供了一个展现自己的舞台,在长江职业学院这个良好的学习环境中,我们得到了很多锻炼的机会,使得我们的动手能力和专业技能都有了很大的提高。其次要感谢教单片机的邓柳老师的悉心教导和全程负责毕业综合实践的陈卉老师,还有帮助我完成的学校电子竞赛组的同学。是你们为我创造了良好的学习和完成毕业设计的环境,你们的支持和鼓励使我对这次的设计完成有了信心和动力,使我能够顺利地完成课题的设计工作,在此向这些帮助我的人致以诚挚的谢意。最后,还要特别感谢我的父母,养育之恩,无以回报,你们永远健康快乐是我最大的心愿。正是在爸妈身体和精神的养育下才让我得以全身心投入学习和研究中,顺利完成学业。詩叁撻訥烬忧毀厉鋨骜。
即将踏上社会了,在人生的又一个十字路口上,我将带着你们的期望和关怀,在将来的工作岗位上勤奋实干,积极进取,用优异的成绩来回报大家对我的关心和帮助!则鯤愜韋瘓賈晖园栋泷。
参考文献
1. 张迎新 《单片微型计算机原理、应用及接口技术》 国防工业出版社
2. 郭天祥 《十天学会单片机》 哈尔滨工程大学出版社
3. 郭天祥 《51单片机C语言教程》 电子工业出版社
4. 张福祥 《C语言程序设计》 辽宁大学出版社
附录:主程序
// 名称:用DS1302与八位数码管设计的可调式电子日历与时钟
// 说明:本例会自动调节合法日期时间,对于星期的调节会在
// 调整年月日时自动完成,闰年问题也会自动判断。
//-------------------------------------------------------胀鏝彈奥秘孫戶孪钇賻。
#include<reg52.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit rst=P1^5;
sbit io=P1^4;
sbit sck=P1^3;
sbit en=P3^6;
sbit s1=P1^0;
sbit s2=P1^1;
sbit s3=P3^2;
sbit s4=P3^3;
uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40,0x00};鳃躋峽祷紉诵帮废掃減。
uchar code table1[]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};稟虛嬪赈维哜妝扩踴粜。
uchar time_data[]={02,22,03,20,12,4,12,0xff};//年,星期,月,日,时,分,秒陽簍埡鲑罷規呜旧岿錟。
uchar code write_add[]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};沩氣嘮戇苌鑿鑿槠谔應。
uchar code read_add[]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};钡嵐縣緱虜荣产涛團蔺。
uchar dis[8];
uchar count,num,no,flag,s1num=0,s2num=0,x,y,m,n;
uchar l;
void delay(uint);
void write_ds1302_byte(uchar);
void write_ds1302(uchar,uchar);
uchar read_ds1302(uchar);
void set_rtc();
void pros();
void display();
void timer0init();
void keyscan();
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void write_ds1302_byte(uchar dat)
{
uchar i;
for(i=0;i<8;i++)
{
sck=0;
io=dat&0x01;
dat>>=1;
sck=1;
}
}
void write_ds1302(uchar add,uchar dat)
{
rst=0;
_nop_();
sck=0;
_nop_();
rst=1;
_nop_();
write_ds1302_byte(add);
write_ds1302_byte(dat);
rst=0;
_nop_();
sck=1;
io=1;
}
uchar read_ds1302(uchar add)
{
uchar j,value;
rst=0;
_nop_();
sck=0;
_nop_();
rst=1;
_nop_();
write_ds1302_byte(add);
for(j=0;j<8;j++)
{
value>>=1;
sck=0;
if(io)
value=value|0x80;
sck=1;
}
rst=1;
_nop_();
sck=0;
_nop_();
sck=1;
io=1;
return value;
}
void set_rtc()
{
uchar k,j;
for(k=0;k<7;k++)
{
j=time_data[k]/10;
time_data[k]=time_data[k]%10;
time_data[k]=time_data[k]+j*16;
}
write_ds1302(0x8e,0);
for(k=0;k<7;k++)
{
write_ds1302(write_add[k],time_data[k]);
}
write_ds1302(0x8e,0x80);
}
void read_rtc()
{
uchar j;
for(j=0;j<7;j++)
{
time_data[j]=read_ds1302(read_add[j]);
}
}
void pros1()
{
dis[0]=time_data[6]/16;
dis[1]=time_data[6]%16;
dis[2]=10;
dis[3]=time_data[4]/16;
dis[4]=time_data[4]%16;
dis[5]=10;
dis[6]=time_data[3]/16;
dis[7]=time_data[3]%16;
}
void pros2()
{
dis[0]=time_data[2]/16;
dis[1]=time_data[2]%16;
dis[2]=10;
dis[3]=time_data[1]/16;
dis[4]=time_data[1]%16;
dis[5]=10;
dis[6]=time_data[0]/16;
dis[7]=time_data[0]%16;
}
void pros3()
{
dis[0]=11;
dis[1]=11;
dis[2]=11;
dis[3]=11;
dis[4]=11;
dis[5]=11;
dis[6]=time_data[5]/16;
dis[7]=time_data[5]%16;
}
void display()
{
uchar t;
// en=1;
for(t=0;t<8;t++)
{
P1=table1[t];
P2=table[dis[t]];
delay(2);
}
}
void timer0init()
{
TMOD=0X01;
TH0=(65536-45873);
TL0=(65536-45872);
EA=1;
ET0=1;
TR0=1;
}
void keyscan()
{
if(s1==0)
{
delay(5);
if(s1==0)
{
s1num++;
if(s1num>7)
s1num=0;
while(!s1);
}
}
if(s1num!=0) {
if(s2==0)
{
delay(5);
if(s2==0)
{uchar l;
write_ds1302(0x8e,0x00);
l=read_ds1302(0x80+2*s1num-1);
l=((l>>4)*10+(l&0x0f));
l++;
l=((l/10)<<4)+(l%10);
write_ds1302(0x80+2*s1num-2,l);
read_rtc();
pros2();
display();
while(!s2);
}
}
if(s3==0)
{
delay(5);
if(s3==0)
{uchar l;
write_ds1302(0x8e,0x00);
l=read_ds1302(0x80+2*s1num-1);
l=((l>>4)*10+(l&0x0f));
l--;
l=((l/10)<<4)+(l%10);
write_ds1302(0x80+2*s1num-2,l);
read_rtc();
pros2();
display();
while(!s3);
}
}}
if(s4==0)
{
delay(5);
if(s4==0)
{
s2num++;
if(s2num>2)
s2num=0;
while(!s4);
}
}
}
void main()
{
timer0init();
set_rtc();
while(1)
{
read_rtc();
if(s2num==0)
{ pros2();
display();}
if(s2num==1)
{ pros1();
display();}
if(s2num==2)
{ pros3();
display();}
keyscan();
}
}
22
展开阅读全文