LCD12864液晶显示电子钟设计.docx
《LCD12864液晶显示电子钟设计.docx》由会员分享,可在线阅读,更多相关《LCD12864液晶显示电子钟设计.docx(32页珍藏版)》请在冰豆网上搜索。
LCD12864液晶显示电子钟设计
《单片机原理及应用》
课程设计说明书
题目
LCD12864液晶显示电子钟设计
系(部)
专业(班级)
姓名
学号
指导教师
起止日期
课程设计任务书
系(部):
专业:
课题名称
LCD12864液晶显示电子钟设计
设计要求
设计一种基于AT89S52单片机的液晶显示电子时钟,要求如下:
(1)、能正确显示时间、日期和星期显示格式为:
时间:
XX小时:
XX分:
XX秒;日期:
XX年:
XX月:
XX日;星期:
X。
(2)、时间能够由按键调整,误差小于1S。
(3)、闹钟功能:
时间运行到与闹钟设定时间时,闹钟响(持续响3秒)。
(4)、报时功能:
时间运行到正点时间时,闹钟响,几点钟就响几声(每
声持续响2秒,每两声之间时间间隔1秒)。
液晶显示器第一行显示“数字电子钟”;第二行显示“当前时间”;第三
行显示日期和星期;第四行显示最近一个闹钟的设定时间。
2、要求:
完成该系统的硬件和软件的设计,在Proteus软件上仿真通过,并提交
一篇课程设计说明书。
设计工作量
1、汇编或C51语言程序设计;
2、程序调试;
3、在Proteus上进行仿真成功,进行实验板下载调试;
4、提交一份完整的课程设计说明书,包括设计原理、程序设计、程序
分析、仿真分析、调试过程,参考文献、设计总结等。
工作计划
起止日期
工作内容
第一天
课题绍,答疑,收集材料,C51介绍
第二天
设计方案论证,练习编写C51程序
第三天~第六天
程序设计
第六天~第八天
程序调试、仿真
第九天~第十天
系统测试并编写设计说明书
教研室
意见
年月日
系(部)主管领导意见
年月日
一、12864液晶的工作原理
液晶显示屏中的业态光电显示材料,利用液晶的电光效应把电信号转换成数字符、图像等可见信号。
如图1-1,液晶正常情况下,其分子排列很有秩序,显得清澈透明,一旦加上直流电场后,分子的排列被打乱,一部分液晶变的不透明,颜色加深因而能显示数字和图像。
管脚一共1个CS1左半屏片选端,CS2右半屏片选端;V0液晶显示驱动电压,通过一个电位器接到VCC;RS数据指令选择信号,H为数据,L为指令,也叫D/I;R/W读写选择信号,H为读,L为写,。
E为LCD使能端,R/W为L时,E信号下降沿锁存
DB7-DB0;R/W为H时,E为H,DDRAM数据读到DB7-DB0。
DB0-DB7数据传输端口。
RST复位信号。
-VOUT
和V0为液晶显示驱动电压。
12864是一种图形点阵液晶显示器,它主要由行驱动器/列驱动器及128×64
全点阵液晶显示器组成。
可完成图形显示,也可以显示8×4个(16×16点阵)汉字。
图1-112864LCD液晶显示屏
二、方案设计
2.1实物硬件设计
单片机控制液晶显示屏系统总共可分为六个环节,分别是单片机控制系统、12864字符显示模块、控制开关模块、晶振控制模块、复位电路模块和DS1302时钟控制模块。
通过这六个模块的协调工作就可以完成相应的液晶屏控制和显示功能。
这六个模块的相互连接如图2-1:
图2-1硬件组成框图
2.2系统硬件设计
本硬件电路主要由四大模块组成:
主芯片模块;晶振和复位电路模块;控制接钮模块;显示电路模块。
2.2.1主芯片模块
主芯片模块即单片机模块,XTAL1:
接外部晶振和微调电容的一端。
在片内,它是振荡电路反相放大器的输入端。
XTAL2:
接外部晶振和微调是容的一端。
RST:
AT89C51的复位信号输入引脚,高电平有效。
当此输入端保持两个机器周期的高电平时,就可以完成复位操作。
ALE:
允许地址锁存信号端。
EA:
该引脚为低电平时,则读取外部的程序代码来执行程序。
P0、P1、P2、P3:
8位并行输入输出口。
每个端口都是8位准双向口,共占32只引脚。
每一条都能独立地用作输入或输出。
每个端口都包括一个锁存器、一个输出驱器和输入缓冲器。
作输出时,数据可以锁存;作输入时,数据可以缓冲。
图如图3—1。
图3-1单片机引脚图
2.2.2晶振和复位模块
89C51芯片内部有一个高增益反相放大器,用于构成振荡器。
如图3—2,反相放大器的输入端为XTAL1,输出端XTAL2,两个跨接石英晶体及两个电容就可以构成稳定的自激振荡器。
XTAL1是片内振荡器的反相放大器输入端,XTAL2则是输出端,使用外部振荡器时,外部振荡信号应直接加到XTAL1,而XTAL2
悬空。
一个晶体振荡器,接在单片机内部的振荡电路上,两个电容是起振电容,频率越高,应该越小。
图4-1晶振模块
在振荡器运行时,有两个机器周期(24个振荡周期)以上的高电平出现在此引脚时,将使单片机复位,只要这个脚保持高电平,51芯片便循环复位。
复位后P0-P3口均置1引脚表现为高电平,程序计数器和特殊功能寄存器SFR全部清零。
当复位脚由高电平变为低电平时,芯片为ROM的00H处开始运行程序。
如上图5-1所示复位电路,由于复位时高电平有效,当刚接上电源的瞬间,电容C1两端相当于短路,即相当于给RESET引脚一个高电平,等充电结束时(这个时间很短暂),电容相当于断开,这时已经完成了复位动作。
图5-1复位模块
2.2.3按钮模块
本模块采用四个按钮进行控制,通过串行口输入输出连接,当K1按键波动一次后,方可进行年、月、日、星期、时、分的改变,当循环满时,按下K0可实现对闹钟的改变。
按键K2、K3分别实现加一减一的操作。
图6-1按钮模块
2.3系统软件设计
2.3.1主程序设计
图7-1主程序流程图
图8-1LCD显示程序和初始化子程序流程图
三、仿真和分析
将程序下载到单片机开发板上,LCD12864显示如下图,第一行为汉字“数字电子钟”,第二行为时分秒,第三行为年月日以及星期,第四行为闹钟,通过按键可实现时间的调整,也可实现整点报时和闹钟。
符合设计要求。
图9-1实物仿真图
程序:
#include
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
sbitrs=P1^0;//12864引脚定义
sbitrw=P1^1;
sbiten=P1^2;
sbitPSB=P1^3;
sbitbeep=P3^4;//蜂鸣器引脚定义
sbitk1=P3^5;//按键定义
sbitk2=P3^6;
sbitk3=P3^7;
sbitk0=P0^0;
uintt,k,kk;
ucharshi,fen,miao,nian=13,yue,ri,zhou,shi0,fen0,miao0;
ucharcodedis1[]={0xca,0xfd,"字电子钟"};//显示字组
ucharcodedis2[]={"00时00分00秒"};
ucharcodedis3[]={"00年00月00日1"};
ucharcodedis4[]={"闹钟00时00分00秒"};
voiddelayms(uintxms)//延时xms函数
{
uchari,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
voidwarn(ucharxn)//“嘟”xn次函数
{
uintnn;
for(nn=0;nn{
uintn;
for(n=2000;n>0;n--)
{
beep=1;
delayms
(1);
beep=0;
delayms
(2);
}
for(n=1000;n>0;n--)
{
beep=1;
delayms(3);
}
}
}
voidwarn3s()//3s报警函数
{
uintn;
for(n=3000;n>0;n--)
{
beep=0;
delayms
(2);
beep=1;
delayms
(1);
}
}
voidwrite_com(ucharcom)//12864写指令函数
{
rs=0;
rw=0;
en=0;
P2=com;
delayms(5);
en=1;
delayms(5);
en=0;
}
voidwrite_data(uchardate)//12864数据指令函数
{
rs=1;
rw=0;
en=0;
P2=date;
delayms(5);
en=1;
delayms(5);
en=0;
}
voidlcd_pos(ucharX,ucharY)//12864显示位置函数
{
ucharpos;
if(X==0)
{
X=0x80;
}
if(X==1)
{
X=0x90;
}
if(X==2)
{
X=0x88;
}
if(X==3)
{
X=0x98;
}
pos=X+Y;
write_com(pos);
}
voidwrite_sfm(intadd,uintdate)//时钟数值函数
{
ucharshi,ge;
shi=date/10;
ge=date%10;
lcd_pos(1,0+add);
write_data(0x30+shi);
write_data(0x30+ge);
}
voidwrite_sfm1(intadd1,uintdate1)//年月日数值函数
{
ucharshi,ge;
shi=date1/10;
ge=date1%10;
lcd_pos(2,0+add1);
write_data(0x30+shi);
write_data(0x30+ge);
}
voidwrite_sfm2(intadd2,uintdate2)//闹钟数值函数
{
ucharshi,ge;
shi=date2/10;
ge=date2%10;
lcd_pos(3,0+add2);
write_data(0x30+shi);
write_data(0x30+ge);
}
voidkeyscan()//按键扫描函数
{
if(k0==0)//闹钟按键操作
{
delayms(5);
if(k0==0)
{
while(!
k0);
kk++;
if(kk==1)
{
TR0=0;
write_com(0x0f);
lcd_pos(3,2);
}
}
if(kk==2)
{
lcd_pos(3,4);
}
if(kk==3)
{
lcd_pos(3,6);
}
if(kk==4)
{
kk=0;
TR0=1;
write_com(0x0c);
}
}
if(k1==0)//调试按键操作
{
delayms(5);
if(k1==0)
{
k++;
while(!
k1);
if(k==1)
{
TR0=0;
write_com(0x0f);
lcd_pos(1,4);
}
}
if(k==2)
{
lcd_pos(1,2);
}
if(k==3)
{
lcd_pos(1,0);
}
if(k==4)
{
lcd_pos(2,4);
}
if(k==5)
{
lcd_pos(2,2);
}
if(k==6)
{
lcd_pos(2,0);
}
if(k==7)
{
lcd_pos(2,7);
}
if(k==8)
{
k=0;
write_com(0x0c);
TR0=1;
}
}
if(k!
=0)
{
if(k2==0)//“+1”按键操作
{
delayms(5);
if(k2==0)
{
while(!
k2);
if(k==1)
{
miao++;
if(miao==60)
miao=0;
write_sfm(4,miao);
lcd_pos(1,4);
//write_sfm(4,miao);
}
if(k==2)
{
fen++;
if(fen==60)
fen=0;
write_sfm(2,fen);
lcd_pos(1,2);
//write_sfm(2,fen);
}
if(k==3)
{
shi++;
if(shi==24)
shi=0;
write_sfm(0,shi);
lcd_pos(1,0);
//write_sfm(0,shi);
}
if(k==4)
{
ri++;
if(ri==32)
ri=1;
write_sfm1(4,ri);
lcd_pos(2,4);
//write_sfm1(4,ri);
}
if(k==5)
{
yue++;
if(yue==13)
yue=1;
write_sfm1(2,yue);
lcd_pos(2,2);
//write_sfm1(2,yue);
}
if(k==6)
{
nian++;
if(nian==50)
nian=0;
write_sfm1(0,nian);
lcd_pos(2,0);
//write_sfm1(0,nian);
}
if(k==7)
{
zhou++;
if(zhou==8)
zhou=0;
write_sfm1(7,zhou);
lcd_pos(2,7);
//write_sfm1(7,zhou);
}
}
}
if(k3==0)//“-1按键操作”
{
delayms(5);
if(k3==0)
{
while(!
k3);
if(k==1)
{
miao--;
if(miao==-1)
miao=59;
write_sfm(4,miao);
lcd_pos(1,4);
//write_sfm(4,miao);
}
if(k==2)
{
fen--;
if(fen==-1)
fen=59;
write_sfm(2,fen);
lcd_pos(1,2);
//write_sfm(2,fen);
}
if(k==3)
{
shi--;
if(shi==-1)
shi=23;
write_sfm(0,shi);
lcd_pos(1,0);
//write_sfm(0,shi);
}
if(k==4)
{
ri--;
if(ri==-1)
ri=31;
write_sfm1(4,ri);
lcd_pos(2,4);
//write_sfm1(4,ri);
}
if(k==5)
{
yue--;
if(yue==-1)
yue=12;
write_sfm1(2,yue);
lcd_pos(2,2);
//write_sfm1(2,yue);
}
if(k==6)
{
nian--;
if(nian==-1)
nian=50;
write_sfm1(0,nian);
lcd_pos(2,0);
//write_sfm1(0,nian);
}
if(k==7)
{
zhou--;
if(zhou==-1)
zhou=7;
write_sfm1(7,zhou);
lcd_pos(2,7);
//write_sfm1(7,zhou);
}
}
}
}
if(k==0)
{
if(k2==0)
{
delayms(5);
if(k2==0)
{
while(!
k2);
if(kk==3)
{
miao0++;
if(miao0==60)
miao0=0;
write_sfm2(6,miao0);
lcd_pos(3,6);
//write_sfm2(6,miao0);
}
if(kk==2)
{
fen0++;
if(fen0==60)
fen0=0;
write_sfm2(4,fen0);
lcd_pos(3,4);
//write_sfm2(4,fen0);
}
if(kk==1)
{
shi0++;
if(shi0==24)
shi0=0;
write_sfm2(2,shi0);
lcd_pos(3,2);
//write_sfm2(2,shi0);
}
}
}
if(k3==0)
{
delayms(5);
if(k3==0)
{
while(!
k3);
if(kk==3)
{
miao0--;
if(miao0==-1)
miao0=59;
write_sfm2(6,miao0);
lcd_pos(3,6);
//write_sfm2(6,miao0);
}
if(kk==2)
{
fen0--;
if(fen0==-1)
fen0=59;
write_sfm2(4,fen0);
lcd_pos(3,4);
//write_sfm2(4,fen0);
}
if(kk==1)
{
shi0--;
if(shi0==-1)
shi0=23;
write_sfm2(2,shi0);
lcd_pos(3,2);
//write_sfm2(2,shi0);
}
}
}
}
}
voidinit()//初始化函数(12864初始化,定时器初始化)
{
PSB=1;
write_com(0x30);
delayms(5);
write_com(0x0c);
delayms(5);
write_com(0x01);
delayms(5);
TH0=(65535-50000)/256;
TL0=(65535-50000)%256;
TMOD=0x01;
ET0=1;
EA=1;
TR0=1;
}
voidmain()//主函数
{
uchari;
delayms(10);
init();
lcd_pos(0,2);//第一排显示
i=0;
while(dis1[i]!
='\0')
{
write_data(dis1[i]);
i++;
}
lcd_pos(1,0);//第二排显示
i=0;
while(dis2[i]!
='\0')
{
write_data(dis2[i]);
i++;
}
lcd_pos(2,0);//第三行显示
i=0;
while(dis3[i]!
='\0')
{
write_data(dis3[i]);
i++;
}
lcd_pos(3,0);//第四行显示
i=0;
while(dis4[i]!
='\0')
{
write_data(dis4[i]);
i++;
}
while
(1)
{
keyscan();
if(miao==0&&fen==0&&TR0==1)//整点报时判断
{
warn(shi);
}
if(miao==miao0&&fen==fen0&&shi==shi0&&TR0==1)//闹钟判断
{
warn3s();
}
if(miao==0&&fen==0&&miao==miao0&&fen==fen0&&shi==shi0&&TR0==1)//整点报时、闹钟时冲突操作
{
warn3s();
}
}
while
(1);
}
voidtimer()interrupt1//定时器函数
{
TH0=15535/256;
TL0=15535%256;
t++;//50ms计数一次
if(t==20)
{
t=0;
miao++;
if(miao==60)
{
miao=0;
fen++;
if(fen==60)
{
fen=0;
shi++;
if(shi==24)
{