#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define LCD1602_DATAPINS P0
sbit DSIO=P3^4;
sbit RST=P3^5;
sbit SCLK=P3^6;
sbit beep=P1^5;
sbit LCD1602_E=P2^7;
sbit LCD1602_RW=P2^5;
sbit LCD1602_RS=P2^6;
sbit s1=P2^0; //s1為功能鍵
sbit s2=P2^1; //s2為增加鍵
sbit s3=P2^2; //s3為減少鍵
int i, t0_num,s1num,rd,flag_ri,flag,count; //flag_ri為鬧鐘響標志,flag為時間調整標志
uchar year,month,day,week,sec,min,hou,c_day,c_week,c_month,c_year,c_sec,c_min,c_hou;
uchar code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
uchar code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
uchar TIME[7] = {0, 0, 0x00, 0x01, 0x01, 0x01, 0x18};
uchar CLOCK[3]={0x00,0x01,0x00};
void Ds1302ReadTime();//hanshushengming
void LcdWriteCom(uchar com) ;
void delay(unsigned int i) //延時程序
{
char j;
for(i; i > 0; i--)
for(j = 200; j > 0; j--);
}
void init()
{
flag=0; //時間調整標志
s1num=0; //s1按下的次數
flag_ri=0; //鬧鐘響標志
}
void Ds1302Write(uchar addr, uchar dat) //
{
uchar n;
RST = 0;
_nop_();//延時一個機器周期的意思
SCLK = 0;//先將SCLK置低電平。
_nop_();
RST = 1; //然后將RST(CE)置高電平。
_nop_();
for (n=0; n<8; n++)//開始傳送八位地址命令
{
DSIO = addr & 0x01;//數據從低位開始傳送
addr >>= 1;
SCLK = 1;//數據在上升沿時,DS1302讀取數據
_nop_();
SCLK = 0;
_nop_();
}
for (n=0; n<8; n++)//寫入8位數據
{
DSIO = dat & 0x01;
dat >>= 1;
SCLK = 1;//數據在上升沿時,DS1302讀取數據
_nop_();
SCLK = 0;
_nop_();
}
RST = 0;//傳送數據結束
_nop_();
}
uchar Ds1302Read(uchar addr)
{
uchar n,dat,dat1;
RST = 0;
_nop_();
SCLK = 0;//先將SCLK置低電平。
_nop_();
RST = 1;//然后將RST(CE)置高電平。
_nop_();
for(n=0; n<8; n++)//開始傳送八位地址命令
{
DSIO = addr & 0x01;//數據從低位開始傳送
addr >>= 1;
SCLK = 1;//數據在上升沿時,DS1302讀取數據
_nop_();
SCLK = 0;//DS1302下降沿時,放置數據
_nop_();
}
_nop_();
for(n=0; n<8; n++)//讀取8位數據
{
dat1 = DSIO;//從最低位開始接收
dat = (dat>>1) | (dat1<<7);
SCLK = 1;
_nop_();
SCLK = 0;//DS1302下降沿時,放置數據
_nop_();
}
RST = 0;
_nop_(); //以下為DS1302復位的穩定時間,必須的。
SCLK = 1;
_nop_();
DSIO = 0;
_nop_();
DSIO = 1;
_nop_();
return dat;
}
void Ds1302Init() //1302初始化
{
uchar n;
Ds1302Write(0x8E,0X00); //禁止寫保護,就是關閉寫保護功能
for (n=0; n<7; n++)//寫入7個字節的時鐘信號:分秒時日月周年
{
Ds1302Write(WRITE_RTC_ADDR[n],TIME[n]);
}
Ds1302Write(0x8E,0x80); //打開寫保護功能
Ds1302ReadTime();
}
void Ds1302ReadTime()
{
uchar n;
for (n=0; n<7; n++)//讀取7個字節的時鐘信號:分秒時日月周年
{
TIME[n] = Ds1302Read(READ_RTC_ADDR[n]);
}
}
/* readbyteds1302() //從ds1302讀一個字節
{
uchar i;
uchar tempdata;
for(i=0;i<8;i++)
{
// if(DSIO)
// tempdata=(tempdata>>1)|0x80;
// else
// tempdata>>=1;
if(DSIO)
tempdata|=(1<<i); //讀到高電平,置位相應位
else
tempdata&=(~(1<<i)); //讀到低電平,清零相應位
SCLK=0;
SCLK=1;
}
return tempdata;
}
writebyteds1302(uchar ds1302dat) //向ds1302寫入一個字節
{
uchar i;
uchar tempdata=ds1302dat;
for(i=8;i>0;i--)
{
DSIO=tempdata&&0x01;
tempdata>>=1;
SCLK=0;
SCLK=1;
}
return tempdata;} */
void LcdWriteCom(uchar com) //寫入命令
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 0; //選擇寫入命令
LCD1602_RW = 0; //選擇寫入
LCD1602_DATAPINS = com; //由于4位的接線是接到P0口的高四位,所以傳送高四位不用改
delay(1);
LCD1602_E = 1; //寫入時序
delay(1);
LCD1602_E = 0;
// Lcd1602_Delay1ms(1);
LCD1602_DATAPINS = com << 4; //發送低四位
delay(1);
LCD1602_E = 1; //寫入時序
delay(1);
LCD1602_E = 0;
}
void LcdInit() //LCD初始化子程序
{
LcdWriteCom(0x32); //將8位總線轉為4位總線
LcdWriteCom(0x28); //在四位線下的初始化
LcdWriteCom(0x0c); //開顯示不顯示光標
LcdWriteCom(0x06); //寫一個指針加1
LcdWriteCom(0x01); //清屏
LcdWriteCom(0x80); //設置數據指針起點
}
void LcdWriteData(uchar dat) //寫入數據
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 1; //選擇寫入數據
LCD1602_RW = 0; //選擇寫入
LCD1602_DATAPINS = dat; //由于4位的接線是接到P0口的高四位,所以傳送高四位不用改
delay(5);
LCD1602_E = 1; //寫入時序
delay(5);
LCD1602_E = 0;
LCD1602_DATAPINS = dat << 4; //寫入低四位
delay(5);
LCD1602_E = 1; //寫入時序
delay(5);
LCD1602_E = 0;
}
void Lcddisplay()
{
LcdWriteCom(0x80+0X40); //第二行顯示
LcdWriteData('0'+TIME[2]/16); //時的高位
LcdWriteData('0'+(TIME[2]&0x0f)); //時的低位
LcdWriteData('-'); //顯示時-分-秒的連接符
LcdWriteData('0'+TIME[1]/16); //分
LcdWriteData('0'+(TIME[1]&0x0f));
LcdWriteData('-');
LcdWriteData('0'+TIME[0]/16); //秒
LcdWriteData('0'+(TIME[0]&0x0f));
LcdWriteCom(0x80); //1602第一行顯示
LcdWriteData('2');
LcdWriteData('0');
LcdWriteData('0'+TIME[6]/16); //年
LcdWriteData('0'+(TIME[6]&0x0f));
LcdWriteData('-');
LcdWriteData('0'+TIME[4]/16); //月
LcdWriteData('0'+(TIME[4]&0x0f));
LcdWriteData('-');
LcdWriteData('0'+TIME[3]/16); //日
LcdWriteData('0'+(TIME[3]&0x0f));
switch('0'+TIME[5])
{
case '1':LcdWriteCom(0x80+13);//0x80+13意思為在第一行第13列開始顯示星期幾
LcdWriteData('M');
LcdWriteData('o');
LcdWriteData('n');
break;
case '2':LcdWriteCom(0x80+13);
LcdWriteData('T');
LcdWriteData('u');
LcdWriteData('e');
break;
case '3':LcdWriteCom(0x80+13);
LcdWriteData('W');
LcdWriteData('e');
LcdWriteData('d');
break;
case '4':LcdWriteCom(0x80+13);
LcdWriteData('T');
LcdWriteData('h');
LcdWriteData('u');
break;
case '5':LcdWriteCom(0x80+13);
LcdWriteData('F');
LcdWriteData('r');
LcdWriteData('i');
break;
case '6':LcdWriteCom(0x80+13);
LcdWriteData('S');
LcdWriteData('a');
LcdWriteData('t');
break;
case '7':LcdWriteCom(0x80+13);
LcdWriteData('S');
LcdWriteData('u');
LcdWriteData('n');
break;
}
LcdWriteCom(0x80+0x40+8);
LcdWriteData('0'+(CLOCK[2]/16)); //顯示鬧鐘時高位
LcdWriteData('0'+(CLOCK[2]&0x0f));
LcdWriteData('-');
LcdWriteData('0'+CLOCK[1]/16);
LcdWriteData('0'+(CLOCK[1]&0x0f));
LcdWriteData('-');
LcdWriteData('0'+CLOCK[0]/16);
LcdWriteData('0'+(CLOCK[0]&0x0f));
}
void write1(uchar add,uchar dat) //寫時分秒函數
{
char former,latter;
former=dat/10;
latter=dat%10;
LcdWriteCom(0x80+0X40+add);
LcdWriteData(0x30+former);
LcdWriteData(0x30+latter);
}
void write2(uchar add,uchar dat) //寫年月日函數
{
char former,latter;
former=dat/10;
latter=dat%10;
LcdWriteCom(0x80+add);
LcdWriteData(0x30+former);
LcdWriteData(0x30+latter);
}
void write3(char dat) //星期函數
{ LcdWriteCom(0x80+13);
switch(dat)
{ case 1: LcdWriteData('M');
LcdWriteData('o');
LcdWriteData('n');
break;
case 2: LcdWriteData('T');
LcdWriteData('u');
LcdWriteData('e');
break;
case 3: LcdWriteData('W');
LcdWriteData('e');
LcdWriteData('d');
break;
case 4: LcdWriteData('T');
LcdWriteData('h');
LcdWriteData('u');
break;
case 5: LcdWriteData('F');
LcdWriteData('r');
LcdWriteData('i');
break;
case 6: LcdWriteData('S');
LcdWriteData('a');
LcdWriteData('t');
break;
case 7: LcdWriteData('S');
LcdWriteData('u');
LcdWriteData('n');
break;
}
}
void keyscan() //鍵盤掃描函數
{
/* if(flag_ri==1) //鬧鐘響標志flag_ri
{
if((s1==0)||(s2==0)||(s3==0)) //如果任意一個按鍵按下
{
delay(10); //去抖動
if((s1==0)||(s2==0)||(s3==0)) //在此判斷是否按鍵真正按下
{
while(!(s1&&s2&&s3)); //檢測是否松手
beep=0;
flag_ri=0;
}
}
} */
if(s1==0) //s1按下
{
delay(10); //去抖
if(s1==0) //再次判斷s1是否真正按下
{
delay(10);
while(!s1);
s1num++;
flag=1;
switch(s1num)
{
case 1:LcdWriteCom(0x80+0X40);//光標定位到“時”
LcdWriteCom(0x0f); //光標閃爍0000 1111 /0000 1DCB D為開顯示C為顯示光標B為光標閃爍
break;
case 2: LcdWriteCom(0x80+0X40+3);//光標定位到“分”
LcdWriteCom(0x0f);
break;
case 3: LcdWriteCom(0x80+0X40+6);//光標定位到“秒”
LcdWriteCom(0x0f);
break;
case 4: LcdWriteCom(0x80);//光標定位到“年”
LcdWriteCom(0x0f);
break;
case 5: LcdWriteCom(0x80+5);//光標定位到“月”
LcdWriteCom(0x0f);
break;
case 6: LcdWriteCom(0x80+8);//光標定位到“日”
LcdWriteCom(0x0f);
delay(1000);
break;
case 7: LcdWriteCom(0x80+13);//光標定位到“周”
LcdWriteCom(0x0f);
break;
case 8: LcdWriteCom(0x80+0x40+8);//光標定位到鬧鐘的時
LcdWriteCom(0x0f);
break;
case 9: LcdWriteCom(0x80+0x40+11);//光標定位到鬧鐘的分
LcdWriteCom(0x0f);
break;
case 10: LcdWriteCom(0x80+0x40+14);//光標定位到鬧鐘的秒
LcdWriteCom(0x0f);
break;
case 11:LcdWriteCom(0x01);//清全屏
LcdWriteCom(0x0c); //關閃爍
Ds1302Write(0x8E,0X00); //禁止寫保護,就是關閉寫保護功能
Ds1302Write(0x80, sec);
Ds1302Write(0x82,min);
Ds1302Write(0x84,hou);
Ds1302Write(0x86,day);
Ds1302Write(0x88,month);
Ds1302Write(0x8a,week);
Ds1302Write(0x8c,year);
Ds1302Write(0x8E,0x80); //打開寫保護功能
break;
flag=0;
}
}
if(s1num!=0) // 按下s1之后才能進行時間的加減
{
if(s2==0)
{
delay(10); // 去抖
if(s2==0)
Ds1302Write(0x8E,0X00); //禁止寫保護,就是關閉寫保護功能
while(!s2==0);
switch(s1num)
{
case 1:hou++;
if(hou==24)
hou=0;
LcdWriteCom(0x80);
write1(0,hou);
Ds1302Write(0x84,hou);
Ds1302Write(0x8E,0x80); //打開寫保護功能
break;
case 2:min++;
if(min==60)
min=0;
LcdWriteCom(0x80+0X40+3);
write1(3,min);
Ds1302Write(0x82,min);
Ds1302Write(0x8E,0x80); //打開寫保護功能
break;
case 3:sec++;
if(sec==60)
sec=0;
LcdWriteCom(0x80+0X40+6);
write1(6,sec);
Ds1302Write(0x80,sec);
Ds1302Write(0x8E,0x80); //打開寫保護功能
break;
case 4:year++;
if(year==100)
year=0;
LcdWriteCom(0x80);
write2(0,year);
Ds1302Write(0x8c,year);
Ds1302Write(0x8E,0x80); //打開寫保護功能
break;
case 5:month++;
if(month==13)
month=1;
LcdWriteCom(0x80+5);
write2(5,month);
Ds1302Write(0x88,month);
Ds1302Write(0x8E,0x80); //打開寫保護功能
break;
case 6:day++;
if(day==32)
day=0;
LcdWriteCom(0x80+8);
write2(8,day);
Ds1302Write(0x86,day);
Ds1302Write(0x8E,0x80); //打開寫保護功能
break;
case 7:week++;
if(week==8)
week=1;
LcdWriteCom(0x80+13);
write3(week);
Ds1302Write(0x8a,week);
Ds1302Write(0x8E,0x80); //打開寫保護功能
break;
case 8:c_hou++;
if(c_hou==24)
hou=0;
LcdWriteCom(0x80+0x40+8);
write1(8,hou);
Ds1302Write(0x8E,0x80); //打開寫保護功能
break;
case 9:c_min++;
if(c_min==60)
c_min=0;
LcdWriteCom(0x80+0X40+11);
write1(11,c_min);
Ds1302Write(0x8E,0x80); //打開寫保護功能
break;
case 10:c_sec++;
if(c_sec==60)
c_sec=0;
LcdWriteCom(0x80+0X40+14);
write1(14,c_sec);
Ds1302Write(0x8E,0x80); //打開寫保護功能
break;
}
}
if(s3==0)
{
delay(10); // 去抖
if(s3==0)
Ds1302Write(0x8E,0X00); //禁止寫保護,就是關閉寫保護功能
while(!s3==0);
switch(s1num)
{ case 1:hou--;
if(hou==-1)
hou=23;
LcdWriteCom(0x80);
write1(0,hou);
Ds1302Write(0x84,hou);
Ds1302Write(0x8E,0x80); //打開寫保護功能
break;
case 2:min--;
if(min==-1)
min=59;
LcdWriteCom(0x80+0X40+3);
write1(3,min);
Ds1302Write(0x82,min);
Ds1302Write(0x8E,0x80); //打開寫保護功能
break;
case 3:sec--;
if(sec==-1)
sec=59;
LcdWriteCom(0x80+0X40+6);
write1(6,sec);
Ds1302Write(0x80,sec);
Ds1302Write(0x8E,0x80); //打開寫保護功能
break;
case 4:year--;
if(year==-1)
year=99;
LcdWriteCom(0x80);
write1(0,year);
Ds1302Write(0x8c,year);
Ds1302Write(0x8E,0x80); //打開寫保護功能
break;
case 5:month--;
if(month==0)
month=11;
LcdWriteCom(0x80+5);
write2(5,month);
Ds1302Write(0x88,month);
Ds1302Write(0x8E,0x80); //打開寫保護功能
break;
case 6:day--;
if(day==0)
day=31;
LcdWriteCom(0x80+8);
write2(8,day);
Ds1302Write(0x86,day);
Ds1302Write(0x8E,0x80); //打開寫保護功能
break;
case 7:week--;
if(week==0)
week=7;
LcdWriteCom(0x80+13);
write3(week);
Ds1302Write(0x8a,week);
Ds1302Write(0x8E,0x80); //打開寫保護功能
break;
case 8:hou--;
if(hou==-1)
hou=23;
LcdWriteCom(0x80+0x40+8);
write1(8,c_hou);
Ds1302Write(0x8E,0x80); //打開寫保護功能
break;
case 9:c_min--;
if(min==-1)
min=59;
LcdWriteCom(0x80+0X40+11);
write1(11,c_min);
Ds1302Write(0x8E,0x80); //打開寫保護功能
break;
case 10:c_sec--;
if(c_sec==-1)
c_sec=59;
LcdWriteCom(0x80+0X40+14);
write1(14,c_sec);
Ds1302Write(0x8E,0x80); //打開寫保護功能
break;
}
}
}
}
}
void main ()
{
init();
LcdInit();
Ds1302Init();
while(1)
{
if(flag_ri==1)
{
beep=1;
delay(60000);
beep=0;
}
Ds1302ReadTime();
Lcddisplay(); //初始時刻
keyscan();
if(flag==0&&flag_ri==0)
{
keyscan();
}
Ds1302ReadTime();
/* if(sec==c_sec)
{
if(min==c_min)
{
if(hou==c_hou)
{ flag_ri=1;
beep=1;
delay(60000); //響一分鐘
beep=0;
keyscan();
}
}
} */
}
}
|