實現的功能如下(無鬧鐘功能)。實物圖和工程文件在壓縮包
制作出來的實物圖如下:
1302顯示可調時間日期+設置鬧鐘
單片機源程序如下:
- //顯示格式24-35-25 ,小時-分鐘-秒鐘, 按下S3后,顯示年月日,2017.09.10,延時6秒后返回
- #include <reg52.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- #define sce timedate[1]
- #define min timedate[2]
- #define hour timedate[3]
- #define date timedate[4]
- #define week timedate[6]
- #define month timedate[5]
- #define year timedate[7]
- uchar displaychar1[8]={0,1,2,3,4,5,6,7},a,ya,ja ; //a結尾的字符都用來專門延時,a通用,ya日期延時程序用
- uchar commandchar[9]={0,0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e}; //與timedate對應,分別控制每個寄存器的寫,讀時數組+1,第8個數是控制寫保護位
- uchar timedate[8],sdat,seta,m;
- bit s,s2,s3,s4,K,setbit,sk;
- sbit d = P2^6;
- sbit w = P2^7;
- sbit S2 = P3^0;
- sbit S3 = P3^1;
- sbit S4 = P3^2;
- sbit SCLK = P3^3;
- sbit TIO = P3^4;
- sbit TRST = P3^5;
- uchar LD = 1; //************數碼管,亮度調節,0最小,10最高,越亮越閃 因會影響開始信號查詢時間,建議最高設置為3**************
- unsigned char code duan[]=
- { 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40,0x00 }; //段選碼0-9
- void timeout(uchar a)
- {
- uchar b;
- for(;a>0;a--)
- for(b=114;b>0;b--);
- }
- void timeout5us()
- {
- _nop_();
- }
- void display() //兩個數,分別記錄鍵值和重復碼個數
- {
-
- P0 = 0xfe; w = 1; w = 0; //顯示1位
- P0 = (displaychar1[0]); d = 1; d = 0;
- timeout(LD);
- P0 = 0; d = 1; d = 0; //清除段選
-
- P0 = 0xfd; w = 1; w = 0; //顯示2位
- P0 = displaychar1[1]; d = 1; d = 0;
- timeout(LD);
- P0 = 0; d = 1; d = 0; //清除段選
- P0 = 0xfb; w = 1; w = 0; //顯示3位
- P0 = displaychar1[2]; d = 1; d = 0;
- timeout(LD);
- P0 = 0; d = 1; d = 0; //清除段選
- P0 = 0xf7; w = 1; w = 0; //顯示4位
- P0 = displaychar1[3]; d = 1; d = 0;
- timeout(LD);
- P0 = 0; d = 1; d = 0; //清除段選,否則下一個位選變化后由于段選沒變會將此位信息顯示到下一個位。
-
- P0 = 0xef; w = 1; w = 0; //顯示5位
- P0 = displaychar1[4]; d = 1; d = 0;
- timeout(LD);
- P0 = 0; d = 1; d = 0; //清除段選
-
- P0 = 0xdf; w = 1; w = 0; //顯示6位
- P0 = displaychar1[5]; d = 1; d = 0;
- timeout(LD);
- P0 = 0; d = 1; d = 0; //清除段選
- P0 = 0xbf; w = 1; w = 0; //顯示7位
- P0 = displaychar1[6]; d = 1; d = 0;
- timeout(LD);
- P0 = 0; d = 1; d = 0; //清除段選
- P0 = 0x7f; w = 1; w = 0; //顯示8位
- P0 = displaychar1[7]; d = 1; d = 0;
- timeout(LD);
- P0 = 0; d = 1; d = 0; //清除段選,否則下一個位選變化后由于段選沒變會將此位信息顯示到下一個位。
-
- }
- /************************************************************************************
- -------------------------------以下是與時鐘芯片的數據時序---------------------------*/
- //寫控制和一個字節
- void sendchar(uchar csdat,uchar sdat)
- { SCLK = 0;
- TRST = 1;
- for(a=0;a<8;a++)
- {
- SCLK = 0;
- TIO = (csdat%2);
- SCLK = 1;
- csdat >>=1;
- }
- for(a=0;a<8;a++)
- {
- SCLK = 0;
- TIO = (sdat%2);
- SCLK = 1;
- sdat >>=1;
- }
- SCLK = 0;
- TRST = 0;
- }
- //讀一個字節
- uchar receviechar(uchar crdat)
- {
- uchar rdat;
- TRST = 1;
- // TIO = 1;
- TRST = 1;
- for(a=0;a<8;a++)
- {
- SCLK = 0;
- TIO = (crdat%2);
- SCLK = 1;
- crdat >>=1;
- }
- for(a=0;a<8;a++)
- {
- SCLK = 1;
- rdat >>= 1;
- SCLK = 0;
-
- if(TIO)
- rdat = rdat|0x80;
- }
- SCLK = 0; TRST = 0;
- return rdat ;
- }
- //讀取時分秒
- void readtime()
- {
- sendchar(0x8e,0);
- hour = receviechar(0x85);
- min = receviechar(0x83);
- sce = receviechar(0x81);
- sendchar(0x8e,0x80); //
-
- }
- //讀取年月日
- void readyear()
- {
- sendchar(0x8e,0);
- date = receviechar(0x87);
- month = receviechar(0x89);
- year = receviechar(0x8d);
- sendchar(0x8e,0x80); //
-
- }
- //=========================鍵盤掃描,用定時器延時================================
- bit jianpan(K)
- {
- if((!K)&TF0) //如果S2按下且計時器0溢出
- {
- TF0 = 0;
- ja++;
- if(ja>=2)
- {// P1 = 0;
- TR0 = 0; //每次按下后都會關閉定時器,后面的程度會檢測松手,松開按鍵后會重新打開定時器,可以保護每次按下只起作用一次
- ja = 0;
- s = 1;
- }
- return s;
- }
- return s;
- }
- //===========================================================================================================
- //**********************************************設置時間日期子函數*******************************************
- //===========================================================================================================
- void settime()
- {
- // uchar sdat,seta;
- // bit sk;
- setbit=1; //設置控制標識,進本函數后先就讓標識打開,在下面延時跳出前都會一直跳入設置功能函數
- if(TF1&(s2==s3==s4==0)) //沒有按鍵按下時用定時器1來延時跳出
- {
- TF1=0;
- seta ++;
- }
- if(!(s2==s3==s4==0)) seta = 0; //延時時間超過一定值,或者有按鍵被按下(注意!這個符號)時,時間會被延長
- if(s3); //P1++; //P1++無用:調試軟件時檢測運行的次數
- if(seta>=70)
- {
- setbit=0; //關閉設置
- sdat = 0;
- }
- if(sk!=s2) //sk用來做s2的中間暫存數據,用來用來識別S2是否變化過
- {
- sk = s2;
- if(s2)
- sdat ++; //每次進行一次S2動作時才自加一次SDTA
- if(sdat ==6)sdat=7; //跳過星期,本程序不顯示星期
- }
- m = timedate[sdat]/16*10+timedate[sdat]%16; //m用10進制存下
- if(s3) m--;
- if(s4) m++;
- switch (sdat) //每次進入設置的對應操作判斷
- {
- case 1:
- if(m>59) m = 0; break;
- case 2:
- if(m>59) m = 0; break;
- case 3:
- if(m>23) m = 0; break;
- case 4:
- if(timedate[5]==4|timedate[5]==6|timedate[5]==9|timedate[5]==11) //小月
- {
- if(m>30) m = 1; break;
- }
- if(timedate[5]==2&(timedate[7]%4==0)) //閏年2月
- {
- if(m>29) m=1; P1++; break; //
- }
- if(timedate[5]==2&(timedate[7]%4!=0)) //平年2月
- {
- if(m>28) m=1; break;
- }
- if(m>31) m =1; break; //其它月分情況
- case 5:
- if(m>12) m = 1; break;
- case 6: sdat++; //跳過星期本程序不顯示星期
- if(m>7) m = 1; break;
- case 7:
- if(m>99) m = 0; break;
- default : /****不在判斷范圍的進行初始化處理*/
- sdat = 0; sk=0; setbit = 0;s2 = 0;// P1++; //本程序所有P1++都是測試軟件運行情況用 //每次在不滿足條件時自動讓數據初始化,
- break;
- //s2=0是優化點,在按下S2后按鍵標識不會清零,松手時程序已重復運行了很多遍,所以會重新跳回設置的第一位,加本命令可以讓設置判斷失效,不進設置頁。
- }
- //==================================
- //setbit為1則說明以上有成立的條件,需要發送修改數據
- if(setbit)
- {
- sendchar(0x8e,0); //去寫保護
- sendchar(commandchar[sdat],m/10*16+m%10); //將改好的數字發送到1302
- sendchar(0x8e,0x80); //加寫保護
-
- if(seta%5>2&seta<50)
- timedate[sdat] = 0xbb; //設置延時操作期間控制閃爍時間
- } //顯示空,對應段選的兩位11;0xbb/16=11,0xbb%16=11 ,而上面段選數組中第12個數是顯示空
- //寫程序時用的測試語句,無用時未刪供復習時看看當時的思路
- /* switch (sdat)
- {
- case 1:
- P1=0xfe;
- m = sce;
- if(s4) m++;
- if(s3) m--;
-
- break;
- case 2:
- P1=0xfd; break;
- case 3:
- P1=0xfb; break;
- case 4
- :P1=0xf7; break;
- case 5:
- P1=0xef; break;
- case 6:
- P1=0xdf; break;
- case 7:
- P1=0xbf; break;
- case 8:
- P1=0x7f; break;
- default :
- sdat = 0;sk=0; //每次在不滿足條件時自動讓數據初始化,
- break;
- } */
- }
- //===================================================================================
- //============================== 主函數==============================================
- main()
- {
-
- SCLK = 0 ;
- TRST = 0 ;
- readyear(); //讀取年月日
- if(year!=0x17) //如果不是2017年,就初始化1302 ,給初值是17年10月03日,12:11:15
- {
- sendchar(0x8e,0);
- sendchar(0x80,0x15);
- sendchar(0x82,0x11);
- sendchar(0x84,0x12);
-
- sendchar(0x86,0x03);
- sendchar(0x88,0x10);
- sendchar(0x8c,0x17);
- sendchar(0x8e,0x80);
- }
- TMOD = 0x12; //設置定時器工作模式
- TR1 = 1;
- TR0 = 1;
- while(1)
- {
- if(!S2) s2 = jianpan(S2);
- if(!S3) s3 = jianpan(S3);
- if(!S4) s4 = jianpan(S4);
-
- TRST = 0;
- /*以下是開始年月日自動歸零的問題修改,問題產生原因是開始沒有加!setbit這個條件,程序在運行到設置年月日時依然會進
- 入下面這個判斷,然后再進入設置,但是年月日在這里還沒有讀數,所以這里的設置就會進入M=0然后加或減,從而讓設置值
- 出現錯誤
- */
- if((!ya&(!setbit)&(!s3))|(setbit&(sdat<4))) //如果S2沒有被按下且不在顯示年月日的延時范圍,而且設置標識為0時,或者在標識為1但是設置值在123中時,則正常顯示時間格式
- {
- readtime(); //P1++; //先讀一下時間然后再判官設置程序,這樣的主要目的是讓初m的值由1302決定。
- if(s2|setbit) //按下S2或設置標識打開時會進入本判斷
- {
- ya = 0;
- settime();
- }
- displaychar1[0] = duan[hour/16];
- displaychar1[1] = duan[hour%16];
- displaychar1[2] = duan[10];
- displaychar1[3] = duan[min/16];
- displaychar1[4] = duan[min%16];
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
所有資料51hei提供下載:
單片機DS1302可調電子時鐘.rar
(214.88 KB, 下載次數: 52)
2019-1-9 01:42 上傳
點擊文件名下載附件
|