#include <reg52.h>
#include "i2c.H" //包含VI2C软件包
#include "lcd1602.h" //包含1602的驱动程序
#include "PCF8563.h"
#define KEY P1
uchar disp_buf[10]={0}; //显示缓存,日期和时间共用一个缓存
uchar code table_time[]={"Time:"};
uchar code table_date[]={"Date:"};
uchar change_timeORdate; //更改时间标志
uchar change; //更改标志
uchar place_change; //位置标志
// 秒 分 时 日 星期 月 年
uchar td[9]={0x00,0x12,0x50, 0x59, 0x23, 0x23, 0x03, 0x10,0x11}; //定义初始化字
uchar code month[7]={0x01,0x03,0x05,0x07,0x08,0x10,0x12}; //一年中大月的月份(BCD码表示)
void delay_ms(uint i) //延时函数
{
uint k,j; //延时参数
for(k=i; i>0; i--)
for(j=0;j<110;j++);
}
void dispose_time(uchar *sd) //处理时间子程序
{
sd[0]=sd[0]&0x7f; //秒屏蔽保留位
sd[1]=sd[1]&0x7f; //分屏蔽保留位
sd[2]=sd[2]&0x3f; //时屏蔽保留位
disp_buf[7] =(sd[0]%16)+0x30; //此处显示秒
disp_buf[6] =(sd[0]/16)+0x30;
disp_buf[5] = ':';
disp_buf[4] =(sd[1]%16)+0x30; // 此处显示分
disp_buf[3] =(sd[1]/16)+0x30;
disp_buf[2] = ':';
disp_buf[1] =(sd[2]%16)+0x30; //此处显示时
disp_buf[0] =(sd[2]/16)+0x30;
/*上面几句把BCD码转换为ASCII码*/
}
void dispose_date(uchar *sd) //处理日期子程序
{
sd[0]=sd[0]&0x3f; //日屏蔽保留位
sd[2]=sd[2]&0x1f; //月屏蔽保留位
disp_buf[9] =(sd[0]%16)+0x30; //此处显示日
disp_buf[8] =(sd[0]/16)+0x30;
disp_buf[7] ='-';
disp_buf[6] =(sd[2]%16)+0x30; //此处显示月
disp_buf[5] =(sd[2]/16)+0x30;
disp_buf[4] ='-';
disp_buf[3] =(sd[3]%16)+0x30; //此处显示年
disp_buf[2] =(sd[3]/16)+0x30;
disp_buf[1] =0+0x30;
disp_buf[0] =2+0x30; //添加年份的前两位20
/*上面几句把BCD码转换为ASCII码*/
}
uchar big_month(uchar mon) //判断大月
{
uchar i;
for(i=0;i<7;i++)
{
if(mon==month[i])
return 1; //返回1:大月
}
return 0; //返回0:小月
}
uchar leap_year(uchar dat) //判断闰年
{
uchar shi;
uchar ge;
uint year;
shi=dat/16; //取年份值
ge=dat%16;
year=2000+shi*10+ge;
if((year%400==0)||(year%4==0&&year%100!=0)) //是否是闰年
return 1; //返回1:闰年
else
return 0; //返回0:非闰年
}
void date_add() //年月日,时分秒的加逻辑
{
switch(place_change)
{
case 5: //年的第三位加1
{
td[8]+=0x10; //这是16进制的加法
if((td[8]/16)>9) //这是16进制的加法,判断年份的第三位是否超过9
td[8]=td[8]-0x10; //年份的第三位超过9则等于9
}break;
case 6: //年的末位位加1
{
td[8]++;
if((td[8]%16)>9) //判断年份的第二位是否超过9
td[8]=td[8]-1; //年份的第二位超过9则等于9
}break;
case 8: //月十位加1
{
td[7]+=0x10; //这是16进制的加法
if(td[7]>0x12) //判断月份的值是否超过12
td[7]=0x12;
}break;
case 9: //月个位加1
{
td[7]++;
if(td[7]>0x12)
td[7] = 0x12;
else if((td[7]%16)>9)
td[7] -= 1;
}break;
case 11: //日十位加1
{
td[5]+=0x10; //这是16进制的加法
}break;
case 12: //日个位加1
{
td[5]+=1;
if((td[5]%16)>9) //这是16进制的加法,判断年份的第三位是否超过9
td[5]=td[5]-1; //年份的第三位超过9则等于9
}break;
default :break;
}
//判断月份是否超过实际天数
if(td[7]==2)
{
if((leap_year(td[8])==0)&&(td[5]>0x28))
td[5]=0x28;
if((leap_year(td[8])==1)&&(td[5]>0x29))
td[5]=0x29;
}
else
{
if((big_month(td[7])==0)&&(td[5]>0x30))
td[5]=0x30;
else if((big_month(td[7])==1)&&(td[5]>0x31))
td[5]=0x31;
}
//显示更改值和位置
LCD1602_write_com(0x0c); //关闭光标
dispose_date(td+5); //处理日期子程序
LCD1602_write_string(0,6,disp_buf,10); //显示日期
LCD1602_write_com(0x0f); //开启光标闪烁
LCD1602_flicker(0,place_change+3); //光标显示更改位
}
void date_cut() //年月日设置时,减功能处理
{
switch(place_change)
{
case 5: //年第三位位减1
{
if((td[8]/16)>0)
td[8]-=16;
}break;
case 6: //年末位个位减1
{
if((td[8]%16)>0)
td[8]-=1;
}break;
case 8: //月十位减1
{
if((td[7]/16)>0)
td[7]-=0x10;
if(td[7]==0) //月的最小值是1
td[7]=0x01;
}break;
case 9: //月个位减1
{
if((td[7]>0x10)||(td[7]%16)>1)
td[7]-=1;
}break;
case 11: //日十位减1
{
if((td[5]/16)>0)
td[5]-=16;
if(td[5]==0) //日的最小值是1
td[5]=0x01;
}break; //日个位减1
case 12:
{
if(((td[5]/16)&&(td[5]%16))||(td[5]%16)>1)
td[5]-=1;
}break;
default :break;
}
//判断月份是否超过实际天数
if(td[7]==2)
{
if((leap_year(td[8])==0)&&(td[5]>0x28))
td[5]=0x28;
if((leap_year(td[8])==1)&&(td[5]>0x29))
td[5]=0x29;
}
else
{
if((big_month(td[7])==0)&&(td[5]>0x30))
td[5]=0x30;
else if((big_month(td[7])==1)&&(td[5]>0x31))
td[5]=0x31;
}
//显示更改值和位置
LCD1602_write_com(0x0c); //关闭光标
dispose_date(td+5); //处理日期子程序
LCD1602_write_string(0,6,disp_buf,10); //显示日期
LCD1602_write_com(0x0f); //开启光标闪烁
LCD1602_flicker(0,place_change+3); //显示光标位置
}
void time_add() //时分秒设置时,加功能的处理
{
switch(place_change)
{
case 5: //小时十位加1
{
td[4]+=0x10;
if(td[4]>0x23)
td[4]=0x23;
}break;
case 6: //小时个位加1
{
td[4]+=1;
if(td[4]>0x23)
td[4] = 0x23;
else if((td[4]%16)>9)
td[4]=td[4]-1;
}break;
case 8: //分十位加1
{
td[3]+=0x10;
if(td[3]>0x59)
td[3]=0x59;
}break; //分个位加1
case 9:
{
td[3]+=1;
if((td[3]%16)>9)
td[3]=td[3]-1;
}break;
case 11: //秒十位加1
{
td[2]+=0x10;
if(td[2]>0x59)
td[2]=0x59;
}break;
case 12: //秒个位加1
{
td[2]+=1;
if((td[2]%16)>9)
td[2]=td[2]-1;
}break;
default :break;
}
//显示更改值和位置
LCD1602_write_com(0x0c); //关闭光标
dispose_time(td+2); //处理时间子程序
LCD1602_write_string(1,6,disp_buf,8); //显示时间
LCD1602_write_com(0x0f); //开启光标闪烁
LCD1602_flicker(1,place_change+1); //显示光标位置
}
void time_cut() //时分秒设置时,减功能的处理
{
switch(place_change)
{
case 5: //小时十位减1
{
if((td[4]/16)>0)
td[4]-=16;
}break;
case 6: //小时个位减1
{
if(td[4]%16>0)
td[4]-=1;
}break;
case 8: //分十位减1
{
if(td[3]/16>0)
td[3]-=16;
}break;
case 9: //分个位减1
{
if(td[3]%16>0)
td[3]-=1;
}break;
case 11: //秒十位减1
{
if(td[2]/16>0)
td[2]-=16;
}break; //秒个位减1
case 12:
{
if(td[2]%16>0)
td[2]-=1;
}break;
default :break;
}
//显示更改值和位置
LCD1602_write_com(0x0c); //关闭光标
dispose_time(td+2); //处理时间子程序
LCD1602_write_string(1,6,disp_buf,8); //显示时间
LCD1602_write_com(0x0f); //开启光标闪烁
LCD1602_flicker(1,place_change+1);
}
uchar key_scan() //读取按键值,没按下按键则返回0
{
uchar key_val=0;
KEY=0xff;
if((KEY&0x7f)!=0x7f)
{
delay_ms(10);
if((KEY&0x7f)!=0x7f)
key_val=KEY&0x7f;
while((KEY&0x7f)!=0x7f)
KEY=0xff;
}
return key_val;
}
void key_function(uchar val) //按键处理功能
{
switch(val)
{
case 0x7e://加
{
if(change==0)
{
if(change_timeORdate)
time_add();
else
date_add();
}
}break;
case 0x7d://减
{
if(change==0)
{
if(change_timeORdate)
time_cut();
else
date_cut();
}
}break;
case 0x7b://显示位加
{
if(change==0)
{
place_change++; //更改位加1
if(place_change>=12)
place_change=12;
if(change_timeORdate)
{
dispose_time(td+2); //处理时间子程序
LCD1602_flicker(1,place_change+1);
}
else
{