lcd时钟文档.docx
《lcd时钟文档.docx》由会员分享,可在线阅读,更多相关《lcd时钟文档.docx(21页珍藏版)》请在冰豆网上搜索。
lcd时钟文档
1602液晶实现时间调整和显示功能
1、运行环境:
stc89c52、通用1602液晶
2、功能:
时分秒年月日星期显示和调整
3、原理图
4、设计思路:
摁下s1后实现调时功能,s2加一,s3减1;若s1没按下,s2、s3摁下无效。
S1摁下,如不调时,s1摁下8次后,时钟正常走动。
5、程序
//160216字符2行
//显示设置0x38设置1602显示,5X7点阵,8位数据接口
//显示开/关以及光标设置
//00001DCBD=1开显示,D=0关显示
//C=1显示光标,C=0不显示光标
//B=1光标闪烁B=0光标不闪烁
//显示开且光标闪烁指令0x0f;显示开不显示光标指令0x0c;
//显示开光标显示但光标不闪烁指令0x0e;
//000001NSN=1当读或写一个字符后地址指针加一,且光标加一
//N=0当读或写一个字符后地址指针减一,且光标减一
//S=1当写一个字符,整屏显示左移(N=1)或右移(N=0),以得到光标不移动而屏幕移动的效果
//S=0当写一个字符后,整屏显示不移动
//向右写字符且屏幕不移动指令0x06;
//向左写字符且屏幕不移动指令0x04;
//数据指针设置80H+地址码(0-27H,第一行),(40H-67H,第二行)
//01H显示清屏:
1、数据指针清零
//2、所有显示清零
//02H显示回车:
1、数据指针清零
//光标或显示移动0001(S/C)(R/L)**
//00光标向左移动,AC自动减1指令0x10
//01光标向右移动,AC自动加1指令0x14
//10光标和显示一起向左移动指令0x18
//
/**************************************************************************************
液晶初始显示2011-01-01MON/23:
59:
49
液晶不中断计时99年
液晶需外接电源,最好加电池,具体电路自行设计
液晶断电后,时间回到初始值,若正常显示需重新调整时间
s1是功能键,摁下调时;s2是加键,s3是减键,摁下实现加减操作
此程序只有一个功能,既是时间调整和显示,如需加定时、报时、计数、闹钟等功能自行随意更改!
*****************************************************************************************/
#include
#include
typedefunsignedcharuchar;
typedefunsignedintuint;
sbitlcde=P2^7;
sbitrs=P2^6;//数据/命令选择端(H/L)
sbitrw=P2^5;//读写选择端(H/L)
sbits1=P2^4;
sbits2=P2^3;
sbits3=P2^2;
ucharcodetab1[]={"2011-01-01MON"};
ucharcodetab2[]={"23:
59:
49"};
ucharcodetab3[7][3]={{'M','O','N'},{'T','U','E'},{'W','E','D'},{'T','H','U'},{'F','R','I'},{'S','A','T'},{'S','U','N'}};
ucharcodetab4[]={31,28,31,30,31,30,31,31,30,31,30,31};
ucharnum,cunt;
charsec,min,hou;
charyea,mon,day,wee;
chari;
ucharj;
uchars1num;
voiddelay(ucharz);
bitlcd_bz();
voidwrite_cmd(ucharcmd);
voidwrite_dat(uchardat);
voiddsprfhline2(ucharadd,uchardat);
voiddsprfhline1(ucharadd,uchardat);
voidkeyscan();
voidtrfh();
/************************
函数初始化
************************/
voidinit()
{
write_cmd(0x38);//液晶显示方式设置
delay(15);
write_cmd(0x0c);//开显示,不显示光标
delay(15);
write_cmd(0x06);//写设置
delay(15);
write_cmd(0x01);//清屏
delay(15);
write_cmd(0x80);//设置数据指针00
delay(15);
for(num=0;num{
write_dat(tab1[num]);
}
write_cmd(0x80+0x40);
for(num=0;num{
write_dat(tab2[num]);
}
TMOD=0x01;//设置定时器T0,16位计数方式
TH0=(65536-50000)/256;//T0装初值,计时50ms后溢出
TL0=(65536-50000)%256;
EA=1;//开总中断
ET0=1;//开定时器T0中断
TR0=1;//启动T0
}
/*************************************
主函数
变量初始化
按键检测
实时显示
**************************************/
voidmain()
{
yea=11;//年月日星期时分秒初始化
mon=1;
day=1;
wee=0;
i=0;
j=1;
sec=49;
min=59;
hou=23;
s1num=0;
init();
delay(255);
while
(1)
{
keyscan();//键盘实时检测
trfh();//显示实时更新
}
}
/**********************************
按键扫描
s1,摁下实现光标移位操作
s2,摁下一次实现加1操作
s3,按下一次实现减1操作
只有当s1摁下时,s2,s3摁下才有效
**********************************/
voidkeyscan()
{
if(s1==0)//判断s1按键是否按下
{
delay(10);//延时去抖动
if(s1==0)//再次检测s1按键是否按下
{
while(!
s1);//s1按键松手检测
s1num++;//记录s1摁下次数
switch(s1num)//执行移位操作
{
case1:
//s1第一次按下
//此处用郭天祥老师的话说,一个傻子都能看出来是在进行时间调整
TR0=0;//定时器T0停止计数
write_cmd(0x80+0x40+11);//光标在秒处停留
write_cmd(0x0e);//光标显示但不闪烁
break;//循环结束
case2:
write_cmd(0x80+0x40+8);break;//s1第二次按下,光标在分钟处停留
case3:
write_cmd(0x80+0x40+5);break;//s1第三次按下,光标在小时处停留
case4:
write_cmd(0x80+15);break;//s1第四次按下,光标在星期处摁下
case5:
write_cmd(0x80+11);break;//s1第五次按下,光标在日期处停留
case6:
write_cmd(0x80+8);break;//s1第六次按下,光标在月份处停留
case7:
write_cmd(0x80+5);break;//s1第七次摁下,光标在年份处停留
case8:
write_cmd(0x80+0x40+11);//s1第八次按下,光标回到秒钟位置
s1num=0;//s1num计数清零
TR0=1;//定时器T0启动计数
write_cmd(0x0c);//光标不闪烁
break;
default:
break;//其他的路过
}
}
}
if(s1num!
=0)//如果s1摁下
{
if(s2==0)//判断s2是否按下
{
delay(10);//延时去抖动
if(s2==0)//再次判断s2是否按下
{
while(!
s2);//s2按键松手检测
switch(s1num)//执行光标所在处的加操作
{
case1:
//秒加1
sec++;
if(sec==60)//秒加到60后清零
sec=0;
dsprfhline2(10,sec);//秒显示更新
write_cmd(0x80+0x40+11);
break;
case2:
min++;//分加1
if(min==60)//分加到60后清零
min=0;
dsprfhline2(7,min);//分显示更新
write_cmd(0x80+0x40+8);
break;
case3:
hou++;//时加1
if(hou==24)//时加到24后清零
hou=0;
dsprfhline2(4,hou);//时显示更新
write_cmd(0x80+0x40+5);
break;
case4:
wee++;//星期加1
if(wee==7)//星期加到7后清零
wee=0;
write_cmd(0x80+13);//星期显示更新
for(num=0;num<3;num++)
{
write_dat(tab3[wee][num]);
}
write_cmd(0x80+15);
break;
case5:
day++;//天加1
if(day>tab4[i])//天加到对应月份的天数后清零
{
day=1;
}
dsprfhline1(10,day);//天显示更新
write_cmd(0x80+11);
break;
case6:
mon++;//月份加1
i++;
if(i==12)//月份加到12后清零
i=0;
if(mon==13)//月份计数加到13后清零
mon=1;
dsprfhline1(7,mon);//月份显示更新
write_cmd(0x80+8);
break;
case7:
yea++;//年份加1
if(yea==99)//年份加到99后清零
yea=0;
dsprfhline1(4,yea);
write_cmd(0x80+5);//年份更新
break;
default:
break;
}
}
}
if(s3==0)//判断s3是否按下
{
delay(10);
{
if(s3==0)
{
while(!
s3);
switch(s1num)//执行光标位置的减操作
{
case1:
sec--;
if(sec==-1)
sec=59;
dsprfhline2(10,sec);
write_cmd(0x80+0x40+11);
break;
case2:
min--;
if(min==-1)
min=59;
dsprfhline2(7,min);
write_cmd(0x80+0x40+8);
break;
case3:
hou--;
if(hou==-1)
hou=23;
dsprfhline2(4,hou);
write_cmd(0x80+0x40+5);
break;
case4:
wee--;
if(wee==-1)
wee=6;
write_cmd(0x80+13);
for(num=0;num<3;num++)
{
write_dat(tab3[wee][num]);
}
write_cmd(0x80+15);
break;
case5:
day--;
if(day==0)
{
day=tab4[i];
}
dsprfhline1(10,day);
write_cmd(0x80+11);
break;
case6:
mon--;
i--;
if(i==-1)
i=11;
if(mon==0)
mon=12;
dsprfhline1(7,mon);
write_cmd(0x80+8);
break;
case7:
yea--;
if(yea==-1)
yea=99;
dsprfhline1(4,yea);
write_cmd(0x80+5);
break;
default:
break;
}
}
}
}
}
}
/*************************************************
中断服务函数
**************************************************/
voidtimer0()interrupt1
{
TH0=(65536-50000)/256;//T0重装初值
TL0=(65536-50000)%256;
cunt++;//中断标志加1
}
/*********************************************
时间刷新
晶振频率是12MHz
中断20次后秒加1
一分等于60秒
一小时等于60分
一天等于24小时
一周等于7天
一月等于28/30/31天
一年等于12个月/365天
**********************************************/
voidtrfh()
{
if(cunt==20)//判断是否计时1m
{
cunt=0;//计时1m后中断标志清零
sec++;//秒加1
if(sec==60)//判断秒是否到了60
{
sec=0;//秒清零
min++;//分加1
if(min==60)//判断分是否到了60
{
min=0;//分清零
hou++;//时加1
if(hou==24)//判断时是否到了24
{
hou=0;//时清零
day++;//天加1
if(day>tab4[i])//判断天是否到了一个月
{
day=1;//天等于1
i++;//月标志加1
if(i==12)//判断月标志是否到了12
{
i=0;//月标志清零
}
}
dsprfhline1(10,day);//天显示刷新
wee++;//星期加1
if(wee==7)//判断是否到了一周
{
wee=0;//星期清零
}
write_cmd(0x80+13);//星期显示刷新
for(num=0;num<3;num++)
{
write_dat(tab3[wee][num]);
}
j++;//天标志加1
if(j==365)//判断是否到了365天
{
j=0;//天标志清零
yea++;//年加1
dsprfhline1(4,yea);//刷新年显示
}
}
dsprfhline2(4,hou);//刷新时显示
}
dsprfhline2(7,min);//刷新分显示
}
dsprfhline2(10,sec);//刷新秒显示
}
}
/******************************************************
1602液晶第二行显示刷新函数
add地址
dat数据
*******************************************************/
voiddsprfhline2(ucharadd,uchardat)
{
ucharshi,ge;//定义局部变量shi,ge
shi=dat/10;//dat的十位赋给shi
ge=dat%10;//dat的个位赋给ge
write_cmd(0x80+0x40+add);//设定数据指针地址
write_dat(0x30+shi);//更新dat
write_dat(0x30+ge);
}
/************************************************
1602液晶第一行显示刷新函数
*************************************************/
voiddsprfhline1(ucharadd,uchardat)
{
ucharshi,ge;
shi=dat/10;
ge=dat%10;
write_cmd(0x80+add);
write_dat(0x30+shi);
write_dat(0x30+ge);
}
/*********************