《基于C51单片机的简单万年历设计(共26页).doc》由会员分享,可在线阅读,更多相关《基于C51单片机的简单万年历设计(共26页).doc(26页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、精选优质文档-倾情为你奉上第X届学生科技节 -单片机设计作品名称:基于C51单片机的万年历设计专 业: xxxxx 班 级: xx 指导老师: xxxxx 组长: xxxxxx 学号: xxxxxxxxxx 组员: xxxxxx 学号: xxxxxxxxxx 专心-专注-专业目 录一、 绪论众所周知单片机是一种集成在电路芯片,是采用超大规模集成电路技术把具有数据处理能力的中央处理器CPU随机存储器RAM、只读存储器ROM、多种I/O口和中断系统、定时器/计时器等功能(可能还包括显示驱动电路、脉宽调制电路、模拟多路转换器、A/D转换器等电路)集成到一块硅片上构成的一个小而完善的计算机系统。本设计
2、要制作的就是单片机于生活中最为常见的几种应用万年历。本设计以AT89S52单片机作为核心,可以显示当前的日历和时间,时间也可以人为设定,显示格式为年(四位),月(两位),日(两位),时(两位),分(两位),秒(两位)。设置时间的位切换、设定数值、启动定时器、切换日历通过外部中断来实现。万年历显示电路由LCD1602组成, 制作该装置的材料需要有软硬件的支持,硬件方面AT89C51单片机,晶振,电源,液晶屏LCD1602。二、 系统功能本次设计的是万年历,采用LCD1602显示,实现的功能如下:1. 显示当前时间,显示格式为年(四位),月(两位),日(两位),时(两位),分(两位),秒(两位);
3、2. 时钟计时,自动进行时间的位切换;3. 键盘设置,能通过键盘设定当前时间和计时,并通过键盘人为设定时间。AT89S52主控制模块LCD1602显示模块计时模块键盘输入模块三、 硬件电路1.2.3.3.1. 电路设计框图3.2. 系统硬件概述本电路是由AT89S52单片机为控制核心,具有在线编程功能,低功耗,能在3V超低压工作,本系统选用12MHZ的晶振,使得单片机有合理的运行速度;利用液晶屏LCD1602显示时间信息,通过对AT89S52单片机的编程控制液晶屏LCD1602的显示。显示时间在LCD1602,通过按键切换选择。外部按键可及时设定或调整时间信息。四、 各模块功能及工作原理4.4
4、.1. 单片机主控制模块的设计AT89S52是一种低功耗、高性能CMOS8位微控制器,具有8K 在系统可编程Flash 存储器。AT89S52单片机为40引脚双列直插芯片,有四个I/O口P0,P1,P2,P3, MCS-51单片机共有4个8位的I/O口(P0、P1、P2、P3),每一条I/O线都能独立地作输出或输入。18引脚和19引脚接时钟电路,XTAL1接外部晶振和微调电容的一端,在片内它是振荡器倒相放大器的输入,XTAL2接外部晶振和微调电容的另一端,在片内它是振荡器倒相放大器的输出。第9引脚为复位输入端,接上电容,电阻及开关后够上电复位电路,20引脚为接地端,40引脚为电源端。引脚图如图
5、图4.1: 图4.1 AT89S52 引脚结构 图4.2.1 LCD1602 引脚结构4.2. LCD1602显示模块4.2.1LCD1602引脚介绍 LCD1602采用标准的14脚(无背光)或16脚(带背光)接口,引脚图如图图4.2.1:各引脚接口说明如表4.2.2所示:编号符号引脚说明编号符号引脚说明1VSS电源地9D2数据2VDD电源正极10D3数据3VL液晶显示偏压11D4数据4RS数据/命令选择12D5数据5R/W读/写选择13D6数据6E使能信号14D7数据7D0数据15BLA背光源正极8D1数据16BLK背光源负极表 4.2.2 LCD1602引脚说明第1脚:VSS为地电源。第2
6、脚:VDD接5V正电源。第3脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。第5脚:R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS和R/W共同为低电平时可以写入指令或者显示地址,当RS为低电平R/W为高电平时可以读忙信号,当RS为高电平R/W为低电平时可以写入数据。第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。第714脚:D0D7为8位双向数据线。第15脚:背光源正极。第16脚:背
7、光源负极。4.2.2LCD1602指令1602液晶模块内部的控制器共有11条控制指令,如表4.2.3编号指令RSR/WD7D6D5D4D3D2D1D01清显示00000000012光标返回000000001*3置输入模式00000001I/DS4显示开/关控制0000001DCB5光标或字符移位000001S/CR/L*6置功能00001DLNF*7置字符发生存贮器地址0001字符发生存贮器地址8置数据存贮器地址001显示数据存贮器地址9读忙标志或地址01BF计数器地址10写数到CGRAM或DDRAM)10要写的数据内容11从CGRAM或DDRAM读数11读出的数据内容表4.2.3 LCD16
8、02的指令说明1602液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。(说明:1为高电平、0为低电平)指令1:清显示,指令码01H,光标复位到地址00H位置。指令2:光标复位,光标返回到地址00H。指令3:光标和显示模式设置 I/D:光标移动方向,高电平右移,低电平左移 S:屏幕上所有文字是否左移或者右移。高电平表示有效,低电平则无效。指令4:显示开关控制。D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示 C:控制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁。指令5:光标或显示移位 S/C:高电平时移动显示的文字,低
9、电平时移动光标。指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线 N:低电平时为单行显示,高电平时双行显示 F: 低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符。指令7:字符发生器RAM地址设置。指令8:DDRAM地址设置。指令9:读忙信号和光标地址 BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。指令10:写数据。指令11:读数据。4.2.3 LCD1602读/写操作LCD1602基本操作时序说明,如表4.2.4读状态输入RS=L,R/W=H,E=H输出D0D7=状态字写指令输入RS=L,R/W=L,D0D7=指令码,E=高
10、脉冲输出无读数据输入RS=H,R/W=H,E=H输出D0D7=数据写数据输入RS=H,R/W=L,D0D7=数据,E=高脉冲输出无表4.2.4 LCD1602基本操作时序说明4.2.4 LCD1602显示模块流程图按下按键?开始LCD 1602初始界面显示欢迎界面显示初始时间结束NY4.3. 键盘模块 本设计采用4乘4键盘的反转法控制万年历的计时和时间设定,4乘4键盘电路图如图图4.3.1 图4.3.2012348+59-674.3.1键盘功能图开始对键盘进行扫描,返回键值键值为+或-?键值为?键值为?键值为09?键值为13?4.4.2流程图 N Y YN N Y Y NNY Y NNY NY
11、五、 实现结果六、 系统的实用性及创新性基本功能:能显示当前时间和计时,实现基本时钟功能。创新性:界面友好,能实现计时和键盘数字的时间设定和自增、自减的时间设定。七、 调节中遇到的问题及心得体会问题一 LCD1602的初始化不规范,导致无法正确在LCD1602上显示相应的字符,时间等。解决 在网上及课本上查找有关LCD1602初始化的程序,找出错误的地方并及时改正,最终解决了LCD1602的初始化问题。问题二 在对秒、分、时、日、月、年等的大小判断时,采用逐位判断,导致程序冗长,不利于程序的优化。解决 通过老师的指导及其他相关程序的借鉴,对时间大小的判断进行优化,将秒的十位和各位合为一个整体进
12、行判断,分、时、日、月、年类似。问题三 在计时模块中,因为细节问题,找不到导致不能正常计时的原因。解决 通过老师的精心指导,找到不能正常计时的原因,将中断次数的判断if(count100)改为if(count=100)即可。问题四 在键盘设计模块中,对空数组的定义无效。解决 通过查找相关资料,了解到空数组的定义要放在data中,不能放在code中。将空数组定义为uchar a14使其默认放在data中就解决了该问题。八、 程序设计5.6.7.8.8.1. 流程图开始显示“SHOWTIME”界面 WELCOME设置键按下?显示当前时间键盘数字进行时间设置键盘自增、自减进行时间设置开始计时按键开始
13、按下?NYY Y8.2. 源代码#include#define uchar unsigned char#define uint unsigned int uchar code Buffer4=0xfe,0xfd,0xfb,0xf7;uchar code table=0,1,2,3,4,5,6,7,8,9,+,-,!,; uchar code w14=0x83,0x84,0x85,0x86,0x88,0x89,0x8b,0x8c,0xc4,0xc5,0xc7,0xc8,0xca,0xcb;uchar a14;sbit E=P27;/1602使能引脚sbit RW=P26;/1602读写引脚sbi
14、t RS=P25;/1602数据/命令选择引脚void Delay(uint xms); /延时void Time0_Init();/中断请求void timer1_int(void); /中断void charge();/判断秒分时日月等是否大于额外值,若大于向上一位加一void ftime();/初始时间void timeon();/计时void add();/自加void sub();/自减void wcmd(uchar del);/1602写指令void write(uchar del);/1602写数据void L1602_init(void);/1602初始化void second
15、();/秒显示void minute();/分显示void hours();/时显示void days();/日显示void month();/月显示void years();/年显示void other();/符号显示void number();/键盘输入数字uint count,t; /中断执行次数,光标位置参数uchar sec=0;/初始秒uchar min=0;/初始分uchar hour=0;/初始时uchar day=0;/初始日uchar mon=0;/初始月uchar yearh=0;/初始年前两位uchar yearl=0;/初始年后两位/1602命令函数void wcmd
16、(uchar del) P0 = del;RS = 0; RW = 0;E = 1;Delay(1);E = 0;Delay(1); / 1602写数据函数void write(uchar del) P0 = del;RS = 1;RW = 0;E = 1;Delay(1);E = 0;Delay(1);/ 1602初始化void L1602_init(void)wcmd(0x38);wcmd(0x38);wcmd(0x38);wcmd(0x0e);wcmd(0x06); wcmd(0x01);/显示秒void second() uchar i,j; i=sec/10; j=sec%10; w
17、cmd(0xca); write(tablei); write(tablej);/显示分void minute() uchar i,j; i=min/10; j=min%10; wcmd(0xc7); write(tablei); write(tablej); /显示时void hours() uchar i,j; i=hour/10; j=hour%10; wcmd(0xc4); write(tablei); write(tablej);/显示日void days() uchar i,j; i=day/10; j=day%10; wcmd(0x8b); write(tablei); writ
18、e(tablej); /显示月void month() uchar i,j; i=mon/10; j=mon%10; wcmd(0x88); write(tablei); write(tablej);/显示年void years() uchar i,j,m,n; i=yearh/10; j=yearh%10; m=yearl/10; n=yearl%10; wcmd(0x83); write(tablei); write(tablej); write(tablem); write(tablen);/符号显示void other() wcmd(0xc9); write(:); wcmd(0xc6
19、); write(:); wcmd(0x87); write(-); wcmd(0x8a); write(-);/延时void Delay(uint xms) uint i,j; for(i=0;ixms;i+) for(j=0;j=100) count=0; charge(); ftime();/显示初始时间/时间初值void ftime() second();Delay(5); minute();Delay(5); hours();Delay(5); days();Delay(5); month();Delay(5); years();Delay(5); other();Delay(5);
20、/各个按键返回值uint Keyvalue() uint i,j; uchar temp; uint Key_value; while(1) P1=0xf0; if(P1!=0xf0) Delay(100); if(P1!=0xf0) for(j=0;j4;j+) P1=Bufferj; temp=0x10; for(i=0;i4;i+) if(!(P1&temp) Key_value=i+j*4; temp=1; return Key_value; /字符串显示void L1602_string(uchar hang,uchar lie,uchar *p)uchar a,b=0;if(han
21、g = 1) a = 0x80;if(hang = 2) a = 0xc0;a = a + lie - 1;while(1)wcmd(a+);b+;if(*p = 0)|(b=16) break;write(*p);Delay(500);p+;/自增void add() wcmd(wt); /光标置位 if(t=1) /光标在第二个位置时 if(yearh99) /判断年前两位是否小于99,是,年前两位加1,并显示 yearh+;years(); else if(t=3) /光标在第四个位置时 if(yearl99) /判断年后两位是否小于99,是,年后两位加1,并显示 yearl+; yea
22、rs(); else if(t=5) /光标在第六个位置时 if(mon12) /判断月是否小于12,是,月加1,并显示 mon+; month(); else if(t=7) /光标在第八个位置时 if(day30) /判断日是否小于30,是,日加1,并显示 day+; days(); else if(t=9)/当光标在第十个位置时 if(hour12)/判断时是否小于12,是,时加1,并显示 hour+; hours(); else if(t=11) /光标在第十二个位置时 if(min59) /判断分是否小于59,是,分加1,并显示 min+;minute(); else if(t=13
23、) /光标在第十四个位置时 if(sec0) yearh-;years(); else if(t=3) /光标在第四个位置时,判断年后两位是否大于0,是,年后两位减1,并显示 if(yearl1) yearl-; years(); else if(t=5)/光标在第六个位置时,判断月是否大于1,是,月减1,并显示 if(mon1) mon-; month(); else if(t=7)/光标在第八个位置时,判断日是否大于1,是,日减1,并显示 if(day1) day-; days(); else if(t=9) /光标在第十个位置时,判断时是否大于0,是,时减1,并显示 if(hour0)
24、hour-; hours(); else if(t=11) /光标在第十二个位置时,判断分是否大于0,是,分减1,并显示 if(min0) min-;minute(); else if(t=13) /光标在第十四个位置时,判断秒是否大于0,是,秒减1,并显示 if(sec0) sec-; second(); /主函数void main()uchar keys; uint i,key; /数组a的参数i=0; t=0; /位置参数L1602_init(); /1602初始化L1602_string(1,5,Showtime);/初始界面显示 L1602_string(2,5,Welcome!);
25、/初始界面显示while(1) key=Keyvalue(); /将键值赋值给key keys=tablekey; if(keys=) /判断键值是否为,是,执行计时 Time0_Init(); while(1) timeon(); else if(keys=!)/判断键值是否为!,是,显示初始时间,光标在第一个位置 ftime(); wcmd(0x83); else if(keys=-|keys=+) /判断键值是否为+或- if(keys=+) /键值为+,执行自加函数 add(); else /键值为-,执行自减函数 sub(); /判断键值是否为,是,光标不在最左边时,光标左移一位 e
26、lse if(keys=1) i-;t=t-1; wcmd(wt); else if(keys=) /判断键值是否为,是,光标不在最右边时,光标右移一位 if(t13) i+;t=t+1; wcmd(wt); else /键值为数字键时,将键值放入a数组中,在调用函数,显示当前设置的时间 number(); i=i%14; ai=key; i+; t+; number(); /输入数字void number() yearh=a0*10+a1;yearl=a2*10+a3;mon=a4*10+a5;day=a6*10+a7;hour=a8*10+a9;min=a10*10+a11;sec=a12
27、*10+a13;ftime();/中断请求void Time0_Init() TMOD=0X10; TH1=(65536-10000)/256; TL1=(65536-10000)%256; EA=1; ET1=1; TR1=1;/中断void timer1_int(void) interrupt 3 count+; TH1=(65536-10000)/256; TL1=(65536-10000)%256;/判断年月日是否超过额外值void charge() sec+; /秒加1 if(sec=60) /秒等于60时,分加1,秒置0 sec=0; min+; if(min=60) /分等于60
28、时,时加1 ,分置0 min=0; hour+; if(hour=24) /时等于24时,日加1,时置0 hour=0; day+; if(day=31) /日等于30时,月加1,日置1 day=1; mon+; if(mon=13) /月等于613时,年后两位加1,月置1 mon=1; yearl+; if(yearl=99) /年后两位等于99时,年前两位加1,年后两位置0 yearh=0; yearh+; if(yearh=99) /年前两位等于99时,年前两位置0 yearh=0; 九、 总结及感谢在用单片机实现万年历的设计中使用到了AT89S52、LCD1602及其4*4键盘的使用。
29、在设计过程中我通过在网上和图书馆查阅资料,收集了关于单片机和液晶屏LCD1602显示方面的资料,通过对这些资料的学习,了解了单片机的基本结构和单片机在生活和生产中所发挥的作用以及液晶屏LCD1602的原理和使用。在整个设计过程中,发挥团队精神,分工合作,充分发挥人的主观能动性,自主学习,学到了许多没学到的知识,较好的完成了作品。虽然这次顺利地完成的设计,但这之中还有很多需要去改进的地方还有很多进步的空间,我们会继续努力去改进,不会因为科技节的结束而停止学习。这次能顺利完成设计,首先我们要感谢我们的指导老师郑旭丹老师的热情关怀和悉心指导,在设计过程中,老师总是耐心的为答疑。最后,我们要感谢彼此,感谢彼此的对于这次比赛的热忱,感谢彼此的包容,感谢彼此的谅解。