基于51单片机的万年历.docx
《基于51单片机的万年历.docx》由会员分享,可在线阅读,更多相关《基于51单片机的万年历.docx(46页珍藏版)》请在冰豆网上搜索。
基于51单片机的万年历
微机与单片机技术实践课程设计报告
一、课程设计教学目的及基本要求
1.了解并掌握单片机的原理、结构、指令、运行模式、功能模块及应用开发方法。
2.提高综合运用所学的理论知识独立分析和解决问题的能力。
3.掌握汇编语言的设计和调试。
4.掌握C语言的设计和调试。
二、课程设计内容及安排
1.掌握各种进制数的特点及其转换方法。
2.掌握PIC/51单片机的硬件结构的特点,详细了解PIC/51单片机的各种资源。
3.了解单片机的指令系统、指令格式及其意义。
4.理解中断的基本概念,了解单片机的中断响应。
5.掌握存储器的分类,熟练掌握存储器的扩展。
6.了解单片机的接口技术及其串行通讯方式。
7.编写课程设计报告,掌握汇编语言的设计和调试方法。
三、课程设计要求
题目2LCD显示的电子钟
设计任务:
以PIC16F877/89C51单片机控制的时钟,在LCD显示器上显示当前的时间。
设计要求:
1、使用文字型LCD显示器显示当前时间。
2、显示格式为“时时:
分分:
秒秒”。
3、用3个功能键操作来设置当前时间。
功能键K1~K34功能如下。
(1)K1——进入设置现在的时间。
(2)K2——设置小时。
(3)K3——设置分钟。
(4)K4——确认完成设置。
4、程序执行后工作指示灯LED闪动,表示程序开始执行,LCD显示“00:
00:
00”,
然后开始计时。
扩充功能:
1、增加闹铃功能,时间到则产生音乐声。
2、增加闹铃功能,时间到则启动继电器控制家电。
3、增加万年历显示“年月日”。
4、结合温度传感器显示当前的温度。
5、结合湿度传感器显示当前的湿度。
一、设计简介
电子万年历是一种非常广泛日常计时工具,对现代社会越来越流行。
它可以对年、月、日、周日、时、分、秒进行计时,还具有闰年补偿等多种功能。
对于数字电子万年历采用直观的数字显示,可以同时显示年、月、日、星期、时、分、秒,还具有时间校准等功能。
该电路采用AT89C52单片机作为核心,功耗小,能在3V的低压工作,电压可选用3~5V电压供电。
本设计是基于51系列的单片机进行的电子万年历设计,可以显示年月日时分秒及星期信息,具有可调整日期和时间功能。
在设计的同时对单片机的理论基础和外围扩展知识进行了比较全面准备。
在硬件与软件设计时,没有良好的基础知识和实践经验会受到很大限制,每项功能实现时需要那种硬件,程序该如何编写,算法如何实现等,没有一定的基础就不可能很好的实现。
在编写程序过程中发现以现有的相关知识要独自完成编写任务困难重重,在同学和网络的帮助下才完成了程序的编写。
万年历的设计过程在硬件与软件方面进行同步设计。
硬件部分主要由AT89C52单片机,LCD1602显示电路,以及调时按键电路等组成。
在单片机的选择上本人使用了AT89C52单片机,该单片机适合于许多较为复杂控制应用场合,显示器使用1片LCD1602。
软件方面主要包括日历程序、时间调整程序,显示程序等。
本设计直接采用单片机定时计数器提供秒信号,使用程序实现年、月、日、星期、时、分、秒计数。
程序采用C语言编写,所有程序编写完成后,在KeiluVision3软件中进行调试,确定没有问题后,用STC_ISP_V4.80下载到单片机内进行检验。
最后在老师同学网络的帮助以及自己的努力下完成了此次电子万年历的设计。
二、系统的硬件设计与实现
洞洞板/万能板成品
图片左下角有地址-有录像
2.1电路设计框图
2.2系统硬件概述
本电路是由AT89C52单片机为控制核心,具有在线编程功能,低功耗,能在3V超低压工作;本设计直接采用单片机定时计数器提供秒信号,它可以对年、月、日、星期、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.5V~5.5V。
显示部份由LCD1602完成。
2.3主要单元电路的设计
2.3.1单片机主控制模块的设计
AT89C52单片机为40引脚双列直插芯片,有四个I/O口P0,P1,P2,P3,MCS-51单片机共有4个8位的I/O口(P0、P1、P2、P3),每一条I/O线都能独立地作输出或输入。
单片机的最小系统如下图所示,18引脚和19引脚接时钟电路,X1接外部晶振和微调电容的一端,在片内它是振荡器倒相放大器的输入,X2接外部晶振和微调电容的另一端,在片内它是振荡器倒相放大器的输出.第9引脚为复位输入端,接上电容,电阻及开关后够上电复位电路,20引脚为接地端,40引脚为电源端.如下图所示
2.3.2键盘电路模块的设计
键盘模块由四个独立键盘组成,每个按键的一钟脚接地,另一种脚接一个单片机I/O口。
如下图所示。
2.3.3显示模块的设计
显示模块通过一块16脚的LCD1602组成。
其中1、3脚接地,4、5、6分别接一个I/O口用于控制液晶的显示,7--14接P2的8个I/O口用于数据传输。
15、16脚用于控制液晶的背光,可不接。
如下图所示。
液晶1602的简介及驱动原理
1602LCD主要技术参数:
显示容量:
16×2个字符
芯片工作电压:
4.5—5.5V
工作电流:
2.0mA(5.0V)
模块最佳工作电压:
5.0V
字符尺寸:
2.95×4.35(W×H)mm
引脚功能说明
1602LCD采用标准的14脚(无背光)或16脚(带背光)接口,各引脚接口说明如表10-13所示:
编号
符号
引脚说明
编号
符号
引脚说明
1
VSS
电源地
9
D2
数据
2
VDD
电源正极
10
D3
数据
3
VL
液晶显示偏压
11
D4
数据
4
RS
数据/命令选择
12
D5
数据
5
R/W
读/写选择
13
D6
数据
6
E
使能信号
14
D7
数据
7
D0
数据
15
BLA
背光源正极
8
D1
数据
16
BLK
背光源负极
表10-13:
引脚接口说明表
第1脚:
VSS为地电源。
第2脚:
VDD接5V正电源。
第3脚:
VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。
第4脚:
RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。
第5脚:
R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。
当RS和R/W共同为低电平时可以写入指令或者显示地址,当RS为低电平R/W为高电平时可以读忙信号,当RS为高电平R/W为低电平时可以写入数据。
第6脚:
E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
第7~14脚:
D0~D7为8位双向数据线。
第15脚:
背光源正极。
第16脚:
背光源负极。
10.8.2.31602LCD的指令说明及时序
1602液晶模块内部的控制器共有11条控制指令,如表10-14所示:
序号
指令
RS
R/W
D7
D6
D5
D4
D3
D2
D1
D0
1
清显示
0
0
0
0
0
0
0
0
0
1
2
光标返回
0
0
0
0
0
0
0
0
1
*
3
置输入模式
0
0
0
0
0
0
0
1
I/D
S
4
显示开/关控制
0
0
0
0
0
0
1
D
C
B
5
光标或字符移位
0
0
0
0
0
1
S/C
R/L
*
*
6
置功能
0
0
0
0
1
DL
N
F
*
*
7
置字符发生存贮器地址
0
0
0
1
字符发生存贮器地址
8
置数据存贮器地址
0
0
1
显示数据存贮器地址
9
读忙标志或地址
0
1
BF
计数器地址
10
写数到CGRAM或DDRAM)
1
0
要写的数据内容
11
从CGRAM或DDRAM读数
1
1
读出的数据内容
表10-14:
控制命令表
1602液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。
(说明:
1为高电平、0为低电平)
指令1:
清显示,指令码01H,光标复位到地址00H位置。
指令2:
光标复位,光标返回到地址00H。
指令3:
光标和显示模式设置I/D:
光标移动方向,高电平右移,低电平左移S:
屏幕上所有文字是否左移或者右移。
高电平表示有效,低电平则无效。
指令4:
显示开关控制。
D:
控制整体显示的开与关,高电平表示开显示,低电平表示关显示C:
控制光标的开与关,高电平表示有光标,低电平表示无光标B:
控制光标是否闪烁,高电平闪烁,低电平不闪烁。
指令5:
光标或显示移位S/C:
高电平时移动显示的文字,低电平时移动光标。
指令6:
功能设置命令DL:
高电平时为4位总线,低电平时为8位总线N:
低电平时为单行显示,高电平时双行显示F:
低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符。
指令7:
字符发生器RAM地址设置。
指令8:
DDRAM地址设置。
指令9:
读忙信号和光标地址BF:
为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。
指令10:
写数据。
指令11:
读数据。
与HD44780相兼容的芯片时序表如下:
读状态
输入
RS=L,R/W=H,E=H
输出
D0—D7=状态字
写指令
输入
RS=L,R/W=L,D0—D7=指令码,E=高脉冲
输出
无
读数据
输入
RS=H,R/W=H,E=H
输出
D0—D7=数据
写数据
输入
RS=H,R/W=L,D0—D7=数据,E=高脉冲
输出
无
表10-15:
基本操作时序表
读写操作时序如图10-55和10-56所示:
图10-55读操作时序
图10-56写操作时序
10.8.2.41602LCD的RAM地址映射及标准字库表
液晶显示模块是一个慢显示器件,所以在执行每条指令之前一定要确认模块的忙标志为低电平,表示不忙,否则此指令失效。
要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符,图10-57是1602的内部显示地址。
10.8.2.51602LCD的一般初始化(复位)过程
延时15mS写指令38H(不检测忙信号)延时5mS写指令38H(不检测忙信号)延时5mS
写指令38H(不检测忙信号)以后每次写指令、读/写数据操作均需要检测忙信号
写指令38H:
显示模式设置写指令08H:
显示关闭写指令01H:
显示清屏
写指令06H:
显示光标移动设置写指令0CH:
显示开及光标设置
三、系统的软件设计
3.1程序流程框图
否否否
是是是
否否否
是是是
四、总结
在整个设计过程中,遇到了很多问题,但在自己的努力和同学的帮助下得到了解决,较好的完成了作品,勉强达到了预期的目的。
并且在这一过程中也学到了许多之前没学过的知识。
在电路焊接时虽然没什么大问题,但从中也知道了焊接在整个作品中的重要性,对电路的设计、布局要先有一个好的构思,然后再焊才可以使电路板美观并且可以减少飞线的使用,并且最好焊接一部分测试一部分。
通过这次设计,特别是通过程序的编写,更深入地了解了单片机的内部结构和外围器件的应用。
参考文献:
1.郭天祥《十天叫你学会单片机》
2.《C51入门教程》
3.《8051系列单片机C语言编程完全手册》
附录一:
系统电路图
附录二:
系统程序清单
#include
#include
sbitLCD_RS=P1^5;
sbitLCD_RW=P1^4;
sbitLCD_EN=P1^3;
sbits1=P2^3;
sbits2=P2^2;
sbits3=P2^0;
unsignedchartt,s1num;
charmiao,fen,shi,yue=1,ri=1,week,nian;
unsignedchara[]="2000-01-01MON";
charb[]="00:
00:
00";
voiddelay(intms)
{
inti;
while(ms--)
{
for(i=0;i<250;i++)
{
_nop_();
_nop_();
_nop_();
_nop_();
}
}
}
delay1(unsignedintz)
{unsignedcharx,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
bitlcd_busy()
{
bitresult;
LCD_RS=0;
LCD_RW=1;
LCD_EN=1;
_nop_();
_nop_();
_nop_();
_nop_();
result=(bit)(P3&0x80);
LCD_EN=0;
returnresult;
}
voidwrite_com(unsignedcharcom)
{
while(lcd_busy());
LCD_RS=0;
LCD_RW=0;
LCD_EN=0;
_nop_();
_nop_();
P3=com;
_nop_();
_nop_();
_nop_();
_nop_();
LCD_EN=1;
_nop_();
_nop_();
_nop_();
_nop_();
LCD_EN=0;
}
voidwrite_date(unsignedchardate)
{
while(lcd_busy());
LCD_RS=1;
LCD_RW=0;
LCD_EN=0;
P3=date;
_nop_();
_nop_();
_nop_();
_nop_();
LCD_EN=1;
_nop_();
_nop_();
_nop_();
_nop_();
LCD_EN=0;
}
voidwrite_sfm(unsignedcharadd,unsignedchardate)
{
unsignedcharshi,ge;
shi=date/10;
ge=date%10;
write_com(0x80+0x40+add);
write_date(0x30+shi);
write_date(0x30+ge);
}
voidwrite_nyr(unsignedcharadd,unsignedchardate)
{
unsignedchargw,sw;
gw=date%10;
sw=date/10;
write_com(0x80+add);
write_date(0x30+sw);
write_date(0x30+gw);
}
voidwrite_week(unsignedweek)
{
write_com(0x80+0x0d);
switch(week)
{
case0:
write_date('M');
write_date('O');
write_date('N');
break;
case1:
write_date('T');
write_date('U');
write_date('E');
break;
case2:
write_date('W');
write_date('E');
write_date('D');
break;
case3:
write_date('T');
write_date('H');
write_date('U');
break;
case4:
write_date('F');
write_date('R');
write_date('I');
break;
case5:
write_date('S');
write_date('A');
write_date('T');
break;
case6:
write_date('S');
write_date('U');
write_date('N');
break;
}
}
voidinit()
{unsignedinti;
write_com(0x38);
delay(5);
write_com(0x38);
delay(5);
write_com(0x38);
delay(5);
write_com(0x0c);
delay(5);
write_com(0x06);
delay(5);
write_com(0x01);
delay(5);
write_com(0x80);
for(i=0;i<16;i++)
{write_date(a[i]);
delay1(5);
}
write_com(0x80+0x40);
for(i=0;i<12;i++)
{write_date(b[i]);
delay1(5);
}
TMOD=0X01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
EA=1;
ET0=1;
TR0=1;
}
voidkeyscan()
{
if(s1==0)
{
delay(5);
if(s1==0)
{s1num++;
while(!
s1);
if(s1num==1)
{
TR0=0;
write_com(0x80+4);
write_com(0x0f);
}
if(s1num==2)
{
write_com(0x80+7);
}
if(s1num==3)
{
write_com(0x80+10);
}
if(s1num==4)
{
write_com(0x80+13);
}
if(s1num==5)
{
write_com(0x80+0x40+4);
}
if(s1num==6)
{
write_com(0x80+0x40+7);
}
if(s1num==7)
{
write_com(0x80+0x40+10);
}
if(s1num==8)
{
s1num=0;
write_com(0x0c);
TR0=1;
}
}
}
if(s1num!
=0)
{
if(s2==0)
{
delay(5);
if(s2==0)
{
while(!
s2);
if(s1num==7)
{
miao++;
if(miao==60)
miao=0;
write_sfm(10,miao);
write_com(0x80+0x40+10);
}
if(s1num==6)
{
fen++;
if(fen==60)
fen=0;
write_sfm(7,fen);
write_com(0x80+0x40+7);
}
if(s1num==5)
{
shi++;
if(shi==24)
shi=0;
write_sfm(4,shi);
write_com(0x80+0x40+4);
}
if(s1num==4)
{
week++;
if(week==7)
week=0;
write_week(week);
write_com(0x80+14);
}
if(s1num==3)
{
ri++;
if(yue==2&&(((nian+2000)%4==0)&&((nian+2000)%100!
=0)||((nian+2000)%400==0))&&ri==30)ri=1;
if(yue==2&&((nian+2000)%4!
=0)&&ri==29)ri=1;
if((yue==4||yue==6||yue==9||yue==11)&&ri==31)ri=1;
if(ri==32)ri=1;
write_nyr(10,ri);
write_com(0x80+10);
}
if(s1num==2)
{
yue++;
if(yue>12)
yue=1;
write_nyr(7,yue);
write_com(0x80+7);
}
if(s1num==1)
{
nian++;
if(nian>99)
nian=0;
write_nyr(4,nian);
write_com(0x80+4);
}
}
}
if(s3==0)
{
delay(5);
if(s3==0)
{
while(!
s3);
if(s1num==7)
{
miao--;
if(miao==-1)
miao=59;
write_sfm(10,miao);
write_com(0x80+0x40+10);
}
if(s1num==6)
{
fen--;
if(fen==-1)
fen=59;
write_sfm(7,fen);
write_com(0x80+0x40+7);
}
if(s1num==5)