标题:
1602 定时器 点扫描做万年历、时钟 走时精度已经可观
[打印本页]
作者:
MCUteacher
时间:
2016-12-15 21:46
标题:
1602 定时器 点扫描做万年历、时钟 走时精度已经可观
仅使用内部定时器,走时精度已经可观。
难度在于使用键盘调节万年历。
下载:
1602 定时器 点扫描做时钟.rar
(2.62 KB, 下载次数: 20)
2016-12-15 21:45 上传
点击文件名下载附件
下载积分: 黑币 -5
#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char
uchar shi,fen,miao,ri,yue,nian,rimax,keyn,xq,flag;
uint tt;
uchar code table[]="2011-11-11 FRI";
uchar code table1[]="23:59:51";
uchar code tablex[]="MON TUE WED THU FRI SAT SUN ";
sbit dula=P2^6;
sbit wela=P2^7;
sbit lcden=P3^4;
sbit rs=P3^5;
sbit key=P3^0;
sbit keyg=P3^1;
sbit keyd=P3^2; //原计划写调减,不想写了。
sbit gnd=P3^7;
void init();
void write_com(uchar com);
void write_date(uchar date);
void write_sfm(uchar wei,uchar date);
void write_nyr(uchar wei,uchar date);
void write_xq();
void delay(uchar z);
void yueday();
void shunbianday();
void keyscan();
void clockrun();
void main()
{
init();
while(1)
{
keyscan();
clockrun();
}
}
void init()
{
uchar a,b;
dula=0;
wela=0;
lcden=0;
shi=23;
fen=59;
miao=58;
nian=16;
yue=2;
ri=29;
keyn=0;
write_com(0x38);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
write_com(0x80+1);
for(a=0;a<14;a++)
{
write_date(table[a]);
}
write_com(0x80+0x40+4);
for(b=0;b<8;b++)
{
write_date(table1[b]);
}
write_nyr(2,nian);
write_nyr(5,yue);
write_nyr(8,ri);
write_sfm(0,shi);
write_sfm(3,fen);
write_sfm(6,miao);
write_xq();
yueday();
TMOD=0x02; //设定定时/计数器工作方式2,自动重装初值
TH0=0; //高八位+1计数器,工作方式1中,(65536-46080)/256=高八位,高八位总共可以装256,减76后可装180,即:当低八位为零时,高八位加一计数器+1次数180次时刚好50ms
TL0=0; //低八位+1计数器,工作方式2中,第八位用于+1计数完成计时,高八位用于保留初值给第八位重写初值
EA=1; //现在因不需占用机器周期重装初值,若还有误差,则只能是晶振的误差
ET0=1;
TR0=1;
}
void timer0() interrupt 1
{
tt++; //由于第八位加计数器只能计256,
}
void write_sfm(uchar wei,uchar date)
{
uchar ge,shi;
shi=date/10;
ge=date%10;
write_com(0x80+0x40+4+wei);
write_date(0x30+shi);
write_date(0x30+ge);
}
void write_nyr(uchar wei,uchar date)
{
uchar ge,shi;
shi=date/10;
ge=date%10;
write_com(0x80+1+wei);
write_date(0x30+shi);
write_date(0x30+ge);
}
void write_xq() //写星期数
{
uchar q;
write_com(0x80+12);
for(q=0;q<4;q++)
{
write_date(tablex[xq]);
xq++;
if(xq==28)
xq=0;
}
}
void yueday() //程序写长了,改子函数名有困难,以后注意。
{ //该子函数表示月+1后计算引用的天数
if(yue==1)
rimax=32;
if(yue==2)
{
if(nian%4==0)
rimax=30;
else
rimax=29;
}
if(yue==3)
rimax=32;
if(yue==4)
rimax=31;
if(yue==5)
rimax=32;
if(yue==6)
rimax=31;
if(yue==7)
rimax=32;
if(yue==8)
rimax=32;
if(yue==9)
rimax=31;
if(yue==10)
rimax=32;
if(yue==11)
rimax=31;
if(yue==12)
rimax=32;
}
void shunbianday() //该子函数表示月+0后计算引用的天数
{
if(yue==2) //实际调用1月份天数最大31
rimax=31;
if(yue==3) //实际调用2月份天数最大28/29
{
if(nian%4==0)
rimax=29;
else
rimax=28;
}
if(yue==4)
rimax=31; //实际调用3月份天数最大31
if(yue==5)
rimax=30; //实际调用4月份天数最大30
if(yue==6)
rimax=31; //实际调用5月份天数最大31
if(yue==7)
rimax=30; //实际调用6月份天数最大30
if(yue==8)
rimax=31; //实际调用7月份天数最大31
if(yue==9)
rimax=31; //实际调用8月份天数最大31
if(yue==10)
rimax=30; //实际调用9月份天数最大30
if(yue==11)
rimax=31; //实际调用10月份天数最大31
if(yue==12)
rimax=30; //实际调用11月份天数最大30
}
void delay(uchar z)
{
uchar i,j;
for(i=z;i>0;i--)
for(j=115;j>0;j--);
}
void write_com(uchar com)
{
rs=0;
P0=com;
delay(4);
lcden=1;
delay(4);
lcden=0;
}
void write_date(uchar date)
{
rs=1;
P0=date;
delay(4);
lcden=1;
delay(4);
lcden=0;
}
void keyscan()
{
uchar temp,p;
gnd=0;
if(key==0)
{
delay(5);
if(key==0)
{
TR0=0;
keyn++;
if(keyn==7)
keyn=0;
write_com(0x0f);
if(keyn==0)
{
TR0=1;
write_com(0x0c);
}
if(keyn==1)
write_com(0x80+0x40+11);
if(keyn==2)
write_com(0x80+0x40+8);
if(keyn==3)
write_com(0x80+0x40+5);
if(keyn==4)
write_com(0x80+10);
if(keyn==5)
write_com(0x80+7);
if(keyn==6)
write_com(0x80+4);
while(!key);
}
}
if(keyn==1)
{
if(keyg==0)
{
delay(5);
if(keyg==0)
{
miao++;
if(miao==60)
miao=0;
write_sfm(6,miao);
write_com(0x80+0x40+11);
while(!keyg);
}
}
}
if(keyn==2)
{
if(keyg==0)
{
delay(5);
if(keyg==0)
{
fen++;
if(fen==60)
fen=0;
write_sfm(3,fen);
write_com(0x80+0x40+8);
while(!keyg);
}
}
}
if(keyn==3)
{
if(keyg==0)
{
delay(5);
if(keyg==0)
{
shi++;
if(shi==24)
shi=0;
write_sfm(0,shi);
write_com(0x80+0x40+5);
while(!keyg);
}
}
}
if(keyn==4)
{
if(keyg==0)
{
delay(5);
if(keyg==0)
{
yueday();
ri++;
if(ri>=rimax)
{
ri=1;
temp=(rimax-2)%7;
for(p=6-temp;p>0;p--)
{
write_xq(); //因为跳出循环后,下面还会再重复一次,所以这里只循环5次
}
}
write_xq();
write_nyr(8,ri);
write_com(0x80+10);
while(!keyg);
}
}
}
if(keyn==5)
{
if(keyg==0)
{
delay(5);
if(keyg==0)
{
yue++;
if(yue==13)
{
yue=1; //情况二,跨月数调月(12变1)后,间隔天数
if(nian%4==0) //情况二分支1,闰年
{ //因为12月、1月均为月大,日编号不会变
for(p=(366-33)%7;p>0;p--)
write_xq();
}
else //情况二分支2,平年
{
for(p=(365-31)%7;p>0;p--)
write_xq();
}
}
write_nyr(5,yue);
//标记点
yueday(); //情况一,顺序调月后(1→12),间隔天数。本句判断本月有多少天供后续利用
if(ri>rimax-1) //情况一分支1。当当前显示的天数小于本月最大天数时,显示本月最大天数
{
write_nyr(8,rimax-1); //上个注释的执行部分,将示数改到最大值范围
temp=ri-rimax; //情况一分支1,判断当月数加一后,天数增加数量
ri=rimax-1; //上个注释的执行部分,不能光改示数,而不改实际运行值。
shunbianday(); //更换rimax值
for(p=(rimax+temp-1)%7;p>0;p--)
write_xq();
}
else //情况一分支2,判断当月数加一后,天数增加数量
{ //当初值大于29时,1月变2月,是顺变,同时显示值大于最大允许值
shunbianday();
for(p=rimax%7;p>0;p--)
write_xq();
}
write_com(0x80+7);
while(!keyg);
}
}
}
if(keyn==6)
{
if(keyg==0)
{
delay(5);
if(keyg==0)
{
if(nian%4==0&&yue==2&&ri==29) //分支3,当年+0为闰年2月29日时,年+1后2月只有28号。
{
ri=28; //改日的值
write_nyr(8,ri); //改日显示
for(p=7;p>0;p--) //改星期显示
write_xq(); //循环七次,相当于没改
flag=1; //分支4,当闰年2月29调过年数,调年再经过闰年未能识别闰年
}
nian++;
if(nian>99) //分支1,嘿嘿,百年虫
{
nian=0;
write_xq();
}
if(nian%4==0) //分支2.1,年+1为闰年
{
if(flag==1)
{
for(p=(365-28)%7;p>0;p--)
write_xq();
flag=2;
}
else
{
for(p=(366-35)%7;p>0;p--)
write_xq();
}
}
else //分支2.2,年+1为平年
{
if(flag==2)
{
for(p=2;p>0;p--)
write_xq();
flag=1;
}
else
{
for(p=(365-28)%7;p>0;p--)
write_xq();
}
}
write_nyr(2,nian);
write_com(0x80+4);
while(!keyg);
}
}
}
}
void clockrun()
{
if(tt==3600)
{
tt=0;
miao++;
if(miao>=60)
{
miao=0;
fen++;
if(fen>=60)
{
fen=0;
shi++;
if(shi>=24)
{
shi=0;
ri++;
write_xq();
yueday();
if(ri>=rimax)
{
ri=1;
yue++;
if(yue>=13)
{
yue=1;
nian++;
if(nian>=100)
nian=0;
write_nyr(2,nian);
}
write_nyr(5,yue);
}
write_nyr(8,ri);
}
write_sfm(0,shi);
}
write_sfm(3,fen);
}
write_sfm(6,miao);
}
}
复制代码
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1