STC89C52單片機+DS1302+數碼管顯示時鐘及按鍵時+整點報時功能
資料含有程序源代碼+及仿真原理圖
仿真軟件運行和實際焊接電路運行都通過驗證。
//注意事項://:仿真時請將程序char H=0,L=1,開發板下載試驗請將變量char H=1 ,L=0;
//:請屏蔽此 DS1302初始化 //init_1302(); 函數。
void main()
{
t0_init();
t1_init();
//init_1302(); //仿真時如你需要顯示當前實時系統時間,請屏蔽此函數。
while(1)
{
read_sf();
ExecuteKeyNum();
}
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
51hei.gif (148.18 KB, 下載次數: 57)
下載附件
2021-11-13 17:45 上傳
說明2.jpg (217.41 KB, 下載次數: 50)
下載附件
2021-11-13 10:01 上傳
說明.jpg (136.46 KB, 下載次數: 37)
下載附件
2021-11-13 09:57 上傳
1》按下設置啟動鍵:分鐘閃爍進入分鐘調時,再次按下小時閃爍進入小時調時
2》按下參數加或參數減按鈕:進行小時后分鐘的時間設置
注意:仿真時請將程序里WELA的變量H=0 L=1,開發板試驗請將變量H=1 L=0;
單片機源程序如下:
- /*********************************************************************************
- 描述: 8位共陰數碼管時鐘,顯示88-88-88樣式,正常走時的時候,兩個“-”0.5秒閃爍一次;
- 調時:按KEY1按鍵第1次分鐘位閃爍,再按KEY2一次分鐘加1,按KEY3一次分鐘減1,長按連加連減;
- 按KEY1按鍵第2次小時位閃爍,再按KEY2一次小時加1,按KEY3一次小時減1,長按連加連減;
- 按KEY1按鍵第3次,秒從零開始累加,時鐘回到正常走時;
- 對時的時候先調好時、分,分鐘要比參考時間的分鐘加1分,
- 再看參考時間的秒數到了59再按KEY1按鍵的第3次,這樣對時可以很準的
- 仿真 實物都通過. 11.0592MHz晶振,STC89C52RC,兩個74HC573鎖存器做位選、段選
- **********************************************************************************/
- #include<reg52.h>
- #include<intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- sbit sclk = P2^4; //1302時鐘端口
- sbit dio = P2^5; //1302數據端口
- sbit ce = P2^6;
- //1302使能
- sbit wela1 = P2^0; //位選
- sbit wela2 = P2^1; //位選
- sbit wela3 = P2^2;
- sbit wela4 = P2^3;
- sbit buzzer=P3^7;
- sbit KEY1=P3^0; //按鍵 設置/確認
- sbit KEY2=P3^1; //按鍵 加
- sbit KEY3=P3^2; //按鍵 減
- uchar snum,fnum;
- char shi,fen,miao,shi_alarm=6;
- uchar ss,mm;
- char H=0,L=1; //用軟件仿真時關閉數碼管H全部改為0,單片機下載H改為1.
- char FunctionKeyNum=0; //功能鍵鍵值
- char FuncTempNum=0; //功能鍵臨時鍵值
- typedef enum KeyState{StateInit,StateAffirm,StateSingle,StateRepeat}; //鍵值狀態值
- /***********寫時DS1302地址************/
- #define write_year 0x8c //寫年的地址
- #define write_moon 0x88 //寫月的地址
- #define write_week 0x8a //寫周的地址
- #define write_day 0x86 //寫日的地址
- #define write_shi 0x84 //寫時的地址
- #define write_fen 0x82 //寫分的地址
- #define write_miao 0x80 //寫秒的地址
- #define write_ram 0xc0 ////RAM的基地址
- /***********讀時DS1302地址************/
- #define read_year 0x8d //讀年的地址
- #define read_moon 0x89 //讀月的地址
- #define read_week 0x8b //讀周的地址
- #define read_day 0x87 //讀日的地址
- #define read_shi 0x85 //讀時的地址
- #define read_fen 0x83 //讀分的地址
- #define read_miao 0x81 //讀秒的地址
- #define read_ram 0xc1 //RAM的基地址
- // 0 1 2 3 4 5 6 7 8 9
- //uchar d[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //共陰不帶小數點
- //uchar d[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef}; // 共陰帶小數點
- uchar d[]={0Xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //共陽極
- uchar dd[]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10}; //共陽極帶小數點
- void Time_alarm(); //整點報時子程序
- void delayms(uint z)
- {
- uint x,y;
- for(x=z;x>0;x--)
- for(y=120;y>0;y--);
- }
- /*
- void buzzer1()
- {
- uint i;
- for(i=0;i<10;i++)
- {
- buzzer=0;
- delayms(500);
- buzzer=1;
- delayms(500);
- }
- }
- */
- void buzzer2() //發聲子程序
- {
-
- uint t,tt;
- for(t=0;t<50;t++) //45為蜂鳴器發聲頻率
- {
- buzzer=!buzzer;
- for(tt=0;tt<50;tt++); //45為蜂鳴器發聲頻率
- }
- }
- void t0_init() //定時50ms一個中斷
- {
-
- TMOD |= 0X01;
- TH0 = (65536-46080)/256;
- TL0 = (65536-46080)%256;
- EA = 1;
- ET0 = 1;
- TR0 = 1;
- }
- void t1_init()
- {
- TMOD |= 0x10;
- TH1 = 0x500;
- TL1 = 0x00;
- TR1 = 1;
- }
- void temer0() interrupt 1
- {
- TH0=(65536-46080)/256;
- TL0=(65536-46080)%256;
- ss++;
- mm++;
- if(ss==22)
- {
- ss=0;
- }
- if(mm==10)
- {
- mm=0;
- Time_alarm();
- }
- }
-
-
- void Display(uchar shi,uchar fen) //顯示函數
- {
- if(FunctionKeyNum==0)
- {
- snum=30;
- fnum=30;
- }
-
- if(FunctionKeyNum==1)
- {
- fnum++;
- snum=30;
- }
-
- if(FunctionKeyNum==2)
- {
- snum++;
- fnum=30;
- }
-
- wela1=H; //關閉所有數碼管
- wela2=H; //用軟件仿真時關閉數碼管H全部改為0,單片機下載H改為1.
- wela3=H; //用軟件仿真時關閉數碼管H全部改為0,單片機下載H改為1.
- wela4=H;
-
- if(snum>=30)
- {
- if((shi/10)<1) //如果小時十位小于1,
- {
- wela1=L; // 小時十位就不顯示
- P0=d[0]; // 小時十位就顯示"0"
- delayms(2);
- P0=0xff;
- wela1=H;
-
- }
-
- else
- {
- wela1=L;
- P0=d[shi/10];
- delayms(2);
- P0=0xff;
- wela1=H;
- }
-
- if(miao%2==0) //if(miao%2==0) 1秒閃爍1次
- // if(ss>=20) // 這里寫為ss>=10,閃爍頻率可調
- {
- wela2=L;
- P0=dd[shi%10];
- delayms(2);
- P0=0xff;
- wela2=H;
- }
-
- else
- {
- wela2=L;
- P0=d[shi%10];
- delayms(2);
- P0=0xff;
- wela2=H;
- }
- if(snum==60)
- snum=0;
- }
-
- // if(miao%2==0) //if(miao%2==0) 1秒閃爍1次
- if(ss>=20) // 這里寫為ss>=10,閃爍頻率可調
- {
- wela2=L;
- P0=d[shi%10];
- delayms(2);
- P0=0xff;
- wela2=H;
- }
-
- if(fnum>=30)
- {
- wela3=L;
- P0=d[fen/10];
- delayms(2);
- P0=0xff;
- wela3=H;
-
- wela4=L;
- P0=d[fen%10];
- delayms(2);
- P0=0xff;
- wela4=H;
-
-
- if(fnum==60)
- fnum=0;
- }
- }
- 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() //初始化函數 設置時間
- {
- write_1302(0x8e,0x00); //保護取消,可以進行寫操作
- write_1302(write_year,0x20);
- write_1302(write_moon,0x12); //寫入時修改月
- write_1302(write_week,0x30); //寫入時修改星期
- write_1302(write_day,0x04); //寫時修改日期
- write_1302(write_miao,0x00);
- write_1302(write_fen,0x30);
- write_1302(write_shi,0x10);
- 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);
- }
- void KeyScan(void)
- {
- static uchar KeyStateTemp1 = 0; //按鍵狀態臨時存儲值1
- static uchar KeyStateTemp2 = 0; //按鍵狀態臨時存儲值2
- static uchar KeyStateTemp3 = 0; //按鍵狀態臨時存儲值3
- static uchar KeyTime = 0; //按鍵延時時間
- bit KeyPressTemp1; //按鍵是否按下存儲值1
- bit KeyPressTemp2; //按鍵是否按下存儲值2
- bit KeyPressTemp3; //按鍵是否按下存儲值3
- KeyPressTemp1 = KEY1; //讀取IO口的鍵值
- switch(KeyStateTemp1)
- {
- case StateInit:
- if(!KeyPressTemp1) //KEY1按下
- KeyStateTemp1 = StateAffirm; //按鍵狀態切換到確認態
- break;
- case StateAffirm: //確認狀態
- if(!KeyPressTemp1) //按鍵還在按下
- {
- KeyTime = 0;
- KeyStateTemp1 = StateSingle; //按鍵狀態切換到單擊狀態
- }
- else KeyStateTemp1 = StateInit; //否則按鍵抬起,回到初始態
- break;
-
- case StateSingle: //單擊
- if(KeyPressTemp1)
- {
- KeyStateTemp1 = StateInit; //按鍵釋放
- FuncTempNum++; //鍵值加1
- if(FuncTempNum>3)
- FuncTempNum = 0;
- }
- else if(++KeyTime>100)
- {
- KeyPressTemp1 = StateRepeat;
- KeyTime = 0;
- }
- break;
-
- case StateRepeat: //連發
- if(KeyPressTemp1)
- KeyStateTemp1 = StateInit;
- else
- {
- if(++KeyTime > 10)
- {
- KeyTime = 0;
- FuncTempNum++;
- if(FuncTempNum>3)
- FuncTempNum = 0;
- }
- break;
- }
- break;
-
- default :KeyStateTemp1 = KeyStateTemp1 = StateInit; break;
-
- }
- if(FuncTempNum) //只有功能鍵被按下后,增加和減小鍵才有效
- {
- KeyPressTemp2 = KEY2; //讀取I/O口的鍵值
- switch(KeyStateTemp2)
- {
- case StateInit: //按鍵初始狀態
- if(!KeyPressTemp2) //當按鍵按下,狀態切換到確認態
- KeyStateTemp2 = StateAffirm;
- break;
- case StateAffirm: //按鍵確認態
- if(!KeyPressTemp2)
- {
- KeyTime = 0;
- KeyStateTemp2 = StateSingle;//切換到單次觸發態
- }
- else KeyStateTemp2 = StateInit; //按鍵已抬起,切換到初始態
- break;
- case StateSingle: //按鍵單發態
- if(KeyPressTemp2) //按下時間小于1s
- {
- KeyStateTemp2 = StateInit; //按鍵釋放,則回到初始態
- if(FunctionKeyNum == 1) //若功能鍵第一次按下
- {
- fen++;
- fen=fen/10*16+fen%10; //轉為16進制
- if(fen==0x60)
- fen=0x00;
- write_1302(write_fen,fen); //寫入1302
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
51hei.png (13.69 KB, 下載次數: 58)
下載附件
2021-11-13 17:47 上傳
所有資料51hei附件下載:
STC89C52單片機+DS1302+數碼管顯示及按鍵調時的時鐘程序.7z
(72.88 KB, 下載次數: 58)
2021-11-13 17:47 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|