/*********************************************************************************
描述:
1、8位共陰數碼管顯示實時時鐘88-88-88樣式,兩‘-’1秒閃爍1次
2、STC89C52 @ 11.0592MHz晶振,兩片74HC573做段選、位選
3、調時的時候,key2鍵短按加1,長按連加;key3鍵短按減一,長按連減;按鍵消抖不用delay。
4、在調時狀態超過3秒再沒有按鍵按下,回到走時狀態
5、加備用電池,掉電走時 ,仿真 實物都通過。
**********************************************************************************/
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
/***********寫時分秒地址************/
#define write_shi 0x84
#define write_fen 0x82
#define write_miao 0x80
#define write_ram 0xc0
/***********讀時分秒地址************/
#define read_shi 0x85
#define read_fen 0x83
#define read_miao 0x81
#define read_ram 0xc1
sbit sclk = P1^0; //控制數據時鐘
sbit dio = P1^1; //數據口
sbit ce = P1^2; //使能端、復位端
sbit wela = P2^7; //位選
sbit dula = P2^6; //段選
sbit key1=P3^0; //按鍵 選擇
sbit key2=P3^1; //按鍵 加
sbit key3=P3^2; //按鍵 減
uint ms; //調時自動走時計時變量
uchar knum=0,snum,fnum,ss; //定義 key1按下次數變量,時分調時閃爍變量,兩‘-’閃爍計時變量
char shi,fen,miao; //定義時分秒變量
bit f1,f2,f3; //定義自動走時標志
// 0 1 2 3 4 5 6 7 8 9 不顯 -
uchar code d[]={ 0x3F,0x06,0x5B,0x4F,0x66, 0x6D,0x7D,0x07,0x7F,0x6F,0x00,0x40}; //共陰不帶小數點段碼
void delay(uint z) //ms延時函數
{
uint x,y;
for(x=z;x>0;x--)
for(y=120;y>0;y--);
}
void t0_init() //定時器初始化函數
{
TMOD |= 0X11; //定時器0、1都為模式1, 16位計數模式
TH0=(65536-46080)/256; //50ms初值 @11.0529MHz
TL0=(65536-46080)%256;
TH1=(65536-921)/256; //1ms初值 @11.0529MHz
TL1=(65536-921)%256;
EA=1; //開總中斷
ET0=1; //開定時器T0中斷
TR0=1; //啟動T0
ET1=1; //開定時器T1中斷
// TR1=1;
}
void display(uchar shi,uchar fen,uchar miao) //顯示函數
{
if(knum==0) //正常走時
{
snum=30;
fnum=30;
}
if(knum==1) //調時,分位閃爍
{
fnum++;
snum=30;
}
if(knum==2) //調時,時位閃爍
{
snum++;
fnum=30;
}
if(snum>=30)
{
if((shi/10)<1) //如果小時十位小于1,
{
wela=1;
P0=0xfe; //第1位
wela=0;
dula = 1;
P0=d[10]; //共陰數碼管段碼送全0 小時十位就不顯示
dula = 0;
}
else
{
wela=1;
P0=0xfe; //第1位
wela=0;
dula=1;
P0=d[shi/10];
dula=0;
P0=0xff;
delay(2);
}
wela=1;
P0=0xfd; //第2位
wela=0;
dula=1;
P0=d[shi%10];
dula=0;
P0=0xff;
delay(2);
if(snum==60)
snum=0;
}
// if(miao%2==0) //if(miao%2==0) 1秒閃爍1次
if(ss>=10) // 這里寫為ss>=10,閃爍頻率可調
{
wela=1;
P0=0xfb; //第3位
wela=0;
dula=1;
P0=d[11]; //第三位數碼管顯示“— ”
dula=0;
P0=0xff;
delay(2);
}
else
{
wela=1;
P0=0xfb; //第3位
wela=0;
dula=1;
P0=d[10]; //第三位數碼管不顯示
dula=0;
P0=0xff;
delay(2);
}
if(fnum>=30)
{
wela=1;
P0=0xf7; //第4位
wela=0;
dula=1;
P0=d[fen/10];
dula=0;
P0=0xff;
delay(2);
wela=1;
P0=0xef; //第5位
wela=0;
dula=1;
P0=d[fen%10];
dula=0;
P0=0xff;
delay(2);
if(fnum==60)
fnum=0;
}
// if(miao%2==0) //if(miao%2==0) 1秒閃爍1次
if(ss>=10) //if(ss>=10)閃爍頻率可調
{
wela=1;
P0=0xdf; //第6位
wela=0;
dula=1;
P0=d[11]; //第六位數碼管顯示“— ”
dula=0;
P0=0xff;
delay(2);
}
else
{
wela=1;
P0=0xdf; //第6位
wela=0;
dula=1;
P0=d[10]; //第六位數碼管不顯示
dula=0;
P0=0xff;
delay(2);
}
wela=1;
P0=0xbf; //第7位
wela=0;
dula=1;
P0=d[miao/10]; //秒十位
dula=0;
P0=0xff;
delay(2);
wela=1;
P0=0x7f; //第8位
wela=0;
dula=1;
P0=d[miao%10]; //秒個位
dula=0;
P0=0xff;
delay(2);
}
void write_1302(uchar add,dat)//寫1302函數
{
uchar i,temp;
temp=add;
ce=0;
_nop_();
sclk=0;
_nop_();
ce=1;
_nop_();
for(i=0;i<8;i++)
{
sclk=0;
_nop_();
if((temp&0x01)==0x01)
dio=1;
else
dio=0;
temp>>=1;
sclk=1;
_nop_();
}
temp=dat;
for(i=0;i<8;i++)
{
sclk=0;
_nop_();
if((temp&0x01)==0x01)
dio=1;
else
dio=0;
temp>>=1;
sclk=1;
_nop_();
}
ce=0;
sclk=0;
}
uchar read_1302(uchar add) //讀1302函數
{
uchar dat,dat1,i,temp;
temp=add;
ce=0;
_nop_();
sclk=0;
_nop_();
ce=1;
for(i=0;i<8;i++)
{
sclk=0;
_nop_();
if((temp&0x01)==0x01)
dio=1;
else
dio=0;
temp>>=1;
sclk=1;
_nop_();
}
for(i=0;i<8;i++)
{
sclk=0;
_nop_();
if(dio)
dat|=0x80;
if(i<7)
dat>>=1;
sclk=1;
}
dat1=dat/16;
dat=dat%16;
dat=dat1*10+dat;
ce=0;
sclk=0;
return dat;
}
void init_1302() //自動初始化函數
{
if(read_1302(read_ram) != 0xaa) //如果初始化標志RAM的值不是0xaa,才初始化
{
write_1302(0x8e,0x00); //保護取消,可以進行寫操作
write_1302(write_miao,0x57); //寫秒57
write_1302(write_fen,0x55); //寫分55
write_1302(write_shi,0x15); //寫時15
write_1302(write_ram,0xaa); //寫入初始化標志RAM(第00個RAM位置)
write_1302(0x8e,0x80); //保護啟動,不能進行寫操作
}
}
void read_sf() //讀時分秒并顯示
{
shi=read_1302(read_shi);
fen=read_1302(read_fen);
miao=read_1302(read_miao);
display(shi,fen,miao);
}
void keyscan() //按鍵掃描函數
{
static uchar count; //這里要定義為靜態變量
if(key1==0) //按鍵按下
{
TR1=1;
count++; //消抖,也是連加一次的間隔時間
f1=1;
if(key1==0 && count>10)//按鍵按下,計數變量加到12,
{
ms=0; //自啟動計時變量清零
while(!key1) //這里不需要連加,就加一句松手檢測
display(shi,fen,miao);
count=0;
TR0=0; //關閉T0定時器,數碼管兩‘-’停止閃爍
knum++;
if(knum==1)
{
write_1302(0x8e,0x00); //DS1302寫保護取消
write_1302(write_miao,0x80); //寫秒80,時鐘停止走時;
}
if(knum==3) //調時完畢,時鐘啟動
{
TR0=1; //啟動T0定時器,數碼管兩‘-’開始閃爍
knum=0;
write_1302(write_miao,0x00); //寫秒0,時鐘啟動走時
write_1302(0x8e,0x80); //保護啟動
}
}
}
if(knum==1) //分鐘調節
{
if(key2==0) //加
{
f2=1;
count++;
if(key2==0 && count>12)//短按加1,長按連加
{
ms=0; //自啟動計時變量清零
count=0;
fen++;
fen=fen/10*16+fen%10; //轉為16進制
if(fen==0x60)
fen=0x00;
write_1302(write_fen,fen); //寫入1302
}
}
if(key3==0) //減
{
f3=1;
count++;
if(key3==0 && count>12)//短按減1,長按連減
{
ms=0; //自啟動計時變量清零
count=0;
fen--;
fen=fen/10*16+fen%10; //轉為16進制
if(fen==-1)
fen=0x59;
write_1302(write_fen,fen);
}
}
}
if(knum==2) //小時調節
{
if(key2==0)
{
f2=1;
count++;
if(key2==0 && count>12 )//短按加1,長按連加
{
ms=0; //自啟動計時變量清零
count=0;
shi++;
shi=shi/10*16+shi%10;//轉為16進制
if(shi==0x24)
shi=0x00;
write_1302(write_shi,shi);
}
}
if(key3==0)
{
f3=1;
count++;
if(key3==0 && count>12 )//短按減1,長按連減
{
ms=0; //自啟動計時變量清零
count=0;
shi--;
shi=shi/10*16+shi%10;//轉為16進制
if(shi==-1)
shi=0x23;
write_1302(write_shi,shi);
}
}
}
/*按鍵超過3秒沒有動作,時鐘回到走時狀態*/
if(f1==1 || f2==1 || f3==1)
{
if(ms>3000) //時間超過3秒
{
TR1=0; //關閉T1
ms=0; //自啟動計時變量清零
knum=0; //key1按鍵次數清零
TR0=1; //啟動T0,數碼管兩‘-’開始閃爍
write_1302(write_miao,0x00); //寫秒0,時鐘啟動走時
write_1302(0x8e,0x80); //保護啟動
}
}
}
/*主函數*/
void main()
{// uchar i;
t0_init();
init_1302();
while(1)
{
// for(i=0;i<4;i++)
// display(shi,fen,miao);
read_sf();
keyscan();
}
}
/*中斷函數*/
void temer1() interrupt 1
{
TH0=(65536-46080)/256;
TL0=(65536-46080)%256;
ss++;
if(ss==20)
ss=0;
}
void temer2() interrupt 3
{
TH1=(65536-921)/256;
TL1=(65536-921)%256;
ms++;
}
|