/*此程序是一款用3216點陣屏與DS1302芯片以及
三個按鍵與STC12C5204AD 4KROM單片機組合成的
萬年歷電子鐘具體功能如下:正常情況下上半屏
(3208)顯示主時間。當第1次按下功能鍵時,下半
屏會左移滾動顯示“年、月、日、星期”,當再
次按下時,便進入年、月、日、星期、鬧鈴等調
整模式,按加與減方便調整,附加功能,當在左
移滾動顯示“年、月、日、星期”時,按下加“+”
按鍵,便可以回到主界面,當在響鈴時,按下
“+鍵”便可以將本次響鈴關閉,當按響鈴時下“-”
按鍵時,便可以關閉鬧鈴功能,再次按下時,可
以恢復鬧鈴功能*/
視頻效果祥見:http://www.tudou.com/programs/view/hQmJSwtHWWc/
完整的源代碼下載地址:http://www.zg4o1577.cn/f/dzwnl.rar
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
#define LINE P2//定義行線IO口,即74HC154控制端
sbit DATA1=P1^4;//74HC595數據端
sbit CLK=P1^5;//74HC595移位脈沖端
sbit CLKR=P1^6;//74HC595數據鎖存端
sbit BBT =P2^7;//蜂鳴器引腳
sbit SCLK=P1^2;//DS1302移位脈沖端
sbit DATA=P1^1;//DS1302數據端
sbit RST=P1^0;//DS1302控制端
sbit key=P3^4;//功能按鍵
sbit key1=P3^3;//加"+"按鍵
sbit key2=P3^2;//加"+"按鍵
uchar line;//行掃描變量
uchar move;//移位次數變量
uchar mov;//年月日時間左移變量,即移8次將1個字移完后加1
uchar yin;//按鍵計數器變量,一共10次,即功能按鍵有10種功能
uchar lk;//掃描兩行還是1行變量
uchar readvalue;//DS1302轉換結果變量
uchar shi,fen,nian,yue,ri,xin;//分別為:小時/分鐘/年/月/日/星期變量
uchar shin=12,fenn;//鬧鐘的小時與分鐘變量
bit dian;//主時間小數點位變量
bit shr,a,b,c,d,e,f,g,h,i;//按鍵對應的10種功能位變量
bit flag;//主程序與調整時間切換變量,即進入調整時間部分就不進入主時間部分
bit flag1;//鬧鐘標志位變量
bit clockbiao;//鬧鐘響鈴主標志位
uchar BUF[19];//4組緩存數組以便動態更改數據
/******************************************************/
/**************點陣0-9代碼(8*6點陣)******************/
/******************************************************/
uchar code table[]={
0x00,0x0E,0x11,0x11,0x11,0x11,0x11,0x0E,//0
0x00,0x04,0x0C,0x04,0x04,0x04,0x04,0x0E,//1
0x00,0x0E,0x11,0x01,0x02,0x04,0x08,0x1F,//2
0x00,0x0E,0x11,0x01,0x06,0x03,0x11,0x0E,//3
0x00,0x06,0x06,0x0A,0x0A,0x12,0x1F,0x02,//4
0x00,0x1F,0x10,0x10,0x1E,0x01,0x01,0x1E,//5
0x00,0x0E,0x11,0x10,0x1E,0x11,0x11,0x0E,//6
0x00,0x1F,0x01,0x02,0x02,0x04,0x04,0x08,//7
0x00,0x0E,0x11,0x11,0x0E,0x11,0x11,0x0E,//8
0x00,0x0E,0x11,0x11,0x0F,0x01,0x01,0x1E,//9
};
/******************************************************/
/**********兩個小數黑屏及堅線代碼8*6點陣)*************/
/******************************************************/
uchar code table1[]={
0x00,0x0C,0x0C,0x00,0x00,0x0C,0x0C,0x00,//為兩個小數點":"
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//為黑屏代碼
0x00,0x00,0x00,0x1E,0x1E,0x00,0x00,0x00//為兩堅線"-"
};
/******************************************************/
/****此數組為74HC154譯碼器代碼(注也可以不用數組)*****/
/******************************************************/
uchar code table2[]={
0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,//上半屏行代碼 0-7行
0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff//下半屏行代碼 8-15行
};
/******************************************************/
/*****************延時子程序1**************************/
/******************************************************/
void delaya(uint z)
{
uint x;
for(x=z;x>0;x--);
}
/******************************************************/
/*****************延時子程序2**************************/
/******************************************************/
void delay(uint z)
{
uint x,y;
for(x=200;x>0;x--)
for(y=z;y>0;y--);
}
/******************************************************/
/***************蜂鳴器響一聲子程序********************/
/******************************************************/
void bbtsoud()
{
BBT=0;//打開蜂鳴器
delay(50);//延時
BBT=1;//關閉它
}
/**********************************/
//向1302寫一個字節數據//
//入口參數:dat
/*********************************/
void write1302xei(uchar dat)
{
uchar x;
SCLK=0; delaya(2);
for(x=0;x<8;x++)
{
DATA=dat&0x01;//取出最低位,從而實現一位位傳送
delaya(2);
SCLK=1;
delaya(2);
SCLK=0;
dat>>=1;//等待傳送第二個字節
}
}
/**************************************/
//根據控制字向1302寫一個字節數據//
//入口參數:控制參數kong,實際參數can
/*************************************/
void write1302(uchar kong,uchar can)
{
SCLK=0;
RST=0;
RST=1;
delaya(2);
write1302xei(kong);
write1302xei(can);
SCLK=1;
RST=0;
}
/**************************************/
//向1302讀一個字節數據//
//入口參數:dat,x
/*************************************/
uchar read1302du()
{
uchar dat,x;
SCLK=0;
for(x=0;x<8;x++)
{
dat>>=1;
if(DATA==1)
dat|=0x80;
SCLK=1;
delaya(2);
SCLK=0;
delaya(2);
}
return dat;
}
/**************************************/
//根據控制字向1302讀一個字節數據//
//入口參數:控制參數kong 實際參:dat
/*************************************/
uchar read1302(uchar kong)
{
uchar dat;
RST=0;
SCLK=0;
RST=1;
write1302xei(kong);
dat=read1302du();
SCLK=1;
RST=0;
return dat;
}
/**************************************/
//根據控制字向1302讀一個字節數據//
//入口參數:分別寫入:日期:2010-03-07 時間:23:59:54 星期天
/*************************************/
void init1302()
{
/*以下是掉電保護函數通過判斷標志位是否為1來判斷*/
uchar flag;
flag=read1302(0x81);//讀秒數據
if(flag&0x80==1)//判斷最高位是否為1,若為1則說明芯片停止工作了,若為0則說明沒有停止
{
write1302(0x8e,0x00);//去掉保護
write1302(0x80,((12/10)<<4)|(12%10));/*顯示54秒/*先將BCD碼求模得到高位,然后左移四位,
得到了高四位,然后將BCD碼求余這樣就得到了低四位,然后相或就轉換成了二進制代碼了*/
write1302(0x82,((59/10)<<4)|(59%10));//顯示59分
write1302(0x84,((23/10)<<4)|(23%10));//顯示23點
write1302(0x86,((7/10)<<4)|(7%10));//顯示07日
write1302(0x88,((3/10)<<4)|(3%10));//顯示03月
write1302(0x8c,((10/10)<<4)|(10%10));//顯示10年
write1302(0x8a,((7/10)<<4)|(7%10));//顯示星期天
write1302(0x90,0xa5);//打開充電方式,選擇一個二極管2K電阻
write1302(0x8e,0x80);//打開保護
}
/*以下是開機復位函數*/
/*
write1302(0x8e,0x00);//去掉保護
write1302(0x80,((12/10)<<4)|(12%10));/*顯示54秒/*先將BCD碼求模得到高位,然后左移四位,
//得到了高四位,然后將BCD碼求余這樣就得到了低四位,然后相或就轉換成了二進制代碼了
write1302(0x82,((59/10)<<4)|(59%10));//顯示59分
write1302(0x84,((23/10)<<4)|(23%10));//顯示23點
write1302(0x86,((7/10)<<4)|(7%10));//顯示07日
write1302(0x88,((3/10)<<4)|(3%10));//顯示03月
write1302(0x8c,((10/10)<<4)|(10%10));//顯示10年
write1302(0x8a,((7/10)<<4)|(7%10));//顯示星期天
write1302(0x90,0xa5);//打開充電方式,選擇一個二極管2K電阻
write1302(0x8e,0x80);//打開保護
*/
}
/******************************************************/
/***************DS1302轉換結果子程序********************/
/******************************************************/
void value()
{
readvalue=read1302(0x83);//讀入分地址
fen=((readvalue&0x70)>>4)*10+(readvalue&0x0f);//將分16進制轉換成10進制
readvalue=read1302(0x85);//讀入小時地址
shi=((readvalue&0x70)>>4)*10+(readvalue&0x0f);//將小時16進制轉換成10進制
readvalue=read1302(0x87);//讀入日地址
ri=((readvalue&0x70)>>4)*10+(readvalue&0x0f);//將分日進制轉換成10進制
readvalue=read1302(0x89);//讀入月地址
yue=((readvalue&0x70)>>4)*10+(readvalue&0x0f);//將分月進制轉換成10進制
readvalue=read1302(0x8d);//讀入年地址
nian=((readvalue&0xf0)>>4)*10+(readvalue&0x0f);//將分年進制轉換成10進制
readvalue=read1302(0x8b);//讀入星期地址
xin=((readvalue&0x70)>>4)*10+(readvalue&0x0f);//將分星期進制轉換成10進制
}
/********************************/
/**74HC595移位寄存器送數子函數***/
/********************************/
void song(uchar dat)//帶參數函數
{
uchar num;//定義變量
for(num=0;num<6;num++)//移動6次將數據發送完畢
{
dat>>=1;//將數移走一位
DATA1=CY;//為1就將74HC595數據端置1
CLK=0;//上升沿送走數據
CLK=1;//高電平形成上升沿
}
}
/******************************************************/
/***裝一線數據子函數(即一行數據)主時間裝數函數********/
/******************************************************/
void yixian(uchar shi,uchar ge,uchar z)
{
BUF[0]=table[(8*(shi/10))+line];//顯示小時十位
BUF[1]=table[(8*(shi%10))+line];//顯示小時個位
BUF[2]=table1[z*8+line];//顯示兩個小數點,注意是不同的數組內喲
BUF[3]=table[(8*(ge/10))+line];//顯示分十位
BUF[4]=table[(8*(ge%10))+line];//顯示分個位
}
/******************************************************/
/***裝一線數據子函數(即一行數據)顯示黑屏子程序********/
/******************************************************/
void yixianhei()
{
uchar linee,i;
if(line>8)//如果是顯示下半屏,就會大于8
linee=line-8;
else
linee=line;//否則直接給數
for(i=0;i<5;i++)//循環5次得到5個數組的數
BUF[i]=table1[8+linee];//查表得到數,注意是數組1中的數
}
/******************************************************/
/*******主程序顯示子程序(包括上半屏與下半屏)********/
/******************************************************/
void xianzhu(uchar nia,uchar ye,uchar rii,uchar xi)
{
uchar temp;//左移數值變量
char i;//有符號變量
for(move=0;move<8;move++)//左移8次讓下半屏形成左移
{
for(line=0;line<8+lk;line++)//lk變量為選擇上半屏還是全屏變量,當它等于0時,只顯示上半屏時間,否則全屏顯示
{
if(line<8)//如果它小于8則說明lk變量為0,只讓它顯示上半屏的主時間
{
yixian(shi,fen,dian);//調用主時間一線數值裝載子函數
for(i=4;i>=0;i--)
song(~BUF[i]);//循環5次,將數組4-0的數全部發數到顯示屏上
}
else//如果大于16則就循環左移顯示下半屏的"年月日星期等信息"
{
uchar movee;//局部變量
movee=line-8;//line大于16,此時用它減去8就得到實際要顯示的值
BUF[0]=table[16+movee];//顯示數字"2"字
BUF[1]=table[movee];//顯示數字"0"字
BUF[2]=table[(8*(nia/10))+movee];//顯示年十位
BUF[3]=table[(8*(nia%10))+movee];//顯示年個位
BUF[4]=table1[16+movee];//顯示橫線"-"
BUF[5]=table[(8*(ye/10))+movee];//顯示月份十位
BUF[6]=table[(8*(ye%10))+movee];//顯示月份個位
BUF[7]=table1[16+movee];//顯示橫線"-"
BUF[8]=table[(8*(rii/10))+movee];//顯示日十位
BUF[9]=table[(8*(rii%10))+movee];//顯示日個位
BUF[10]=table1[16+movee];//顯示橫線"-"
BUF[11]=table[(8*(xi%10))+movee];//顯示星期幾
for(i=4;i>=0;i--)//循環5次將數發送給下半屏
{
temp=((BUF[i+mov]<<move)|(BUF[(i+1)+mov]>>(6-move)));//將左半屏數左移x位,然后將右
//半屏數右移6-x位,然后或一下就得到在左移了,此句是左移關鍵!
song(~temp);//送數出去
}
delaya(1000);//延時一下
}
LINE=table2[line];//打開行線,即174HC154行線端
CLKR=1;//在74HC595處鎖存起來
CLKR=0;
CLKR=1;
delaya(800);//延時一下
}
}
mov++;//顯示完一屏后,將移1個字變量加1,這樣就完成下一字顯示。原理是:顯示下一個數組
if(mov>13)//移完14次,就將它清0。原因是,程序全部定了19個數組,前面顯示數用了5個加現在14次,剛好19個數組
mov=0;//清0,重新開始顯示
}
/******************************************************/
/**********閃爍間斷顯示子程序(包括下半屏)************/
/******************************************************/
void xianshan()
{
char ii;//有符號變量
for(line=0;line<8;line++)//掃描8次,即完成一個字的移動
{
if(flag1==0)//如果標志位為0,則以0.5秒速度顯示時分鐘主界面
yixian(shi,fen,dian);//調用時分秒主界面子程序
if(flag1==1)//如果標志位為1,則以0.5秒速度顯示黑屏界面,形成閃爍效果
yixianhei();//調用黑屏子程序
for(ii=4;ii>=0;ii--)//循環5次將數發往顯示屏
song(~BUF[ii]);//送數
LINE=table2[line];//打開行線,即174HC154行線端
CLKR=1;//在74HC595處鎖存起來
CLKR=0;
CLKR=1;
delaya(800);
}
}
/******************************************************/
/**********年調整界面顯示子程序(包括下半屏)************/
/******************************************************/
void xiannian(uchar nia)//變量年
{
uchar movee;
char ii;
for(line=8;line<16;line++)//掃描8次,即完成一個字的移動,line等于8,表示在下半屏顯示
{
if(flag1==0)//如果標志位為1,則執行顯示部分
{
movee=line-8;
BUF[0]=table[16+movee];//顯示數字2
BUF[1]=table[movee];//顯示數字0
BUF[2]=table[(8*(nia/10))+movee];//顯示年十位
BUF[3]=table[(8*(nia%10))+movee];
BUF[4]=table1[16+movee];//顯示橫線
}
if(flag1==1)
yixianhei();//否則顯示黑屏
for(ii=4;ii>=0;ii--)//循環5次將數發往顯示屏
song(~BUF[ii]);//送數
LINE=table2[line];//打開行線,即174HC154行線端
CLKR=1;//在74HC595處鎖存起來
CLKR=0;
CLKR=1;
delaya(800);
}
}
/******************************************************/
/*********月/日調整界面顯示子程序(包括下半屏)********/
/******************************************************/
void xianriyue(uchar ye,uchar rii)//月與日變量
{
uchar movee;
char ii;
for(line=8;line<16;line++)//掃描8次,即完成一個字的移動,line等于8,表示在下半屏顯示
{
if(flag1==0)//同上如果為0就顯示,為1就黑屏,形成閃爍
{
movee=line-8;
BUF[0]=table[(8*(ye/10))+movee];//顯示月十位
BUF[1]=table[(8*(ye%10))+movee];//月個位
BUF[2]=table1[16+movee];//顯示橫線
BUF[3]=table[(8*(rii/10))+movee];//顯示日十位
BUF[4]=table[(8*(rii%10))+movee];//顯示橫線
}
if(flag1==1)//為1就黑屏顯示
yixianhei();
for(ii=4;ii>=0;ii--)//循環5次將數發往顯示屏
song(~BUF[ii]);//送數
LINE=table2[line];//打開行線,即174HC154行線端
CLKR=1;//在74HC595處鎖存起來
CLKR=0;
CLKR=1;
delaya(800);
}
}
/******************************************************/
/*********星期調整界面顯示子程序(包括下半屏)********/
/******************************************************/
void xi(uchar xi)
{
uchar movee;
char ii;
for(line=8;line<16;line++)//掃描8次,即完成一個字的移動,line等于8,表示在下半屏顯示
{
if(flag1==0)//0.5秒顯示
{
movee=line-8;
BUF[0]=table1[16+movee];//顯示橫線"-"
BUF[1]=table1[16+movee];//顯示橫線"-"
BUF[2]=table[(8*(xi%10))+movee];//顯示出星期個位
BUF[3]=table1[16+movee];//顯示橫線"-"
BUF[4]=table1[16+movee];//顯示橫線"-"
}
if(flag1==1)
yixianhei();
for(ii=4;ii>=0;ii--)//循環5次將數發往顯示屏
song(~BUF[ii]);//送數
LINE=table2[line];//打開行線,即174HC154行線端
CLKR=1;//在74HC595處鎖存起來
CLKR=0;
CLKR=1;
delaya(800);
}
}
/******************************************************/
/***************鬧鐘時間調整顯示子程序*****************/
/******************************************************/
void xianniao(uchar shi,uchar ge,uchar z)
{
char ii;
for(line=0;line<8;line++)//掃描8次,即完成一個字的移動
{
if(flag1==0)//同樣0.5秒顯示時間
{
BUF[0]=table[(8*(shi/10))+line];//顯示小時十位
BUF[1]=table[(8*(shi%10))+line];
BUF[2]=table1[z*8+line];//顯示橫線
BUF[3]=table[(8*(ge/10))+line]; //顯示分鐘十位
BUF[4]=table[(8*(ge%10))+line];
}
if(flag1==1)//同樣0.5秒顯示黑屏
yixianhei();
for(ii=4;ii>=0;ii--)//循環5次將數發往顯示屏
song(~BUF[ii]);//送數
LINE=table2[line];//打開行線,即174HC154行線端
CLKR=1;//在74HC595處鎖存起來
CLKR=0;
CLKR=1;
delaya(800);
}
}
/******************************************************/
/***************按鍵按下后處理子程序*******************/
/******************************************************/
void skey()
{
if(shr!=0)//如果標志位shr不為0,則執行以下內容------如果按下了加按鍵則程序復位
{
if(key1==0)
{
delay(10);
if(key1==0)//如果加按鍵按下了,則全部復位
{
yin=0;//將按鍵計數器清0
shr=0;//標志位清0
lk=0;//顯示上半屏,此變量是全屏與半屏控制變量,當它為8時,就執行全屏,否則半屏
clockbiao=~clockbiao;
bbtsoud();//蜂鳴器響一聲子程序
while(!key1);//按鍵釋放
}
}
}
if(a!=0)//如果標志位不為0,則執行以下內容-------閃爍進入調整模式
xianshan(); //閃爍
if(b!=0)//如果標志位不為0,則執行以下內容,進行主時間小時調整
{
xianshan();//調用主時間顯示子程序
if(key1==0)
{
delay(10);
if(key1==0)
{
xianshan();
shi++;
if(shi==24)//小時等于24?
shi=0;//清0
write1302(0x8e,0x00);//去掉保護
write1302(0x84,((shi/10)<<4)|(shi%10));//時數據寫入
write1302(0x8e,0x80);//打開保護
readvalue=read1302(0x85);
shi=((readvalue&0xf0)>>4)*10+(readvalue&0x0f);//將小時轉換出來
while(!key1);
}
}
if(key2==0)//以下是處理主時間小時減部分
{
delay(10);
if(key2==0)
{
shi--;
if(shi==(0-1))
shi=23;
write1302(0x8e,0x00);//去掉保護
write1302(0x84,((shi/10)<<4)|(shi%10));//時數據寫入
write1302(0x8e,0x80);//打開保護
readvalue=read1302(0x85);
shi=((readvalue&0xf0)>>4)*10+(readvalue&0x0f);
while(!key2);
}
}
}
if(c!=0)//如果標志位不為0,則執行以下內容------以下是處理主時間分鐘調整部分
{
xianshan();
if(key1==0)//加分鐘部分
{
delay(10);
if(key1==0)
{
xianshan();//調用主時間顯示子程序
fen++;
if(fen==60)
fen=00;
write1302(0x8e,0x00);//去掉保護
write1302(0x82,((fen/10)<<4)|(fen%10));//分數據寫入
write1302(0x8e,0x80);//打開保護
readvalue=read1302(0x83);
fen=((readvalue&0xf0)>>4)*10+(readvalue&0x0f);//將它轉換出來
while(!key1);
}
}
if(key2==0)//減分鐘部分
{
delay(10);
if(key2==0)
{
xianshan();
fen--;
if(fen==(0-1))
fen=59;
write1302(0x8e,0x00);//去掉保護
write1302(0x82,((fen/10)<<4)|(fen%10));//分數據寫入
write1302(0x8e,0x80);//打開保護
readvalue=read1302(0x83);
fen=((readvalue&0xf0)>>4)*10+(readvalue&0x0f);
while(!key2);
}
}
}
if(d!=0)//如果標志位不為0,則執行以下內容-----調整年
{
xiannian(nian);//調用年顯示子程序
if(key1==0)//年時間加部分處理
{
delay(10);
if(key1==0)
{
xiannian(nian);
nian++;
if(nian==99)//年到了99嗎?
nian=0;
write1302(0x8e,0x00);//去掉保護
write1302(0x8c,((nian/10)<<4)|(nian%10));//年數據寫入
write1302(0x8e,0x80);//打開保護
readvalue=read1302(0x8d);
nian=((readvalue&0xf0)>>4)*10+(readvalue&0x0f);//年數據轉換
while(!key1);
}
}
if(key2==0)//年時間減部分處理
{
delay(10);
if(key2==0)
{
xiannian(nian);
nian--;
if(nian==(0-1))
nian=99;
write1302(0x8e,0x00);//去掉保護
write1302(0x8c,((nian/10)<<4)|(nian%10));//年數據寫入
write1302(0x8e,0x80);//打開保護
readvalue=read1302(0x8d);
nian=((readvalue&0xf0)>>4)*10+(readvalue&0x0f);//年數據轉換
while(!key2);
}
}
}
if(e!=0)//如果標志位不為0,則執行以下內容-----處理月
{
xianriyue(yue,ri);
if(key1==0)//月加部分處理
{
delay(10);
if(key1==0)
{
xianriyue(yue,ri);
yue++;
if(yue==13)
yue=1;
write1302(0x8e,0x00);//去掉保護
write1302(0x88,((yue/10)<<4)|(yue%10));//月數據寫入
write1302(0x8e,0x80);//打開保護
readvalue=read1302(0x89);
yue=((readvalue&0xf0)>>4)*10+(readvalue&0x0f);
while(!key1);
}
}
if(key2==0)//月減部分處理
{
delay(10);
if(key2==0)
{
xianriyue(yue,ri);
yue--;
if(yue==(1-1))
yue=12;
write1302(0x8e,0x00);//去掉保護
write1302(0x88,((yue/10)<<4)|(yue%10));//月數據寫入
write1302(0x8e,0x80);//打開保護
readvalue=read1302(0x89);
yue=((readvalue&0xf0)>>4)*10+(readvalue&0x0f);//月轉換
while(!key2);
}
}
}
if(f!=0)//如果標志位不為0,則執行以下內容-------調整日
{
xianriyue(yue,ri);
if(key1==0)//加日部分
{
delay(10);
if(key1==0)
{
xianriyue(yue,ri);
ri++;
if(ri==32)
ri=1;
write1302(0x8e,0x00);//去掉保護
write1302(0x86,((ri/10)<<4)|(ri%10));//日數據寫入
write1302(0x8e,0x80);//打開保護
readvalue=read1302(0x87);
ri=((readvalue&0xf0)>>4)*10+(readvalue&0x0f);
while(!key1);
}
}
if(key2==0)//減日部分
{
delay(10);
if(key2==0)
{
xianriyue(yue,ri);
ri--;
if(ri==(1-1))
ri=31;
write1302(0x8e,0x00);//去掉保護
write1302(0x86,((ri/10)<<4)|(ri%10));//日數據寫入
write1302(0x8e,0x80);//打開保護
readvalue=read1302(0x87);
ri=((readvalue&0xf0)>>4)*10+(readvalue&0x0f);
while(!key2);
}
}
}
if(g!=0)//如果標志位不為0,則執行以下內容-----星期調整部分
{
xi(xin);
if(key1==0)//星期加部分
{
delay(10);
if(key1==0)
{
xi(xin);
xin++;//將星期+1
if(xin==8)//如果星期到了8就清它清1
xin=1;//清1
write1302(0x8e,0x00);//去掉保護
write1302(0x8a,((xin/10)<<4)|(xin%10));//顯示星期天
write1302(0x8e,0x80);//打開保護
readvalue=read1302(0x8b);//讀星期
xin=((readvalue&0xf0)>>4)*10+(readvalue&0x0f);//將星期值還原
while(!key1);
}
}
if(key2==0)//星期減部分
{
delay(10);
if(key2==0)
{
xi(xin);
xin--;//減1
if(xin==(1-1))//如果到了(1-1)就給它7,因為星期只1---7
xin=7;//將它給7
write1302(0x8e,0x00);//去掉保護
write1302(0x8a,((xin/10)<<4)|(xin%10));//顯示星期天
write1302(0x8e,0x80);//打開保護
readvalue=read1302(0x8b);
xin=((readvalue&0xf0)>>4)*10+(readvalue&0x0f);//讀星期值
while(!key2);
}
}
}
if(h!=0)////如果標志位不為0,則執行以下內容------------以下是鬧鐘小時調整部分
{
xianniao(shin,fenn,2);//調整鬧鐘小時與分鐘顯示子程序
if(key1==0)//鬧鐘小時加處理
{
delay(10);
if(key1==0)
{
xianniao(shin,fenn,2);
shin++;//將星期+1
if(shin==24)//如果星期到了8就清它清1
shin=0;//清1
while(!key1);
}
}
if(key2==0)//鬧鐘小時減處理
{
delay(10);
if(key2==0)
{
xianniao(shin,fenn,2);
shin--;
if(shin==(0-1))
shin=23;
while(!key2);
}
}
}
if(i!=0)//如果標志位不為0,則執行以下內容----------鬧鐘分鐘調整
{
xianniao(shin,fenn,2);
if(key1==0)//鬧鐘分鐘加處理
{
delay(10);
if(key1==0)
{
xianniao(shin,fenn,2);
fenn++;//將星期+1
if(fenn==60)//如果星期到了8就清它清1
fenn=0;//清1
while(!key1);
}
}
if(key2==0)//鬧鐘分鐘減處理
{
delay(10);
if(key2==0)
{
xianniao(shin,fenn,2);
fenn--;
if(fenn==(0-1))
fenn=59;
while(!key2);
}
}
}
}
/******************************************************/
/*******************響鬧子程序*************************/
/******************************************************/
void xiangniao()
{
bit clock;//定義一個標志位
if(clockbiao==0)//鬧鐘總標志為0時才可以執行鬧鐘處理程序
{
if(clock==0)//如果標志位為0,就執行下面內容
{
if(shin==shi)//主時間小時與鬧鐘小時相等嗎?
{
if(fenn==fen)//主時間分鐘與鬧鐘分鐘相等嗎?
bbtsoud();//相等了就執行鬧鐘響一聲子程序,即小時與分鐘都相等了就執行鬧鈴
}
}
if(fenn!=fen)//如果分鐘不等
clock=0;//將標志位清0,以便下次再響鈴
if(key1==0)//判斷加"+"按鍵有沒有被按下,如果按下了,就讓鬧鈴停止響
{
delay(10);
if(key1==0)
{
clock=1;//將標志位清0,讓鬧鐘在響鈴時立馬停下來
while(!key1);
}
}
}
if(key2==0)//如果減按鍵按下了,則則關閉鬧鈴全部功能
{
delay(10);
if(key2==0)//如果加按鍵按下了,則全部復位
{
clockbiao=~clockbiao;
bbtsoud();//蜂鳴器響一聲子程序
while(!key2);//按鍵釋放
}
}
}
/******************************************************/
/******************************************************/
/**********主程序(包括主顯示/鬧鐘/按鍵處理)************/
/******************************************************/
/******************************************************/
void main()
{
init1302();
TMOD=0X11;//寄存器工作方式
EA=1;//開總中斷
TR0=1;//開定時器
ET0=1;//開定時器中斷
TH0=(65536-20000)/256;//賦值給高位
TL0=(65536-20000)%256;//賦值給低位
TR1=1;//開定時器
ET1=1;//開定時器中斷
TH1=(65536-50000)/256;//賦值給高位
TL1=(65536-50000)%256;//賦值給低位
while(1)
{
if(flag==0)//如果標志位為0,就讓它執行主程序,不讓它讀按鍵處理部分,省資源
{
value();//調用DS1302時間轉換子程序
xianzhu(nian,yue,ri,xin);//調用主顯示
xiangniao();//調用響鬧子程序
}
skey();//調用按鍵處理子程序
}
}
/******************************************************/
/*******************定時中斷0子程序********************/
/******************************************************/
void zhong() interrupt 3
{
uchar ding;
TH1=(65536-50000)/256;
TL1=(65536-50000)%256;
ding++;
if(ding>=10)//模擬普通鬧鐘小數閃爍處理部分
{
ding=0;
dian=~dian;//0.5秒閃一次,它不參與具體計時,具體計時只是DS1302內部
}
}
/******************************************************/
/*******************定時中斷1子程序********************/
/******************************************************/
void zhong1() interrupt 1//T1中斷服務程序
{
uchar ding1,ding2;
TH0=(65536-10000)/256;//賦值給高位
TL0=(65536-10000)%256;//賦值給低位
ding1++;
ding2++;
if(ding2>=50)//進入調整模式時閃爍標志位處理
{
ding2=0;
flag1=~flag1;
}
switch(yin)//以下是主功能按鍵處理子程序
{
case 0:if(ding1>=250)//長按功能按鍵進入調整模式,否則怕誤按-------------進入查看年月日功能
{
ding1=0;//將定時器清0
if(key==0)
{
delay(100);
if(key==0)
{
yin++;//將標志位加1
lk=8;//些句是調用"年月日星期"顯示的關鍵一步,即打開下屏顯示
shr=1;//將標志位置1
bbtsoud();//蜂鳴器響一聲
while(!key);//按鍵釋放
}
}
}
break;
case 1:if(key==0)//-----------------------------進入調整模式閃爍功能
{
delay(100);
if(key==0)
{
yin++;//以便進入一個功能
a=1;//標志位置1,以便進入按鍵功能
shr=0;//將上次標志位清0,以免與現在的鍵值產生沖突
lk=0;//將下半屏清掉
flag=1;//將主程序中的標志位置1
bbtsoud();//蜂鳴器響一聲
TR1=0;//將定時器關掉
dian=0;//將主時間中的兩位小數點標志位打開
write1302(0x8e,0x00);//去掉DS1302保護
write1302(0x80,0x80);//當它等于0X80時,讓DS1302時間停下來,以便調整
write1302(0x8e,0x80);//讓DS1302保護
while(!key);
}
}
break;
case 2: if(key==0)//-----------------------------進入主時間小時調整功能
{
delay(100);
if(key==0)
{
yin++;//以下便進行下一功能
b=1;//標志位置1
a=0;
bbtsoud();
while(!key);
}
}
break;
case 3: if(key==0)//---------------------------進入主時間分鐘時調整功能
{
delay(100);
if(key==0)
{
yin++;
b=0;
c=1;
bbtsoud();
while(!key);
}
}
break;
case 4: if(key==0)//---------------------------------進入日期年調整功能
{
delay(100);
if(key==0)
{
yin++;
c=0;
d=1;
bbtsoud();
while(!key);
}
}
break;
case 5:if(key==0)//-----------------------------------進入日期月調整功能
{
delay(100);
if(key==0)
{
yin++;
d=0;
e=1;
bbtsoud();
while(!key);
}
}
break;
case 6: if(key==0)//-----------------------------------進入日期日調整功能
{
delay(100);
if(key==0)
{
yin++;
e=0;
f=1;
bbtsoud();
while(!key);
}
}
break;
case 7:if(key==0)//---------------------------------進入日期星期調整功能
{
delay(100);
if(key==0)
{
yin++;
f=0;
g=1;
bbtsoud();
while(!key);
}
}
break;
case 8: if(key==0)//------------------------------進入鬧鐘小時調整功能
{
delay(100);
if(key==0)
{
yin++;
g=0;
h=1;
bbtsoud();
while(!key);
}
}
break;
case 9:if(key==0)//------------------------------進入鬧鐘分鐘調整功能
{
delay(100);
if(key==0)
{
yin++;
h=0;
i=1;
bbtsoud();
while(!key);
}
}
break;
case 10:if(key==0)//----------------------將系統全部復位,即回到主程序
{
delay(100);
if(key==0)
{
yin=0;//總計數器復位為0
i=0;//上次功能標志位清0
flag=0;//主程序標志位清0
TR1=1;//打開定時器
write1302(0x8e,0x00);//去掉DS1302保護
write1302(0x80,0x00);//當它等于0X00時,讓時間就開始走 即0X00就讓時間開始走,0X80讓時停
write1302(0x8e,0x80);//讓時間停下來
bbtsoud();
while(!key);
}
}
break;
}
}