一、LCD12864液晶的工作原理
液晶显示屏中的业态光电显示材料,利用液晶的电光效应把电信号转换成数字符、图像等可见信号。
如图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&TImes;64 全点阵液晶显示器组成。可完成图形显示,也可以显示8&TImes;4个(16&TImes;16点阵)汉字。
图1-1 12864LCD液晶显示屏
二、方案设计
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-1 LCD显示程序和初始化子程序流程图
三、仿真和分析
将程序下载到单片机开发板上,LCD12864显示如下图,第一行为汉字“数字电子钟”,第二行为时分秒,第三行为年月日以及星期,第四行为闹钟,通过按键可实现时间的调整,也可实现整点报时和闹钟。符合设计要求。
图9-1 实物仿真图
程序:
#include《reg52.h》
{ uchar i,j; for(i=xms;i》0;i--)
for(j=110;j》0;j--);
}
void warn(uchar xn)//“嘟”xn次函数 { uint nn;
for(nn=0;nn《xn;nn++) { uint n;
for(n=2000;n》0;n--) { beep=1; delayms(1); beep=0; delayms(2);
}
for(n=1000;n》0;n--) { beep=1;
delayms(3);
}
}
}
void warn3s()//3s报警函数 { uint n;
for(n=3000;n》0;n--) { beep=0; delayms(2); beep=1; delayms(1);
}
}
void write_com(uchar com)//12864写指令函数 { rs=0; rw=0; en=0; P2=com; delayms(5); en=1; delayms(5); en=0; }
void write_data(uchar date)//12864数据指令函数 { rs=1; rw=0; en=0; P2=date; delayms(5); en=1; delayms(5); en=0;
}
{ X=0x88;
} if(X==3) { X=0x98; } pos=X+Y; write_com(pos);
}
void write_sfm(int add,uint date)//时钟数值函数 { uchar shi,ge; shi=date/10; ge=date%10; lcd_pos(1,0+add); write_data(0x30+shi); write_data(0x30+ge);
}
void write_sfm1(int add1,uint date1)//年月日数值函数 { uchar shi,ge;
shi=date1/10;
void lcd_pos(uchar X,uchar Y)//12864显示位置函数 { uchar pos; 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);
}
void write_sfm(int add,uint date)//时钟数值函数 { uchar shi,ge; shi=date/10; ge=date%10; lcd_pos(1,0+add); write_data(0x30+shi); write_data(0x30+ge);
}
void write_sfm1(int add1,uint date1)//年月日数值函数 { uchar shi,ge;
shi=date1/10;
ge=date1%10; lcd_pos(2,0+add1); write_data(0x30+shi); write_data(0x30+ge);
}
void write_sfm2(int add2,uint date2)//闹钟数值函数 { uchar shi,ge; shi=date2/10; ge=date2%10; lcd_pos(3,0+add2); write_data(0x30+shi); write_data(0x30+ge);
}
{ 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)
void keyscan()//按键扫描函数 { if(k0==0)//闹钟按键操作 { delayms(5); if(k0==0) { while(!k0); kk++;
if(kk==1)
{ 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);
}
}
}
}
}
void init()//初始化函数(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;
}
void main()//主函数 { uchar i; 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() interrupt 1//定时器函数 { 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)
{ shi=0; zhou++; if(zhou==8) { zhou=1;
} ri++;
if(yue==1||yue==3||yue==5||yue==7||yue==8||yue==10||yue==12) { if(ri==32) { ri=1; yue++; if(yue==13) { yue=1; nian++;
}
}
}
if(yue==4||yue==6||yue==9||yue==11) { if(ri==31)
{
ri=1; yue++; if(yue==13) { yue=1; nian++;
}
}
}
if(yue==2) { if((nian%4)==0) { if(ri==30) { ri=1; yue++; if(yue==13) { yue=1; nian++;
}
}
}
if((nian%4)!=0)
{ if(ri==29) { ri=1; yue++; if(yue==13) { yue=1; nian++;
}
}
write_sfm1(0,nian);
}
write_sfm1(2,yue);
}
write_sfm1(7,zhou); write_sfm1(4,ri);
}
write_sfm(0,shi);
}
write_sfm(2,fen);
}
write_sfm(4,miao);
}
}