#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define LCD_DB_PORT P0 //液晶数据端口DB0-DB7
#define LCD_START_ROW 0xC0 //启始行命令
#define LCD_PAGE 0xb8 //页命令
#define LCD_COL 0x04 //列命令
bit Reverse_Display=0; //是否反相显示(白底黑字/黑底白字)
char Adjust_Index=-1; //当前调节的时间对象:秒,分,时,日,月,年
uchar MonthsDays[]={31,0,31,30,31,30,31,31,30,31,30,31}; //一年当中的每个月的天数,二月份由年份决定
uchar DateTime[7]; //所取的日期时间
void Write_Byte_T0_DS1302(uchar X); //向1302写入一个字方节
uchar Read_Byte_FROM_DS1302(); //从1302中读取一个字节
uchar Read_Data_FROM_DS1302(uchar addr); //从1302指定位置读取数据
void Write_Data_T0_DS1302(uchar addr,uchar dat); //向1302指定位置写入数据
void SET_DS1302(); //设置时间
void GetTime(); //读取当前时间
void DateTime_Adjust(char X); //年,月,日和时,分++/--
uchar Is_Leapyear(uint year); //判断是否为闰年
extern void LCD_12864_Initialization();
extern void Display_char(uchar P1,uchar L1,uchar *M) reentrant;
extern void Dispaly_Word(uchar P2,uchar L2,uchar *M) reentrant;
extern void DateTime_Adjust(char X);
extern void SET_DS1302(); //设置时间
extern void GetTime(); //(extern GetTime)
void Initialization(); //初始化函数
extern bit Reverse_Display; //是否反相显示(白底黑字/黑的白字)
extern uchar code Digits[];
extern uchar code WEEK_WORDS[];
extern uchar code Digits[];
extern uchar code DATE_TIME_WORDS[];
extern char Adjust_Index; //当前调节的时间对象:秒,分,时,日,月,年(0,1,2,3,4,5,6)
extern uchar Monthsdays[]; //一年中每个月的天数,二月天数有年份来决定的
extern uchar DateTime[7]; //所读取的时间日期
uchar tcount=0; //定义
uchar H_Offset=10;
uchar V_page_Offset=0;
sbit RS=P2^0; //12864引脚定义
sbit RW=P2^1; //12864引脚定义
sbit E=P2^2; //12864引脚定义
sbit CS1=P2^3; //12864引脚定义
sbit CS2=P2^4; //12864引脚定义
sbit RST=P2^5; //12864引脚定义
sbit SDA=P1^0; //1302数据线
sbit CLK=P1^1; //1302时钟线
sbit RSTT=P1^2; //1302复位线
sbit k1=P3^4; //选择案件
sbit k2=P3^5; //加
sbit k3=P3^6; //减
sbit k4=P3^7; //确定
bit LCD_IS_BUSY()//检查LCD是否忙
{
LCD_DB_PORT=0xFF;
RW=1;
_nop_();
RS=0;
E=1;
_nop_();
E=0;
return (bit)(P0&0x80);
}
void Write_Byte_To_LCD(uchar comand)//向LCD写入一个字节(一般用于发送命令)
{
while(LCD_IS_BUSY());
LCD_DB_PORT=0xFF;
RW=0;
_nop_();
RS=0;
LCD_DB_PORT=comand;
E=1;
_nop_();
E=0;
}
void Write_Data_To_LCD(uchar dat)//向LCD写入数据
{
while(LCD_IS_BUSY());
LCD_DB_PORT=0xFF;
RW=0;
_nop_();
RS=1;
if(!Reverse_Display)//根据Reverse_Display决定是否反向显示
LCD_DB_PORT=dat;
else
LCD_DB_PORT=~dat;
E=1;
_nop_();
E=0;
}
void LCD12864_Initialization()//初始化LCD
{
CS1=1;
CS2=1;
Write_Byte_To_LCD(0x38);
Write_Byte_To_LCD(0x0F);
Write_Byte_To_LCD(0x01);
Write_Byte_To_LCD(0x06);
Write_Byte_To_LCD(LCD_START_ROW);
}
void LCD_Show(uchar P,uchar L,uchar W,uchar *r) reentrant
//通用显示函数 从第P页第L列显示W个字节数据,具体显示的数据在r所指的数组中
{
uchar i;
if(L<64)
{
CS1=1; //左半屏选中
CS2=0;
Write_Byte_To_LCD(LCD_PAGE+P); //页
Write_Byte_To_LCD(LCD_COL+L); //列
if(L+W<64)
{
for(i=0;i<W;i++)
Write_Data_To_LCD(r[i]);
}
else
{
for(i=0;i<64-L;i++)
Write_Data_To_LCD(r[i]);
CS1=0; //选中右半屏
CS2=1;
Write_Byte_To_LCD(LCD_PAGE+P);
Write_Byte_To_LCD(LCD_COL);
for(i=64-L;i<W;i++)
Write_Data_To_LCD(r[i]);
}
}
else
{
CS1=0;
CS2=1;
Write_Byte_To_LCD(LCD_PAGE+P);
Write_Byte_To_LCD(LCD_COL+L-64);
for(i=0;i<W;i++)
Write_Data_To_LCD(r[i]);
}
}
void Display_char(uchar P1,uchar L1,uchar *M) reentrant//显示一个8*16点阵字符
{
LCD_Show(P1,L1,8,M);
LCD_Show(P1+1,L1,8,M+8);
}
void Dispaly_Word(uchar P2,uchar L2,uchar *M) reentrant//显示一个16*16点阵字符(汉字上半部分与下半部分分别处在相邻两页中)
{
LCD_Show(P2,L2,16,M);
LCD_Show(P2+1,L2,16,M+16);
}
void Write_Byte_T0_DS1302(uchar X)//向DS1302写入一个字符
{
uchar i;
for(i=0;i<8;i++)
{
SDA=X&1;
CLK=1;
CLK=0;
X>>=1;
}
}//读字节函数,从DS1302读取一个字节
uchar Read_Byte_FROM_DS1302()
{
uchar i,byte,t;
for(i=0;i<8;i++)
{
byte>>=1;
t=SDA;
byte|=t<<7;
CLK=1;
CLK=0;
}
//BCD码转换
return byte/16*10+byte%16;
}
uchar Read_Data_FROM_DS1302(uchar addr)//从DS1302指定位置读取数据,读数据
{
uchar dat;
RST=0;
CLK=0;
RST=1;
Write_Byte_T0_DS1302(addr);//向S1302写入一个地址
dat=Read_Byte_FROM_DS1302();//在上面写入的地址中读取数据
CLK=1;
RST=0;
return dat;
}
void Write_Data_T0_DS1302(uchar addr,uchar dat)//向DS1302指定位置写入数据,写数据
{
CLK=0;
RST=1;
Write_Byte_T0_DS1302(addr);
Write_Byte_T0_DS1302(dat);
CLK=1;
RST=0;
}
void SET_DS1302()//设置时间
{
uchar i;
Write_Data_T0_DS1302(0x8E,0x00);//写控制字,取消写保护
//分,时,日,月,年依次写入
for(i=1;i<7;i++)
{
//分的起始地址是10000010(0x82),后面依次是时,日,年,月,周,年,写入的地址每次递增2
Write_Data_T0_DS1302(0x80+2*i,(DateTime[i]/10<<4)|(DateTime[i]%10));
}
Write_Data_T0_DS1302(0x8E,0x80);//写控制字,加写保护
}
void GetTime()//读取当前时间
{
uchar i;
for(i=0;i<7;i++)
{
DateTime[i]=Read_Data_FROM_DS1302(0x81+2*i);
}
}
uchar Is_Leapyear(uint year)//判断是否为闰年
{
return (year%4==0&&year%100!=0)||(year%400==0);
}
void Refresh_Week_Day()//求自2000.1.1开始的任何一天是星期几?
{
uint i,d,w=5;//已知1999年12.31是星期五
for(i=2000;i<2000+DateTime[6];i++)//判断是否为闰年
{
d=Is_Leapyear(i)?366:365;
w=(w+d)%7;
}
d=0;
for(i=1;i<DateTime[4];i++)
{
d+=MonthsDays[i];
}
d+=DateTime[3];
//保存星期,0-6表示星期日,星期一至星期六,为了与DS1302的星期格式匹配,返回值需要加1
DateTime[5]=(w+d)%7+1;
}
void DateTime_Adjust(char X)//年,月,日和时,分++/--
{
switch(Adjust_Index)
{
case 6://年调整,00-99
if(X==1&&DateTime[6]<99)
{
DateTime[6]++;
}
if(X==-1&&DateTime[6]>0)
{
DateTime[6]--;
}
MonthsDays[2]=Is_Leapyear(2000+DateTime[6]?29:28);//获取2月天数
if(DateTime[3]>MonthsDays[DateTime[4]])//如果年份变化后当前月份的天数大于上限则设为上限
{
DateTime[3]=MonthsDays[DateTime[4]];
}
Refresh_Week_Day();//刷新星期
break;
case 4://月调整01-12
if(X==1&&DateTime[4]<12)
{
DateTime[4]++;
}
if(X==-1&&DateTime[4]>1)
{
DateTime[4]--;
}
MonthsDays[2]=Is_Leapyear(2000+DateTime[6]?29:28);//获取2月天数
if(DateTime[3]>MonthsDays[DateTime[4]])//如果年份变化后当前月份的天数大于上限则设为上限
{
DateTime[3]=MonthsDays[DateTime[4]];
}
Refresh_Week_Day();//刷新星期
break;
case 3://日调整00-28或00-29或00-30或00-31
MonthsDays[2]=Is_Leapyear(2000+DateTime[6]?29:28);//调节之前首先根据当前年份得出该年中2月的天数
if(X==1&&DateTime[3]<MonthsDays[DateTime[4]])//根据当前月份决定调节日期的上限
{
DateTime[3]++;
}
if(X==-1&&DateTime[3]>0)
{
DateTime[3]--;
}
Refresh_Week_Day();//刷新星期
break;
case 2://时调整
if(X==1&&DateTime[2]<23)
{
DateTime[2]++;
}
if(X==-1&&DateTime[4]>0)
{
DateTime[2]--;
}
break;
case 1://分调整
if(X==1&&DateTime[1]<59)
{
DateTime[1]++;
}
if(X==-1&&DateTime[4]>0)
{
DateTime[1]--;
}
break;
case 0://秒调整
if(X==1&&DateTime[1]<59)
{
DateTime[0]++;
}
if(X==-1&&DateTime[4]>0)
{
DateTime[0]--;
}
break;
}
}
//年,月,日,星期,时,分,秒等汉字点阵(16*16)
uchar code DATE_TIME_WORDS[]={
//年
0x00,0x04,0x18,0xE3,0x22,0x22,0x22,0x22,0x3F,0x22,0x22,0x22,0x22,0x20,0x00,0x00,
0x20,0x20,0x20,0xE0,0x20,0x20,0x20,0x20,0xFF,0x20,0x20,0x20,0x20,0x20,0x20,0x00,
//月
0x00,0x00,0x00,0x7F,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x7F,0x00,0x00,0x00,
0x01,0x02,0x0C,0xF0,0x40,0x40,0x40,0x40,0x40,0x40,0x42,0x41,0xFE,0x00,0x00,0x00,
//日
0x00,0x00,0x00,0x7F,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x7F,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0xFF,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0xFF,0x00,0x00,0x00,0x00,
//星
0x00,0x00,0x00,0x7D,0x54,0x54,0x54,0x57,0x54,0x54,0x54,0x7C,0x00,0x00,0x00,0x00,
0x00,0x22,0x42,0x92,0x92,0x92,0x92,0xFE,0x92,0x92,0x92,0x92,0x82,0x02,0x00,0x00,
//期
0x00,0x20,0xFF,0x24,0x24,0x24,0xFF,0x20,0x00,0x7F,0x44,0x44,0x44,0x7F,0x00,0x00,
0x11,0x12,0xF4,0x90,0x90,0x98,0xF5,0x12,0x0C,0xF0,0x40,0x42,0x41,0xFE,0x00,0x00,
//时
0x00,0x3F,0x21,0x21,0x21,0x3F,0x00,0x08,0x08,0x08,0x08,0x08,0xFF,0x08,0x08,0x00,
0x00,0xFC,0x08,0x08,0x08,0xFC,0x00,0x00,0x80,0x60,0x02,0x01,0xFE,0x00,0x00,0x00,
//分
0x01,0x02,0x04,0x09,0x11,0x61,0x01,0x01,0x01,0xC1,0x31,0x08,0x04,0x02,0x01,0x00,
0x00,0x01,0x02,0x04,0x18,0xE0,0x00,0x02,0x01,0x02,0xFC,0x00,0x00,0x00,0x00,0x00,
//秒
0x24,0x24,0x25,0x7F,0xC4,0x44,0x00,0x03,0x1C,0x00,0xFF,0x00,0x10,0x08,0x06,0x00,
0x10,0x60,0x80,0xFF,0x80,0x60,0x81,0x01,0x02,0x02,0xE4,0x08,0x30,0xC0,0x00,0x00,
};
//一,二,三,四,五,六和天等汉字点阵16*16)
uchar code WEEK_WORDS[]={
/*-- 文字: 天 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x02,0x02,0x42,0x42,0x42,0x42,0x42,0x7F,0x42,0x42,0x42,0x42,0x42,0x02,0x02,0x00,
0x01,0x01,0x02,0x04,0x08,0x30,0xC0,0x00,0xC0,0x30,0x08,0x04,0x02,0x01,0x01,0x00,
/*-- 文字: 一 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
/*-- 文字: 二 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,
/*-- 文字: 三 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x00,0x20,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x20,0x00,0x00,
0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,
/*-- 文字: 四 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x00,0x3F,0x20,0x20,0x20,0x3F,0x20,0x20,0x20,0x3F,0x20,0x20,0x20,0x3F,0x00,0x00,
0x00,0xFE,0x14,0x24,0xC4,0x04,0x04,0x04,0x04,0x84,0x44,0x44,0x44,0xFE,0x00,0x00,
/*-- 文字: 五 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x00,0x40,0x42,0x42,0x42,0x43,0x7E,0x42,0x42,0x42,0x42,0x43,0x40,0x40,0x00,0x00,
0x02,0x02,0x02,0x02,0x1E,0xE2,0x02,0x02,0x02,0x02,0x02,0xFE,0x02,0x02,0x02,0x00,
/*-- 文字: 六 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x04,0x04,0x04,0x04,0x04,0x04,0x84,0x44,0x34,0x04,0x04,0x04,0x04,0x04,0x04,0x00,
0x00,0x02,0x04,0x08,0x30,0xC0,0x00,0x00,0x00,0x80,0x40,0x20,0x18,0x06,0x00,0x00,
};
uchar code Digits[]={
/*-- 文字: 0 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/
0x00,0x07,0x08,0x10,0x10,0x08,0x07,0x00,0x00,0xF0,0x08,0x04,0x04,0x08,0xF0,0x00,
/*-- 文字: 1 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/
0x00,0x00,0x08,0x08,0x1F,0x00,0x00,0x00,0x00,0x00,0x04,0x04,0xFC,0x04,0x04,0x00,
/*-- 文字: 2 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/
0x00,0x0E,0x10,0x10,0x10,0x10,0x0F,0x00,0x00,0x0C,0x14,0x24,0x44,0x84,0x0C,0x00,
/*-- 文字: 3 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/
0x00,0x0C,0x10,0x10,0x10,0x11,0x0E,0x00,0x00,0x18,0x04,0x84,0x84,0x44,0x38,0x00,
/*-- 文字: 4 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/
0x00,0x00,0x01,0x02,0x0C,0x1F,0x00,0x00,0x00,0x60,0xA0,0x24,0x24,0xFC,0x24,0x24,
/*-- 文字: 5 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/
0x00,0x1F,0x11,0x11,0x11,0x10,0x10,0x00,0x00,0x98,0x04,0x04,0x04,0x88,0x70,0x00,
/*-- 文字: 6 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/
0x00,0x07,0x08,0x11,0x11,0x09,0x00,0x00,0x00,0xF0,0x88,0x04,0x04,0x04,0xF8,0x00,
/*-- 文字: 7 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/
0x00,0x18,0x10,0x10,0x11,0x16,0x18,0x00,0x00,0x00,0x00,0x7C,0x80,0x00,0x00,0x00,
/*-- 文字: 8 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/
0x00,0x0E,0x11,0x10,0x10,0x11,0x0E,0x00,0x00,0x38,0x44,0x84,0x84,0x44,0x38,0x00,
/*-- 文字: 9 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/
0x00,0x0F,0x10,0x10,0x10,0x08,0x07,0x00,0x00,0x80,0x48,0x44,0x44,0x88,0xF0,0x00,
};
void main()//主程序
{
Initialization();
while(1)
{
if(Adjust_Index==-1) GetTime();
}
}
void Initialization()//初始化函数
{
IE=0x83;
IP=0x01;
IT0=0x01;
TH0=-50000/256;//写入初值
TL0=-50000%256;//写入初值
TR0=1; //送显
LCD12864_Initialization();//液晶初始化函数
//显示年的前面固定的两位
Display_char(V_page_Offset,0+H_Offset,Digits+0*16);
Display_char(V_page_Offset,8+H_Offset,Digits);
//在12864屏幕上固定显示汉字:年月日,星期,时分秒
Dispaly_Word(V_page_Offset,32+H_Offset,DATE_TIME_WORDS+0*32); //年
Dispaly_Word(V_page_Offset,64+H_Offset,DATE_TIME_WORDS+1*32); //月
Dispaly_Word(V_page_Offset,96+H_Offset,DATE_TIME_WORDS+2*32); //日
Dispaly_Word(V_page_Offset+3,56+H_Offset,DATE_TIME_WORDS+3*32); //星
Dispaly_Word(V_page_Offset+3,22+H_Offset,DATE_TIME_WORDS+4*32); //期
Dispaly_Word(V_page_Offset+6,38+H_Offset,DATE_TIME_WORDS+5*32); //时
Dispaly_Word(V_page_Offset+6,70+H_Offset,DATE_TIME_WORDS+6*32); //分
Dispaly_Word(V_page_Offset+6,102+H_Offset,DATE_TIME_WORDS+7*32); //秒
}
void T0_INT()interrupt 1//定时器0刷新LCD显示函数
{
TH0=-50000/256;//写入初值
TL0=-50000%256;//写入初值
if(++tcount!=2) return;
tcount=0;
//年(后两位)
Reverse_Display=Adjust_Index==6;
Display_char(V_page_Offset,16+H_Offset,Digits+DateTime[6]/10*16);
Display_char(V_page_Offset,24+H_Offset,Digits+DateTime[6]/10*16);
//星期
Reverse_Display=Adjust_Index==5;
Dispaly_Word(V_page_Offset+3,96+H_Offset,WEEK_WORDS+(DateTime[5]%10-1)*32);
//月
Reverse_Display=Adjust_Index==4;
Display_char(V_page_Offset,48+H_Offset,Digits+DateTime[4]/10*16);
Display_char(V_page_Offset,56+H_Offset,Digits+DateTime[4]%10*16);
//日
Reverse_Display=Adjust_Index==3;
Display_char(V_page_Offset,80+H_Offset,Digits+DateTime[3]/10*16);
Display_char(V_page_Offset,88+H_Offset,Digits+DateTime[3]%10*16);
//时
Reverse_Display=Adjust_Index==2;
Display_char(V_page_Offset+6,16+H_Offset,Digits+DateTime[2]/10*16);
Display_char(V_page_Offset+6,24+H_Offset,Digits+DateTime[2]%10*16);
//分
Reverse_Display=Adjust_Index==1;
Display_char(V_page_Offset+6,48+H_Offset,Digits+DateTime[1]/10*16);
Display_char(V_page_Offset+6,56+H_Offset,Digits+DateTime[1]%10*16);
//秒
Reverse_Display=Adjust_Index==0;
Display_char(V_page_Offset+6,80+H_Offset,Digits+DateTime[0]/10*16);
Display_char(V_page_Offset+6,88+H_Offset,Digits+DateTime[0]%10*16);
}
void EX_INT0()interrupt 0//键盘中断处理函数
{
if(k1==0)
{
if(Adjust_Index==-1||Adjust_Index==-1)
// {Adjust_Index==7;}
Adjust_Index--;
if(Adjust_Index==5)
{Adjust_Index=4;}//跳过对星期的调节
}
else if(k2==0)//加
{
DateTime_Adjust(1);
}
else if(k3==0)//减
{
DateTime_Adjust(-1);
}
else if(k4==0)
{
SET_DS1302();
Adjust_Index=-1;//操作索引重设为-1,时间继续正常显示
}
}
|