#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit lcden=P3^4; //液晶使能端
sbit rs=P3^5; //液晶数据命令选择端
sbit led=P2^5; //控制LED的锁存器
sbit dula=P2^6; //控制LCD的段锁存器
sbit wela=P2^7; //控制LCD的位锁存器
sbit dsirq=P3^2; //DS12887的中断请求端
sbit dsds=P1^7; //DS12887的读允许输入端
sbit dsrw=P1^6; //DS12887的写允许输入端
sbit dsas=P1^5; //DS12887的地址选通端
sbit dscs=P1^4; //DS12887的芯片片选端
sbit a=P3^0; //设置键盘用的
sbit b=P3^1; //设置键盘用的
sbit c=P3^6; //设置键盘用的
sbit d=P3^7; //设置键盘用的
sbit e=P3^3; //设置键盘用的
uchar code table1[]=" 2000-00-00 ";
uchar code table2[]=" 00:00:00 ";
uchar flag1,flag2,temp,temp1;
/*
falg1标志位是用来判断是否执行从DS12C887中读取数据并送去液晶显示;
flag2标志位是用来判断LCD上显示的年数是否是闰年;
temp与temp1都时当月的天数值,用来判断DS12C887中的天数值是否大
于当月应有的天数,如大于则将天数值置1,如有需要请重新设置天数值。
*/
char miao,fen,nian,yue,ri,xingqi;
int shi; //小时的数值大于128,所以不能选择char型数据
/*------------
延时子程序
*/
void delayms(uchar a)
{
uchar x,y;
for(x=a;x>0;x--)
for(y=110;y>0;y--);
}
/*----------------
往液晶中写指令
----------------*/
void write_com(uchar com)
{
rs=0; //选择写命令模式
lcden=0; //将lcden置为零
P0=com; //将要写的命令字送到数据总线上
delayms(5); //稍做延时以待数据稳定
lcden=1; //使能端给一个高脉冲
delayms(5); //稍做延时
lcden=0; //将使能端置0以完成高脉冲
}
/*----------------
往液晶中写数据
----------------*/
void write_date(uchar date)
{
rs=1; //选择写数据模式
lcden=0; //将lcden置为零
P0=date; //将要写的数据送到数据总线上
delayms(5); //稍做延时以待数据稳定
lcden=1; //使能端给一个高脉冲
delayms(5); //稍做延时
lcden=0; //将使能端置0以完成高脉冲
}
/*--------------------
向DS12C887内写数据
--------------------*/
void write_ds(uchar add,uchar date)
{
dscs=0;
dsas=1;
dsds=1;
dsrw=1;
P0=add; //先写地址
dsas=0;
dsrw=0;
P0=date; //再写数据
dsrw=1;
dsas=1;
dscs=1;
}
/*--------------------
从DS12C887中读数据
--------------------*/
uchar read_ds(uchar add)
{
uchar temp;
dscs=0;
dsas=1;
dsds=1;
dsrw=1;
P0=add; //先写地址
dsas=0;
dsds=0;
P0=0xff; //读数据之前先将P0口置一
temp=P0; //再读数据
dsds=1;
dsas=1;
dscs=1;
return temp;
}
/*----------------------------------------------------------------------
24小时制在液晶的指定位置写入时分秒,12小时制在液晶的指定位置写入分秒
----------------------------------------------------------------------*/
void write_sfm(uchar add,uchar date)
{
uchar shi,ge;
shi=date/10; //分解一个2位数的十位和个位
ge=date%10;
write_com(0x80+0x40+add); //设置显示位置
write_date(shi+0x30); //送去液晶显示十位
write_date(ge+0x30); //送去液晶显示个位
}
/*----------------------------
在液晶的指定位置写入年月日
----------------------------*/
void write_nyr(uchar add,uchar date)
{
uchar shi,ge;
shi=date/10; //分解一个2位数的十位和个位
ge=date%10;
write_com(0x80+add); //设置显示位置
write_date(shi+0x30); //送去液晶显示十位
write_date(ge+0x30); //送去液晶显示个位
}
/*----------------------------
在液晶的指定位置写入星期
----------------------------*/
void write_xq(uchar date)
{
uchar i;
i=date;
write_com(0x80+12);
switch(i) //switch-case语句判断i的值及执行相应的操作
{
case 1: //当i等于1时,送去液晶显示MON(星期一)
write_date('M');
write_date('O');
write_date('N');
break;
case 2: //当i等于2时,送去液晶显示TUE(星期二)
write_date('T');
write_date('U');
write_date('E');
break;
case 3: //当i等于3时,送去液晶显示WED(星期三)
write_date('W');
write_date('E');
write_date('D');
break;
case 4: //当i等于4时,送去液晶显示THU(星期四)
write_date('T');
write_date('H');
write_date('U');
break;
case 5: //当i等于5时,送去液晶显示FRI(星期五)
write_date('F');
write_date('R');
write_date('I');
break;
case 6: //当i等于6时,送去液晶显示SAT(星期六)
write_date('S');
write_date('A');
write_date('T');
break;
case 7: //当i等于7时,送去液晶显示SUN(星期日)
write_date('S');
write_date('U');
write_date('N');
break;
}
}
/*----------------
判断天数的函数
----------------*/
char day_num(char nian,char yue)
{
char num;
if(((nian%4==0)&&(nian%100!=0))||((nian%100==0)&&(nian%400==0))) //闰年判断
flag2=1;
else
flag2=0;
if(flag2==1) //是闰年时,将第二月的天数设为29
{
switch(yue)
{
case 1:
num=31; //1月的天数
break;
case 2:
num=29; //2月的天数
break;
case 3:
num=31; //3月的天数
break;
case 4:
num=30; //4月的天数
break;
case 5:
num=31; //5月的天数
break;
case 6:
num=30; //6月的天数
break;
case 7:
num=31; //7月的天数
break;
case 8:
num=31; //8月的天数
break;
case 9:
num=30; //9月的天数
break;
case 10:
num=31; //10月的天数
break;
case 11:
num=30; //11月的天数
break;
case 12:
num=31; //12月的天数
break;
}
}
if(flag2==0) //不是闰年时,将第二月的天数设为28
{
switch(yue)
{
case 1:
num=31; //1月的天数
break;
case 2:
num=28; //2月的天数
break;
case 3:
num=31; //3月的天数
break;
case 4:
num=30; //4月的天数
break;
case 5:
num=31; //5月的天数
break;
case 6:
num=30; //6月的天数
break;
case 7:
num=31; //7月的天数
break;
case 8:
num=31; //8月的天数
break;
case 9:
num=30; //9月的天数
break;
case 10:
num=31; //10月的天数
break;
case 11:
num=30; //11月的天数
break;
case 12:
num=31; //12月的天数
break;
}
}
return num; //函数的返回值时当月的天数
}
/*--------------
键盘扫描程序
--------------*/
void keyscan()
{
uchar num;
a=0; //设置矩阵键盘S1低电平
b=1; //设置矩阵键盘S2高电平
if(c==0) //判断S3有没有被按下
{
delayms(5); //去抖延时
if(c==0) //判断S3有没有被按下
{
while(!c); //判断按键S3有没有释放
num++; //按下键的次数
flag1=1; //标志位flag1置一
if(num==1) //当num等于1时,光标在秒钟处闪烁
{
write_com(0x80+0x40+8);
write_com(0x0f);
}
if(num==2) //当num等于2时,光标在分钟处闪烁
{
write_com(0x80+0x40+5);
write_com(0x0f);
}
if(num==3) //当num等于3时,光标在时钟处闪烁
{
write_com(0x80+0x40+2);
write_com(0x0f);
}
if(num==4) //当num等于4时,光标在年处闪烁
{
write_com(0x80+4);
write_com(0x0f);
}
if(num==5) //当num等于5时,光标在月处闪烁
{
write_com(0x80+7);
write_com(0x0f);
}
if(num==6) //当num等于6时,光标在日处闪烁
{
write_com(0x80+10);
write_com(0x0f);
}
if(num==7) //当num等于7时,光标在星期处闪烁
{
write_com(0x80+14);
write_com(0x0f);
}
if(num==8)
{
num=0; //num清0
write_ds(0x00,miao); //将秒写入DS12C887
write_ds(0x02,fen); //将分写入DS12C887
write_ds(0x04,shi); //将时写入DS12C887
write_ds(0x06,xingqi); //将星期写入DS12C887
write_ds(0x07,ri); //将日写入DS12C887
write_ds(0x08,yue); //将月写入DS12C887
write_ds(0x09,nian); //将年写入DS12C887
flag1=0; //标志位flag1清0
}
}
}
if(num!=0) //当功能键S3按下后,数值增大键S4才有用
{
a=0; //设置矩阵键盘第一排位低电平
b=1; //设置矩阵键盘第二排位高电平
if(d==0) //判断S4有没有被按下
{
delayms(5); //去抖延时
if(d==0) //判断S4有没有被按下
{
while(!d); //判断按键S4有没有释放
if(num==1)
{
miao++; //当num=1时,秒值加一
if(miao>59) //当秒值大于59时,将秒值置0
miao=0;
write_sfm(7,miao); //将秒值写入液晶显示
write_com(0x80+0x40+8); //光标在秒值的个位闪烁
write_com(0x0f);
}
if(num==2)
{
fen++; //当num=2时,分值加一??
if(fen>59) //当分值大于59时,将分值置0
fen=0;
write_sfm(4,fen); //将分值写入液晶显示
write_com(0x80+0x40+5); //光标在分值的个位闪烁
write_com(0x0f);
}
if(num==3)
{
shi++; //当num=3时,时钟加一?
if(shi>23) //当时钟大于23时,将时钟置0
shi=0;
write_sfm(1,shi); //将时钟写入液晶显示
write_com(0x80+0x40+2); //光标在时钟的个位闪烁
write_com(0x0f);
}
if(num==4)
{
nian++; //当num=4时,年加一
if(nian>99) //当年大于99时,将年置0
nian=0;
write_nyr(3,nian); //将年写入液晶显示
write_com(0x80+4); //光标在年的个位闪烁
write_com(0x0f);
}
if(num==5)
{
yue++; //当num=5时,月加一
if(yue>12) //当月大于12时,将月置1
yue=1;
write_nyr(6,yue); //将月写入液晶显示
write_com(0x80+7); //光标在月的个位闪烁
write_com(0x0f);
}
if(num==6)
{
ri++; //当num=6时,日加一
temp=day_num(nian,yue);
if(ri>temp) //当日大于当月的天数时,将日置1
ri=1;
write_nyr(9,ri); //将日写入液晶显示
write_com(0x80+10); //光标在月的个位闪烁
write_com(0x0f);
}
if(num==7)
{
xingqi++; //当num=7时,星期加一
if(xingqi>7) //当星期大于7时,将星期置1
xingqi=1;
write_xq(xingqi); //将星期写入液晶显示
write_com(0x80+14); //光标在星期的个位闪烁
write_com(0x0f);
}
}
}
}
if(num!=0) //当功能键S3按下后,数值减小键S5才有用
{
a=1; //设置矩阵键盘第一排位高电平
b=0; //设置矩阵键盘第二排位低电平
if(e==0) //判断S5有没有被按下
{
delayms(5); //去抖延时
if(e==0) //判断S5有没有被按下
{
while(!e); //判断按键S5有没有释放
if(num==1)
{
miao--; //当num=1时,秒值减一
if(miao<0) //当秒值小于0时,将秒值置59
miao=59;
write_sfm(7,miao); //将秒值写入液晶显示
write_com(0x80+0x40+8); //光标在秒值的个位闪烁
write_com(0x0f);
}
if(num==2)
{
fen--; //当num=2时,分值减一
if(fen<0) //当分值小于0时,将分值置59
fen=59;
write_sfm(4,fen); //将分值写入液晶显示
write_com(0x80+0x40+5); //光标在分值的个位闪烁
write_com(0x0f);
}
if(num==3)
{
shi--; //当num=3时,时钟减一
if(shi<0) //当时钟小于0时,将时钟置23
shi=23;
write_sfm(1,shi); //将时钟写入液晶显示
write_com(0x80+0x40+2); //光标在时钟的个位闪烁
write_com(0x0f);
}
if(num==4)
{
nian--; //当num=4时,年减一
if(nian<0) //当年小于0时,将年置99
nian=99;
write_nyr(3,nian); //将年写入液晶显示
write_com(0x80+4); //光标在年的个位闪烁
write_com(0x0f);
}
if(num==5)
{
yue--; //当num=5时,月减一
if(yue<1) //当月小于1时,将月置12
yue=12;
write_nyr(6,yue); //将月写入液晶显示
write_com(0x80+7); //光标在月的个位闪烁
write_com(0x0f);
}
if(num==6)
{
ri--; //当num=6时,日减一
temp=day_num(nian,yue);
if(ri>temp)
ri=temp;
if(ri<1) //当日小于1时,将日置为当月的天数
ri=temp;
write_nyr(9,ri); //将日写入液晶显示
write_com(0x80+10); //光标在月的个位闪烁
write_com(0x0f);
}
if(num==7)
{
xingqi--; //当num=7时,星期加一
if(xingqi<1) //当星期小于1时,将星期置7
xingqi=7;
write_xq(xingqi); //将星期写入液晶显示
write_com(0x80+14); //光标在星期的个位闪烁
write_com(0x0f);
}
}
}
}
}
/*--------------
? 初始化时钟函数
--------------*/
void set_time()
{
write_ds(0,0); //初始化时钟秒钟的数值为0
write_ds(2,0); //初始化时钟分钟的数值为0
write_ds(4,1); //初始化时钟小时的数值为1
write_ds(6,1); //初始化时钟星期的数值为1
write_ds(7,1); //初始化时钟日的数值为1
write_ds(8,1); //初始化时钟月的数值为1
write_ds(9,0); //初始化时钟年的数值为0
}
/*------------
? 初始化程序
------------*/
void init()
{
uchar i;
dula=0; //关段锁存器(不让数码管显示)
wela=0; //关位锁存器
lcden=0;
write_com(0x38); //设置16*2显示,5*7点阵,8位数据接口(LCD初始化设置)
write_com(0x0c); //设置开显示,不显示光标(LCD初始化设置)
write_com(0x06); //写一个字符后地址指针自动加一(LCD初始化设置)
write_com(0x01); //显示清零,数据指针清零(LCD初始化设置)
write_com(0x80); //将数据指针定位到第一行第一字处
for(i=0;i<16;i++)
{
write_date(table1[i]); //将字符串1写入液晶
}
write_com(0x80+0x40); //将数据指针定位到第2行第1字处
for(i=0;i<16;i++)
{
write_date(table2[i]); //将字符串2写入液晶
}
set_time(); //初始化时钟
}
void main()
{
init(); //调用初始化子程序
while(1)
{
keyscan();
if(flag1==0) //当标志位flag1等于0时,才从DS12C887中读取数据并送去液晶显示
{
miao=read_ds(0); //从DS12C887中读取秒的值
write_sfm(7,miao); //将秒值送去液晶显示
fen=read_ds(0x02); //从DS12C887中读取分的值
write_sfm(4,fen); //将分值送去液晶显示
shi=read_ds(0x04); //从DS12C887中读取小时的值
write_sfm(1,shi); //将小时送去液晶显示
nian=read_ds(0x09); //从DS12C887中读取年的值
write_nyr(3,nian); //将年值送去液晶显示
yue=read_ds(0x08); //从DS12C887中读取月份的值
write_nyr(6,yue); //将月份送去液晶显示
ri=read_ds(0x07); //从DS12C887中读取日的值
temp1=day_num(nian,yue); //读取当月的天数值
if(ri>temp1) //判断DS12C887中的天数值是否大于当月应有的天数,如大于则将天数值置1,如有需要请重新设置
ri=1;
write_nyr(9,ri); //将日值送去液晶显示
xingqi=read_ds(0x06); //从DS12C887中读取星期的值
write_xq(xingqi); //将星期送去液晶显示
}
}
} |
|