#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;
}
|