程序重新優化了一下,原來附件里面的程序有bug,就是第一次程序燒進去,要按設置鍵3次時鐘才會走時,下面的程序已修改好了- /*********************************************************************************
- 描述:
- 1、8位共陰數碼管顯示實時時鐘88-88-88樣式,兩‘-’1秒閃爍1次
- 2、STC89C52 @ 11.0592MHz晶振,兩片74HC573做段選、位選
- 3、按key1鍵選擇調節位,按第一次,分位閃爍,按第2次,時位閃爍,按第3次,回到正常走時;
- 調時的時候,key2鍵短按加1,長按連加;key3鍵短按減一,長按連減;按鍵消抖不用delay。
- 4、在調時狀態超過3秒再沒有按鍵按下,回到正常走時狀態(這功能不太實用,可以取消)
- 5、加備用電池,掉電走時
- 6、對時的時候先調好時、分,分鐘要比參考時間的分鐘加1分,
- 再看參考時間的秒數到了59再按KEY1按鍵的第3次,這樣對時可以很準的。
- 仿真 實物都通過。
- **********************************************************************************/
- #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 TSCLK = P1^0;//時鐘線 接到P10上用杜邦線
- sbit TIO = P1^1;//數據線,接到P11上
- sbit TRST = P1^2;//使能端,接到P12上
- 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;
- P0=0x00;
- dula = 1;
- P0=d[10]; //共陰數碼管段碼送全0 小時十位就不顯示
- dula = 0;
- }
-
- else
-
- if((shi/10)>0)
- {
- wela=1;
- P0=0xfe; //第1位
- wela=0;
- P0=0x00;
- dula=1;
- P0=d[shi/10];
- dula=0;
- P0=0xff;
- delay(3);
- }
- wela=1;
- P0=0xfd; //第2位
- wela=0;
- P0=0x00;
- dula=1;
- P0=d[shi%10];
- dula=0;
- P0=0xff;
- delay(3);
-
- 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;
- P0=0x00;
- dula=1;
- P0=d[11]; //第三位數碼管顯示“— ”
- dula=0;
- P0=0xff;
- delay(3);
- }
-
- else
- {
- wela=1;
- P0=0xfb; //第3位
- wela=0;
- P0=0x00;
- dula=1;
- P0=d[10]; //第三位數碼管不顯示
- dula=0;
- P0=0xff;
- delay(3);
- }
-
-
- if(fnum>=30)
- {
- wela=1;
- P0=0xf7; //第4位
- wela=0;
- P0=0x00;
- dula=1;
- P0=d[fen/10];
- dula=0;
- P0=0xff;
- delay(3);
-
-
- wela=1;
- P0=0xef; //第5位
- wela=0;
- P0=0x00;
- dula=1;
- P0=d[fen%10];
- dula=0;
- P0=0xff;
- delay(3);
-
-
- 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;
- P0=0x00;
- dula=1;
- P0=d[11]; //第六位數碼管顯示“— ”
- dula=0;
- P0=0xff;
- delay(3);
- }
-
- else
- {
- wela=1;
- P0=0xdf; //第6位
- wela=0;
- P0=0x00;
- dula=1;
- P0=d[10]; //第六位數碼管不顯示
- dula=0;
- delay(3);
- }
-
-
- wela=1;
- P0=0xbf; //第7位
- wela=0;
- P0=0x00;
- dula=1;
- P0=d[miao/10]; //秒十位
- dula=0;
- P0=0xff;
- delay(3);
-
-
- wela=1;
- P0=0x7f; //第8位
- wela=0;
- P0=0x00;
- dula=1;
- P0=d[miao%10]; //秒個位
- dula=0;
- P0=0xff;
- delay(3);
- }
- //寫DS1302數據
- void Write_DS1302_DAT(uchar cmd, uchar dat)
- {
- uchar i;
- TRST = 0; //拉低使能端
- TSCLK = 0;//拉低數據總線
- TRST = 1; //拉高使能端,產生上升沿開始寫數據
- for(i = 0; i < 8; i++)//每次寫1位,寫8次
- {
- TSCLK = 0; //拉低時鐘總線
- TIO = cmd & 0x01; //寫1位數據,從最低位開始寫
- TSCLK = 1; //拉高時鐘總線,產生上升沿數據被DS1302讀走
- cmd >>=1; //右移一位
- }
- for(i = 0; i < 8; i++)//每次寫1位,寫8次
- {
- TSCLK = 0; //拉低時鐘總線
- TIO = dat & 0x01; //寫1位數據,從最低位開始寫
- TSCLK = 1; //拉高時鐘總線,產生上升沿數據被DS1302讀走
- dat >>= 1; //右移一位
- }
- }
- //讀DS1302數據
- uchar Read_DS1302_DAT(uchar cmd)
- {
- uchar i, dat;
- TRST = 0; //拉低使能端
- TSCLK = 0; //拉低數據總線
- TRST = 1; //拉高使能端,產生上升沿開始寫數據
- for(i = 0; i < 8; i++)//每次寫1位,寫8次
- {
- TSCLK = 0; //拉低時鐘總線
- TIO = cmd & 0x01;//寫1位數據,從最低位開始寫
- TSCLK = 1; //拉高時鐘總線,產生上升沿數據被DS1302讀走
- cmd >>=1; //右移一位
- }
- for(i = 0; i < 8; i++)//每次讀1位,讀8次
- {
- TSCLK = 0; //拉低時鐘總線,產生下降沿,DS1302把數據放到TIO上
- dat >>= 1; //右移一位
- if(TIO) dat |= 0x80;//讀取數據,從最低位開始
- TSCLK = 1; //拉高時鐘總線,以備下一次產生下降沿
- }
- return dat; //返回讀出數據
- }
- //數據轉BCD碼
- uchar Dat_Chg_BCD(uchar dat)
- {
- uchar dat1, dat2;
- dat1 = dat / 10;
- dat2 = dat % 10;
- dat2 = dat2 + dat1 * 16;
- return dat2;
- }
- //BCD碼轉換為數據
- uchar BCD_Chg_Dat(uchar dat)
- {
- uchar dat1, dat2;
- dat1 = dat / 16;
- dat2 = dat % 16;
- dat2 = dat2 + dat1 * 10;
- return dat2;
- }
- void init_1302() //初始化函數 設置時間
- { //加備用電池,掉電走時
- if((Read_DS1302_DAT(0x81)& 0x80) != 0) //讀出秒數據,再跟80h(0x80)與運算看結果,結果是0則不需要初始化1302;是80h就要初始化!
- {
- Write_DS1302_DAT(0x8e, 0);//清除寫保護
- Write_DS1302_DAT(write_miao, Dat_Chg_BCD(58));//58秒(并且進行BCD碼轉換)
- Write_DS1302_DAT(write_fen, Dat_Chg_BCD(10));//10分
- Write_DS1302_DAT(write_shi, Dat_Chg_BCD(9));//9時
- Write_DS1302_DAT(0x8e, 0x80);//開寫保護
- }
- }
- void read_sf()
- {
- miao = BCD_Chg_Dat(Read_DS1302_DAT(read_miao));//讀秒寄存器(并且進行BCD碼轉換)
- fen = BCD_Chg_Dat(Read_DS1302_DAT(read_fen));//讀分寄存器
- shi = BCD_Chg_Dat(Read_DS1302_DAT(read_shi));//讀時寄存器
- 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_DS1302_DAT(0x8e,0x00); //DS1302寫保護取消
- Write_DS1302_DAT(write_miao,0x80); //寫秒80,時鐘停止走時;
- }
-
- if(knum==3) //調時完畢,時鐘啟動
- {
- TR0=1; //啟動T0定時器,數碼管兩‘-’開始閃爍
- knum=0;
- Write_DS1302_DAT(write_miao,0x00); //寫秒0,時鐘啟動走時
- Write_DS1302_DAT(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_DS1302_DAT(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_DS1302_DAT(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_DS1302_DAT(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_DS1302_DAT(write_shi,shi);
- }
- }
- }
- /*按鍵超過3秒沒有動作,時鐘回到走時狀態*///這段加上,秒調不精確,因為超過3秒沒有按鍵按下,秒就清0開始走時了。
- /* if(f1==1 || f2==1 || f3==1)
- {
- if(ms>3000) //時間超過3秒
- {
- TR1=0; //關閉T1
- ms=0; //自啟動計時變量清零
- knum=0; //key1按鍵次數清零
- TR0=1; //啟動T0,數碼管兩‘-’開始閃爍
- Write_DS1302_DAT(write_miao,0x00); //寫秒0,時鐘啟動走時
- Write_DS1302_DAT(0x8e,0x80); //保護啟動
- }
-
- } */
- }
- /*主函數*/
- void main()
- {
- t0_init();
- init_1302();
- while(1)
- {
- 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++;
- }
復制代碼 |