#include <reg51.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit DS1302_CLK=P1^0;//實時時鐘時鐘線引腳
sbit DS1302_IO=P1^1; //實時時鐘數據線引腳
sbit DS1302_RST=P1^2;//實時時鐘復位線引腳
sbit ACC0=ACC^0;
sbit ACC7=ACC^7;
uchar hide_sec,hide_min,hide_hour,hide_day,hide_week,hide_month,hide_year;//秒,分,時到日,月,年位閃的計數
sbit Set=P3^4; //模式切換鍵,對應實驗板K5
sbit Up=P3^5; //加法按鈕,對應實驗板K6
sbit Down=P3^6; //減法按鈕,對應實驗板K7
sbit out=P3^7; //立刻跳出調整模式按鈕,對應實驗板K8
//sbit p35=P3^5;//定時時間轉換
sbit BEEP=P3^2;
sbit guang=P3^3;
uchar done,count,temp,up_flang,down_flang;
uchar h;
bit a,b; //閃爍標志位
uchar week_value[3];
void show_time(); //液晶顯示程序
//12864液晶顯示部分子程序
sbit rs =P2^0;
sbit rw =P2^1;
sbit e =P2^2;
#define lcddata P0
sbit busy=P0^7; //lcd busy bit
void wr_d_lcd (uchar content);
void wr_i_lcd (uchar content);
void clrram_lcd(void);
void init_lcd(void);
void busy_lcd(void);
void rev_row_lcd(uchar row);
void rev_co_lcd(uchar row,uchar col,uchar mode);
void clr_lcd(void);
void wr_co_lcd(uchar row,uchar col,uchar lcddata1,uchar lcddata2);
void wr_row_lcd(uchar row,char*p);
unsigned char idata i,tl0_temp=0,th0_temp=0;
//液晶初始化
void init_lcd(void)
{
wr_i_lcd(0x06); //光標的移動方向
wr_i_lcd(0x0c); //開顯示,關游標
}
//填充夜晶DDRAM全為空格
void clrram_lcd(void)
{
wr_i_lcd(0x30);
wr_i_lcd(0x01);
}
//對液晶寫數據
//content為要寫入的數據
void wr_d_lcd(uchar content)
{
busy_lcd();
rs=1;
rw=0;
lcddata=content;
e=1;
e=0;
}
//對液晶寫指令
//content為要寫入的指令代碼
void wr_i_lcd(uchar content)
{
busy_lcd();
rs=0;
rw=0;
lcddata=content;
e=1;
e=0;
}
//夜晶檢測忙狀態
//在寫入前必須執行
void busy_lcd(void)
{
lcddata=0xff;
rs=0;
rw=1;
e=1;
while(busy==1) ;
e=0;
}
//指定要顯示字符的坐標
void gotoxy(unsigned char y,unsigned char x)
{
if(y==1)
wr_i_lcd(0x80|x);
if(y==2)
wr_i_lcd(0x90|x);
if(y==3)
wr_i_lcd((0x80|x)+8);
if(y==4)
wr_i_lcd((0x90|x)+8);
}
//液晶顯示字符串程序
void print(uchar*str)
{
while(*str!='\0')
{
wr_d_lcd(*str);
str++;
}
}
//DS1302時鐘部分子程序模塊
typedef struct_SYSTEMTIME_
{
uchar Second;
uchar Minute;
uchar Hour;
uchar Week;
uchar Day;
uchar Month;
uchar Year;
uchar DateString[11];
uchar TimeString[9];
}
SYSTEMTIME;//定義的時間類型
SYSTEMTIME CurrentTime;
#define AM(X) X
#define PM(X) (X+12) //轉成24小時制
#define DS1302_SECOND 0X80 //時鐘芯片的寄存器位置,存放時間
#define DS1302_MINUTE 0X82
#define DS1302_HOUR 0X84
#define DS1302_WEEK 0X8A
#define DS1302_DAY 0X86
#define DS1302_MONTH 0X88
#define DS1302_YEAR 0X8C \
//實時時鐘寫入一個字節(內部函數)
void DS1302InputByte(uchar d)
{
uchar i;
ACC=d;
for(i=8;i>0;i--)
{
DS1302_IO=ACC0;
DS1302_CLK=1;
DS1302_CLK=0;
ACC=ACC>>1;
}
}
//實時時鐘讀取一個字節
uchar DS1302OutputByte(void)
{
uchar i;
for(i=8;i>0;i--)
{
ACC=ACC>>1;
ACC7=DS1302_IO;
DS1302_CLK=1;
DS1302_CLK=0;
}
return(ACC);
}
//ucAddr:DS1302地址,ucData:要寫的數據
void Write 1302(uchar ucAddr,uchar ucDa)
{
DS1302_RST=0;
DS1302_CLK=0;
DS1302_RST=1;
DS1302InputByte;//地址,命令
DS1302InputByte;//寫1Byte數據
DS1302_CLK=1;
DS1302_RST=0;
}
//讀取DS1302某地址的數據
uchar Read 1302(uchar ucAddr)
{
uchar ucData;
DS1302_RST=0;
DS1302_CLK=0;
DS1302_RST=1;
DS1302InputByte(ucAdd|0x01);//地址,命令
ucData=DS1302OutputByte();//讀1Byte數據
DS1302_CLK=1;
DS1302_RST=0;
return(ucData);
}
//獲取時鐘芯片的時鐘數據到自定義的結構型數組
void DS1302_GetTime(SYSTEMTIME*Time)
{
uchar ReadValue;
ReadValue=Read1302(DS13012_SECOND);
Time->Second=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);//轉換為相應的10進制數
ReadValue=Read1302(DS13012_MINUTE);
Time->Minute=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);
ReadValue=Read1302(DS13012_HOUR);
Time->Hour=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);
ReadValue=Read1302(DS13012_DAY);
Time->Day=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);
ReadValue=Read1302(DS13012_WEEK);
Time->Week=((ReadValue&0x10)>>4)*10+(ReadValue&0x0F);
ReadValue=Read1302(DS13012_MONTH);
Time->Month=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);
ReadValue=Read1302(DS13012_YEAR);
Time->Year=((ReadValue&0xf0)>>4)*10+(ReadValue&0x0F);
}
//將時間年月日星期數據轉換成液晶顯示字符串,
//放到數據里DateString[]
void DateStr(SYSTEMTIME*Time)
{
uchar tab[]={0XD2,0XBB,0XB6,0XFE,0XC8,0XFD,0XCB,0XC4,0XCE,0XE5,
0XC1,0XF9,0XC8,0XD5 };
if(hide_year<2)
{
Time->DateString[0]='2';
Time->DateString[1]='2';
Time->DateString[2]=Time->Year/10+'0';
Time->DateString[3]=Time->Year%10+'0';
}
else
{
Time->DateString[0]='';
Time->DateString[1]='';
Time->DateString[2]='';
Time->DateString[3]='';
}
Time->DateString[4]='-';
if(hide_month<2)
{
Time->DateString[5]=Time->Month/10+'0';
Time->DateString[6]=Time->Month%10+'0';
}
else
{
Time->DateString[5]='';
Time->DateString[6]='';
}
Time->DateString[7]='-';
if(hide_day<2)
{
Time->DateString[8]=Time->Day/10+'0';
Time->DateString[9]=Time->Day%10+'0';
}
else
{
Time->DateString[8]=' ';
Time->DateString[9]=' ';
}
if(hide_week<2)
{
week_value[0]=tab[2*(Time->Week%10)-2];
week_value[1]=tab[2*(Time->Week%10)-2];
}
else
{
week_value[0]='';
week_value[1]='';
}
week_value[2]='\0';
Time->DateString[10]='\0';//字符串末尾加'\0',判斷結束字符
}
//將時分秒數據轉換成液晶顯示字符串,
//放到數據里TimeString[]
void TimeTostr(SYSTEMTIME*Time)
{
if(hide_hour<2)
{
Time->TimeString[0]=Time->Hour/10+'0';
Time->TimeString[1]=Time->Hour%10+'0';
//定時器使能,開始計數
if(Time->Hour<0x06||Time->Hour>0x11)
TR0=1;
else
if(guang==0)
TR0=1;
else
TR0=0;
else
{
Time->TimeString[0]='';
Time->TimeString[1]='';
}
Time->TimeString[2]=':';
if(hide_min<2)
{
Time->TimeString[3]=Time->Minute/10+'0';
Time->TimeString[4]=Time->Minute%10+'0';
}
else
{
Time->TimeString[3]='';
Time->TimeString[4]='';
}
Time->TimeString[5]=':';
if(hide_sec<2)
{
Time->TimeString[6]=Time->Second/10+'0';
Time->TimeString[7]=Time->Second%10+'0';
}
else
{
Time->TimeString[6]='';
Time->TimeString[7]='';
}
Time->TimeString[8]='\0';
}
}
//時鐘芯片初始化
void Initial_Ds1302(void)
{
uchar Second=Read1302(DS1302_SECOND);
if(Second&0x80)//判斷時鐘芯片是否關閉
{
Write 1302(0x8e,0x00);//寫入允許
Write 1302(0x8c,0x12); //以下寫入初始化時間
Write 1302(0x88,0x11);
Write 1302(0x86,0x26);
Write 1302(0x8a,0x01);
Write 1302(0x84,0x18);
Write 1302(0x82,0x17);
Write 1302(0x80,0x55);
Write 1302(0x8e,0x80);//禁止寫入
}
}
//延時子程序模塊
void mdelay(uchar delay)
{
uint i;
for(;delay>0;delay--)
for(i=0;i<80;i++)//延時一毫秒
;
}
//按鍵設置程序模塊
//跳出調整模式,返回默認顯示
void outkey()
{
uchar Second;
if(out==0)
{
mdelay(5);
count=0;
hide_sec=0, hide_min=0, hide_hour=0,hide_day=0,hide_week=0, hide_month=0,hide_year=0;
Second=Read1302(DS1302_SECOND);
Write 1302(0x8e,0x00); //寫入允許
Write 1302(0x80,Second&0x7f);
Write 1302(0x8E,0x80);//禁止寫入
done=0;
}
}
//升序按鍵
void Upkey()
{
Up=1;
if(Up=0)
{
mdelay(5);
switch(count)
{
case 1: temp=Read1302(DS1302_SECOND);//讀取秒數
temp=((temp&0x70)>>4)*10+(temp&0x0F);
temp=temp+1; //秒數+1
up_flag=1; //數據調整后更新標志
if((temp)>59) //超過59秒,清零
temp=0;
temp=temp/10*16+temp%10;
break;
case 2: temp=Read1302(DS1302_MINUTE);//讀取分數
temp=((temp&0x70)>>4)*10+(temp&0x0F);
temp=temp+1; //分數+1
up_flag=1; //數據調整后更新標志
if((temp)>59) //超過59分,清零
temp=0;
temp=temp/10*16+temp%10;
break;
case 3: temp=Read1302(DS1302_HOUR);//讀取小時數
temp=((temp&0x70)>>4)*10+(temp&0x0F);
temp=temp+1; //小時數+1
up_flag=1; //數據調整后更新標志
if((temp)>23) //超過23小時,清零
temp=0;
temp=temp/10*16+temp%10;
//定時器使能,開始計數
if(temp<0x06||temp>0x17)
{
TR0=1;
}
else
TR0=0;
break;
case 4: temp=Read1302(DS1302_WEEK);//讀取 星期數
temp=((temp&0x70)>>4)*10+(temp&0x0F);
temp=temp+1; //興趣數+1
up_flag=1; //數據調整后更新標志
if((temp)>7)
temp=1;
temp=temp/10*16+temp%10;
break;
case 5: temp=Read1302(DS1302_DAY);//讀取日數
temp=((temp&0x70)>>4)*10+(temp&0x0F);
temp=temp+1; //日數+1
up_flag=1;
if((temp)>31)
temp=1;
temp=temp/10*16+temp%10;
break;
case 6: temp=Read1302(DS1302_MONTH);//讀取月數
temp=((temp&0x70)>>4)*10+(temp&0x0F);
temp=temp+1; //月數+1
up_flag=1;
if((temp)>12)
temp=1;
temp=temp/10*16+temp%10;
break;
case 7: temp=Read1302(DS1302_YEAR);//讀取年數
temp=((temp&0x70)>>4)*10+(temp&0x0F);
temp=temp+1; //年數+1
up_flag=1;
if((temp)>99)
temp=0;
temp=temp/10*16+temp%10;
break;
default:break;
}
//while(Up==0) ;
}
}
//降序按鍵
void Downkey
{
Down=1;
if(Down=0)
{
mdelay(5);
switch(count)
{
case 1: temp=Read1302(DS1302_SECOND);//讀取秒數
temp=((temp&0x70)>>4)*10+(temp&0x0F);
temp=temp-1; //秒數-1
down_flag=1; //數據調整后更新標志
if(temp==-1) //返回59秒,小于零
temp=59;
temp=temp/10*16+temp%10;
break;
case 2: temp=Read1302(DS1302_MINUTE);//讀取分數
temp=((temp&0x70)>>4)*10+(temp&0x0F);
temp=temp-1; //分數-1
down_flag=1; //數據調整后更新標志
if(temp==-1) //返回59分,小于零
temp=59;
temp=temp/10*16+temp%10;
break;
case 3: temp=Read1302(DS1302_HOUR);//讀取小時數
temp=((temp&0x70)>>4)*10+(temp&0x0F);
temp=temp-1; //小時數+1
down_flag=1; //數據調整后更新標志
if(temp==-1) //超過23小時,清零
temp=23;
temp=temp/10*16+temp%10;
//定時器使能,開始計數
if(temp<0x06||temp>0x17)
{
TR0=1;
}
else
TR0=0;
break;
case 4: temp=Read1302(DS1302_WEEK);//讀取 星期數
temp=((temp&0x70)>>4)*10+(temp&0x0F);
temp=temp-1; //興趣數-1
down_flag=1; //數據調整后更新標志
if(temp==0)
temp=7;
temp=temp/10*16+temp%10;
break;
case 5: temp=Read1302(DS1302_DAY);//讀取日數
temp=((temp&0x70)>>4)*10+(temp&0x0F);
temp=temp-1; //日數-1
down_flag=1;
if(temp==0)
temp=31;
temp=temp/10*16+temp%10;
break;
case 6: temp=Read1302(DS1302_MONTH);//讀取月數
temp=((temp&0x70)>>4)*10+(temp&0x0F);
temp=temp-1; //月數-1
down_flag=1;
if(temp==0)
temp=12;
temp=temp/10*16+temp%10;
break;
case 7: temp=Read1302(DS1302_YEAR);//讀取年數
temp=((temp&0x70)>>4)*10+(temp&0x0F);
temp=temp-1; //年數-1
down_flag=1;
if(temp==0)
temp=99;
temp=temp/10*16+temp%10;
break;
default:break;
}
//while(down==0);
}
}
//按鍵模式選擇
void Setkey()
{
Set=1;
if(Set==0)
{
mdelay(5);
count=count+1;//Setkey按一次,count加1
done=1; //進入調整模式
while(Set==0);
}
}
//按鍵功能執行
void keydone()
{
uxhar Second;
/* if(flag==0)
{
Write 1302(0x8e,0x00); //寫入允許
temp=Read1302(0x80);
Write 1302(0x80,temp|0x80);
Write 1302(0x8E,0x80);//禁止寫入
flag=1;
} */
Setkey (); //掃描模式切換按鍵
switch(count)
{
case 1:do //count=1 ,調整秒
{
outkey();//掃描跳出按鍵
Upkey();//掃描加按鍵
Downkey();//掃描減按鍵
if(up_flag==1||down_flag==1)//數據更新,重新寫入新的數據
{
Write 1302(0x8e,0x00);//寫入允許
Write 1302(0x80,temp);//寫入新的秒數
Write 1302(0x8e,0x80);//禁止寫入
up_flag=0;
down_flag=0;
}
if(Down!=0&&Up!=0)
{
hide_sec++;
if(hide_sec>3)
hide_sec=0;
}
else
hide_sec=0;
show_time();//液晶顯示顯示數據
}
while(count==2);
break;
case 2:do //count=2 ,調整分
{
hide_sec=0;
outkey();//掃描跳出按鍵
Upkey();//掃描加按鍵
Downkey();//掃描減按鍵
if(temp>0x60)
temp=0;
if(up_flag==1||down_flag==1)//數據更新,重新寫入新的數據
{
Write 1302(0x8e,0x00);//寫入允許
Write 1302(0x82,temp);//寫入新的分數
Write 1302(0x8e,0x80);//禁止寫入
up_flag=0;
down_flag=0;
}
if(Down!=0&&Up!=0)
{
hide_min++;
if(hide_min>3)
hide_min=0;
}
else
hide_min=0;
show_time();//液晶顯示顯示數據
}
while(count==3);
break;
case 3:do //count=3 ,調整小時
{
hide_min=0;
outkey();//掃描跳出按鍵
Upkey();//掃描加按鍵
Downkey();//掃描減按鍵
if(up_flag==1||down_flag==1)//數據更新,重新寫入新的數據
{
Write 1302(0x8e,0x00);//寫入允許
Write 1302(0x84,temp);//寫入新的分數
Write 1302(0x8e,0x80);//禁止寫入
up_flag=0;
down_flag=0;
}
if(Down!=0&&Up!=0)
{
hide_hour++;
if(hide_hour>3)
hide_hour=0;
}
else
hide_hour=0;
show_time();//液晶顯示顯示數據
}
while(count==4);
break;
case 4:do //count=4 ,調整星期
{
hide_hour=0;
outkey();//掃描跳出按鍵
Upkey();//掃描加按鍵
Downkey();//掃描減按鍵
if(up_flag==1||down_flag==1)//數據更新,重新寫入新的數據
{
Write 1302(0x8e,0x00);//寫入允許
Write 1302(0x8a,temp);//寫入新的分數
Write 1302(0x8e,0x80);//禁止寫入
up_flag=0;
down_flag=0;
}
if(Down!=0&&Up!=0)
{
hide_week++;
if(hide_week>3)
hide_week=0;
}
else
hide_week=0;
show_time();//液晶顯示顯示數據
}
while(count==5);
break;
case 5:do //count=5 ,調整日
{
hide_week=0;
outkey();//掃描跳出按鍵
Upkey();//掃描加按鍵
Downkey();//掃描減按鍵
if(temp>0x60)
temp=0;
if(up_flag==1||down_flag==1)//數據更新,重新寫入新的數據
{
Write 1302(0x8e,0x00);//寫入允許
Write 1302(0x86,temp);//寫入新的分數
Write 1302(0x8e,0x80);//禁止寫入
up_flag=0;
down_flag=0;
}
if(Down!=0&&Up!=0)
{
hide_day++;
if(hide_day>3)
hide_day=0;
}
else
hide_day=0;
show_time();//液晶顯示顯示數據
}
while(count==6);
break;
case 6:do //count= ,調整月
{
hide_day=0;
outkey();//掃描跳出按鍵
Upkey();//掃描加按鍵
Downkey();//掃描減按鍵
if(temp>0x60)
temp=0;
if(up_flag==1||down_flag==1)//數據更新,重新寫入新的數據
{
Write 1302(0x8e,0x00);//寫入允許
Write 1302(0x88,temp);//寫入新的分數
Write 1302(0x8e,0x80);//禁止寫入
up_flag=0;
down_flag=0;
}
if(Down!=0&&Up!=0)
{
hide_month++;
if(hide_month>3)
hide_momth=0;
}
else
hide_month=0;
show_time();//液晶顯示顯示數據
}
while(count==7);
break;
case 7:do //count=7 ,調整年
{
hide_month=0;
outkey();//掃描跳出按鍵
Upkey();//掃描加按鍵
Downkey();//掃描減按鍵
if(temp>0x60)
temp=0;
if(up_flag==1||down_flag==1)//數據更新,重新寫入新的數據
{
Write 1302(0x8e,0x00);//寫入允許
Write 1302(0x8c,temp);//寫入新的分數
Write 1302(0x8e,0x80);//禁止寫入
up_flag=0;
down_flag=0;
}
if(Down!=0&&Up!=0)
{
hide_year++;
if(hide_year>3)
hide_year=0;
}
else
hide_year=0;
show_time();//液晶顯示顯示數據
}
while(count==8);
break;
case 8:count=0;hide_year=0;//count8跳出調整模式,返回默認顯示狀態
Second=Read1302(DS1302_SECOND);
Write 1302(0x8e,0x00);//寫入允許
Write 1302(0x80,temp);//
Write 1302(0x8E,0x80);//禁止寫入
done=0;
break;//count=7,開始中斷,標志位置0并退出
default:break;
}
}
//液晶顯示主程序
void show_time()
{
DS1302_GetTime(&CurrentTime);//獲取時間芯片數據
TimeToStr(&CurrentTime); //時間數據轉換液晶字符
DateToStr(&CurrentTime); //日期數據轉換液晶字符
gotoxy(4,0);
print(" 時間:");
gotoxy(4,3);
print(CurrentTime.TimeString);//顯示時間
gotoxy(3,3);
print(CurrentTime.DateString);//顯示日期
gotoxy(3,0);
print("星期");
gotoxy(3,2);
print(week_value);//顯示星期
gotoxy(2,0);
print("定時:18:00--6:00");
gotoxy(1,0);
print("燈光狀態:明亮");
if(guang==0)
{
gotoxy(1,5);
print("黑暗");
}
mdelay(500);//掃描延時
}
//主程序
main()
{
//flag=1; //時鐘停止標志
init_lcd();
clrram_lcd();
Initial_DS1302();//時鐘芯片初始化
up_flag=0;
down_flag=0;
done=0;//進入默認液晶顯示
BEEP=1;
guang=1;
TMOD=0X01; //工作寄存器設置
ET0=1; //定時器0中斷使能
EA=1; //總中斷使能
TH0=0; //定時器計數寄存器賦初始值
TL0=0;
TCON=0x10; //工作寄存器設置
while(1)
{
while(done==1)
keydone(); //進入調整模式
while(done==0)
{
show_time();// 液晶顯示數據
Setkey(); //掃描各功能鍵
}
}
}
void INTTO() interrupt 1 //定時器0中斷服務程序,定時器計數滿溢出以后自動進入
{
TH0=0xff;
TL1=0x00;
BEEP=~BEEP;
}
|