源代码(C语言)
/*******************************仅用lcd与51单片机io口,定时器0来实现电子日历**************************/
#include<reg52.h>
#include<intrins.h>
#include<copy.h>
#define u16 unsigned int
#define u8 unsigned char
sbit LCD1602_E=P2^7;
sbit LCD1602_RW=P2^5;//写指令 输入:RS=L,RW=L,E=下降沿脉冲,DB0~DB7=指令码 输出:无
sbit LCD1602_RS=P2^6;//写数据 输入:RS=H,RW=L,E=下降沿脉冲,DB0~DB7=数据 输出:无
sbit k1=P3^1;//对应单片机上的4个独立按键
sbit k2=P3^0;
sbit k3=P3^2;
sbit k4=P3^3;
//k1功能键k2加键k3减键
u8 code table[]=" 2022-01-01 SUN";
u8 code table1[]=" 23:59:55";
u8 code table2[7][3]={"MON","TUE","WED","THU","FRI","SAT","SUN"};
u8 count,k1num;char shi,fen,miao,ri,yue,nian,shiji;//时分秒日月年世纪-1(世纪这个,估计也活不到那么久)
u8 xingqiji,i;//全局变量星期几,i
void Delay_ms(u16 z)//延时函数大致1ms
{
u16 x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void LcdWriteCom(uchar com) //写入命令
{
LCD1602_E = 0; //使能
LCD1602_RS = 0; //选择发送命令
LCD1602_RW = 0; //选择写入
P0 = com; //放入命令
Delay_ms(1); //等待数据稳定
LCD1602_E = 1; //写入时序
Delay_ms(5); //保持时间
LCD1602_E = 0;
}
void LcdWrite_data(u8 dat)//写数据
{
LCD1602_RS=1; //选择输入数据
P0=dat; //接在P0口
Delay_ms(5);
LCD1602_E = 1; //写入时序
Delay_ms(5);
LCD1602_E = 0;
}
void Init()
{
u8 i;nian=22;yue=1;ri=1;shi=23;fen=59;miao=55,shiji=20;//初始化要设置参数,也要改初始显示
LcdWriteCom(0x38);//显示模式 8位总线 显示2行 5*10
LcdWriteCom(0x0c);//开光标,光标闪烁 0000 1111
//开光标不闪烁0x0e 0000 1110 ;闪烁0x0f
LcdWriteCom(0x06);//0000 0110 读写一个字符后地址光标加一
LcdWriteCom(0x01);//清屏
//LcdWriteCom(0x80+0x10);//设置数据指针起点80H+
//例如如果是0x81则数据从第一行的第二个显示
for(i=0;i<16;i++)
{
LcdWrite_data(table[i]);
Delay_ms(5);
}
LcdWriteCom(0x80+0x40);//设置数据指针起点80H+
for(i=0;i<12;i++)
{
LcdWrite_data(table1[i]);
Delay_ms(5);
}
TMOD=0x01;//开定时器0
TH0=0x3c;
TL0=0xb0;
ET0=1;
EA=1;
TR0=1;
// //设置INT0
// IT0=1;//跳变沿出发方式(下降沿)
// EX0=1;//打开INT0的中断允许。
// EA=1;//打开总中断
//本来想用中断来写星期函数,还是算了,没必要
}
void write_sfm(u8 add,u8 dat)//一个地址位,一个数据位
{
u8 shi,ge;//十位个位,本来用了个千百位,老报错,也找不到原因,索性不用了
shi=dat/10;
ge=dat%10;
LcdWriteCom(0x80+0x40+add);//从地址位下一位写入,自动移位来写个位数据
LcdWrite_data(0x30+shi);
LcdWrite_data(0x30+ge);
}
void write_nyr(u8 add,u8 dat)
{
u8 shi,ge;
shi=dat/10;
ge=dat%10;
LcdWriteCom(0x80+add);
LcdWrite_data(0x30+shi);
LcdWrite_data(0x30+ge);
}
void keypros()
{
if(k1==0) //检测按键K1是否按下
{
Delay_ms(10); //消除抖动 一般大约10ms
if(k1==0) //再次判断功能键是否按下
{
while(!k1); //检测按键是否松开
k1num++;
if(k1num==1)
{
TR0=0; //关闭定时器
LcdWriteCom(0x80+0x40+11);//在秒钟处闪烁
LcdWriteCom(0x0f);//显示光标
}
if(k1num==2)
{
LcdWriteCom(0x80+0x40+8);//在分钟处
}
if(k1num==3)
{
LcdWriteCom(0x80+0x40+5); //在小时处
}
if(k1num==4)
{
LcdWriteCom(0x80+15); //星期
}
if(k1num==5)
{
LcdWriteCom(0x80+11); //日
}
if(k1num==6)
{
LcdWriteCom(0x80+8); //月
}
if(k1num==7)
{
LcdWriteCom(0x80+5); //年
}
if(k1num==8)
{
LcdWriteCom(0x80+3);//世纪-1
}
if(k1num==9)
{
k1num=0;
LcdWriteCom(0x0c);//按下光标不再闪烁
TR0=1;//打开定时器
}
}
}
if(k1num!=0)
{
if(k2==0) //检测按键K2是否按下
{
Delay_ms(10); //消除抖动 一般大约10ms
if(k2==0) //再次判断按键是否按下
{
while(!k2);
if(k1num==1)//如果值为1,则对秒操作
{
miao++;
if(miao==60)
miao=0;
write_sfm(10,miao);
LcdWriteCom(0x80+0x40+10);//写完让光标停在这个位置
}
if(k1num==2)//值为2,对分操作
{
fen++;
if(fen==60)
fen=0;
write_sfm(7,fen);
LcdWriteCom(0x80+0x40+7);
}
if(k1num==3)//值为3,对小时操作
{
shi++;
if(shi==24)
shi=0;
write_sfm(4,shi);
LcdWriteCom(0x80+0x40+4);
}
if(k1num==4)//值为4,对星期操作
{
xingqiji++;//一个礼拜7天,用取余的方式调用switch语句比if语句要少些很多,其实都是复制粘贴
if(xingqiji==8)
xingqiji=1;
switch(xingqiji%7)//二维数组来存放字符串,对应用for循环一个个输到对应地址
{
case(0):LcdWriteCom(0x80+13);for(i=0;i<3;i++)
{
LcdWrite_data( table2[6][i]);
}break;
case(1):LcdWriteCom(0x80+13);for(i=0;i<3;i++)
{
LcdWrite_data( table2[0][i]);
}break;
case(2):LcdWriteCom(0x80+13);for(i=0;i<3;i++)
{
LcdWrite_data( table2[1][i]);
}break;
case(3):LcdWriteCom(0x80+13);for(i=0;i<3;i++)
{
LcdWrite_data( table2[2][i]);
}break;
case(4):LcdWriteCom(0x80+13);for(i=0;i<3;i++)
{
LcdWrite_data( table2[3][i]);
}break;
case(5):LcdWriteCom(0x80+13);for(i=0;i<3;i++)
{
LcdWrite_data( table2[4][i]);
}break;
case(6):LcdWriteCom(0x80+13);for(i=0;i<3;i++)
{
LcdWrite_data( table2[5][i]);
}break;
}
LcdWriteCom(0x80+13);
}
if(k1num==5)//值为5,对天进行操作
{
ri++;
if(ri==32)
ri=1;
write_nyr(10,ri);
LcdWriteCom(0x80+10);
}
if(k1num==6)//值为6,对月进行操作
{
yue++;
if(yue==13)
yue=1;
write_nyr(7,yue);
LcdWriteCom(0x80+7);
}
if(k1num==7)//值为7,对年进行操作
{
nian++;
if(nian==100)
nian=0;
write_nyr(4,nian);
LcdWriteCom(0x80+4);
}
if(k1num==8)//值为8,对世纪-1进行操作
{
shiji++;
if(shiji==100)
shiji=0;
write_nyr(2,shiji);
LcdWriteCom(0x80+2);
}
}
}
if(k3==0) //检测按键K3是否按下
{
Delay_ms(10); //消除抖动 一般大约10ms
if(k3==0) //再次判断按键是否按下
{
while(!k3);
if(k1num==1)
{
miao--; //前面定义的这几个都是char型,方便一些,如果用unsigned char的话是255吧
if(miao==-1)
{
miao=59;
}
write_sfm(10,miao);
LcdWriteCom(0x80+0x40+10);
}
if(k1num==2)
{
fen--;
if(fen==-1)
{
fen=59;
}
write_sfm(7,fen);
LcdWriteCom(0x80+0x40+7);
}
if(k1num==3)
{
shi--;
if(shi==-1)
shi=23;
write_sfm(4,shi);
LcdWriteCom(0x80+0x40+4);
}//星期数很小,没有对其设置减功能,后续再添加别的功能
if(k1num==5)//值为4,对天进行操作
{
ri--;
if(ri==0)
ri=31;
write_nyr(10,ri);
LcdWriteCom(0x80+10);
}
if(k1num==6)//值为5,对月进行操作
{
yue--;
if(yue==0)
yue=12;
write_nyr(7,yue);
LcdWriteCom(0x80+7);
}
if(k1num==7)//值为6,对年进行操作
{
nian--;
if(nian==0)
nian=99;
write_nyr(4,nian);
LcdWriteCom(0x80+4);
}
if(k1num==8)//值为7,对世纪-1进行操作
{
shiji--;
if(shiji==0)
shiji=99;
write_nyr(2,shiji);
LcdWriteCom(0x80+2);
}
}
}
}
}
void nyr_pros()//写年月日
{
if(ri==32)//1,3,5,7,8,10,12一个月31天
{
if(yue==1||yue==3||yue==5||yue==7||yue==8||yue==10||yue==12)
{
ri=1;
yue++;
write_nyr(7,yue);
write_nyr(10,ri);
}
if(yue==13)
{
yue=1;
nian++;
write_nyr(4,nian);
write_nyr(7,yue);
write_nyr(10,ri);
if(nian==100)
{
nian=0;
shiji++;
write_nyr(4,nian);//这里一定对nian进行刷新,不然会出现100进位变成:0而不是00的情况
write_nyr(2,shiji);
}
}
}
if(ri==31)//4,6,9,11一个月30天
{
if(yue==4||yue==6||yue==9||yue==11)
{
ri=1;
yue++;
write_nyr(7,yue);
write_nyr(10,ri);
}
}
if((yue==2)&&(nian%4==0))
{
if(ri==30)//闰年2月29天
{
ri=1;
yue++;
write_nyr(7,yue);
write_nyr(10,ri);
}
}
else if(ri==29)//非闰年2月28天
{
ri=1;
yue++;
write_nyr(7,yue);
write_nyr(10,ri);
}
}
//void xingqi()//开始写的if,万物皆可if
//{
// u8 i,j;
//
// j=xingqiji%7;
// if(j==1)
// {
// LcdWriteCom(0x80+13);
// for(i=0;i<3;i++)
// {
// LcdWrite_data( table2[0][i]);
// }
// }
// if(j==2)
// {
// LcdWriteCom(0x80+13);
// for(i=0;i<3;i++)
// {
// LcdWrite_data( table2[1][i]);
// }
// }
// if(j==3)
// {
// LcdWriteCom(0x80+13);
// for(i=0;i<3;i++)
// {
// LcdWrite_data( table2[2][i]);
// }
// }
// if(j==4)
// {
// LcdWriteCom(0x80+13);
// for(i=0;i<3;i++)
// {
// LcdWrite_data( table2[3][i]);
// }
// }
// if(j==5)
// {
// LcdWriteCom(0x80+13);
// for(i=0;i<3;i++)
// {
// LcdWrite_data( table2[4][i]);
// }
// }
// if(j==6)
// {
// LcdWriteCom(0x80+13);
// for(i=0;i<3;i++)
// {
// LcdWrite_data( table2[5][i]);
// }
// }
// if(j==0)
// {
// LcdWriteCom(0x80+13);
// for(i=0;i<3;i++)
// {
// LcdWrite_data( table2[6][i]);
// }
// }
//
//}
void xingqi_pros()//因为不能放进按键里,暂时不放了,因为重复定义,我还没找到问题所在
{
xingqiji++;
if(xingqiji==8)
xingqiji=1;
switch(xingqiji%7)
{
case(0):LcdWriteCom(0x80+13);for(i=0;i<3;i++)
{
LcdWrite_data( table2[6][i]);
}break;
case(1):LcdWriteCom(0x80+13);for(i=0;i<3;i++)
{
LcdWrite_data( table2[0][i]);
}break;
case(2):LcdWriteCom(0x80+13);for(i=0;i<3;i++)
{
LcdWrite_data( table2[1][i]);
}break;
case(3):LcdWriteCom(0x80+13);for(i=0;i<3;i++)
{
LcdWrite_data( table2[2][i]);
}break;
case(4):LcdWriteCom(0x80+13);for(i=0;i<3;i++)
{
LcdWrite_data( table2[3][i]);
}break;
case(5):LcdWriteCom(0x80+13);for(i=0;i<3;i++)
{
LcdWrite_data( table2[4][i]);
}break;
case(6):LcdWriteCom(0x80+13);for(i=0;i<3;i++)
{
LcdWrite_data( table2[5][i]);
}break;
}
}
void main()
{
Init();
while(1)
{
keypros();
}
}
void timer0()interrupt 1
{
TH0=0x3c;
TL0=0xb0;
count++;
if(count==20)
{
count=0;
miao++;
if(miao==60)
{
miao=0;
fen++;
if(fen==60)
{
fen=0;
shi++;
if(shi==24)
{
shi=0;
ri++;
xingqi_pros();
nyr_pros();
write_nyr(10,ri);
}
write_sfm(4,shi);
}
write_sfm(7,fen);
}
write_sfm(10,miao);
}
}
//过程很艰辛,结果很有趣