在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 第48節(jié):利用DS1302做一個(gè)實(shí)時(shí)時(shí)鐘

            第48節(jié):利用DS1302做一個(gè)實(shí)時(shí)時(shí)鐘

            作者: 時(shí)間:2016-11-22 來源:網(wǎng)絡(luò) 收藏
            開場白:
            DS1302有兩路獨(dú)立電源輸入,我們只要在其中一路電源上掛一個(gè)紐扣電池就可以實(shí)現(xiàn)掉電時(shí)鐘繼續(xù)跑的功能,紐扣電池作為備用電源必須比主電源的電壓低一點(diǎn)。DS1302還給我們預(yù)留了一片RAM區(qū),我們可以把一些數(shù)據(jù)存入到DS1302,只要DS1302的電池有電,那么它就相當(dāng)于一個(gè)EEPROM。這個(gè)RAM區(qū)有什么用呢?因?yàn)镽AM區(qū)的數(shù)據(jù)只要一掉電,所有的數(shù)據(jù)都會(huì)變成0x00或者0xff,也就是數(shù)據(jù)掉電會(huì)丟失,我們可以利用這個(gè)特點(diǎn),可以在里面存入標(biāo)志位數(shù)據(jù),一旦發(fā)現(xiàn)這個(gè)數(shù)據(jù)改變了,就知道時(shí)鐘的數(shù)據(jù)需要重新設(shè)置過,或者說明電池沒電了。
            在移植DS1302驅(qū)動(dòng)程序中,有一個(gè)地方最容易出錯(cuò),就是DS1302芯片的數(shù)據(jù)線DIO。我們編程時(shí)要特別留意這個(gè)IO口什么時(shí)候作為數(shù)據(jù)輸入,什么時(shí)候作為數(shù)據(jù)輸出,以便及時(shí)更改方向寄存器。對于51單片機(jī),IO口在讀取數(shù)據(jù)之前,要先置1。
            這一節(jié)要教會(huì)大家六個(gè)知識點(diǎn):
            第一個(gè):DS1302做實(shí)時(shí)時(shí)鐘時(shí),修改時(shí)間和讀取時(shí)間的常見程序框架。
            第二個(gè):如何編寫監(jiān)控備用電池電量耗盡的監(jiān)控程序。
            第三個(gè):在往DS1302寫入數(shù)據(jù)修改時(shí)間之前,必須注意調(diào)整一下“日”的變量,因?yàn)槊總€(gè)月的最大天數(shù)是不一樣的,有的一個(gè)月28天,有的一個(gè)月29天,有的一個(gè)月30天,有的一個(gè)月31天。
            第四個(gè):本程序第一次出現(xiàn)了電平按鍵,跟之前講的下降沿按鍵不一樣,請留意我是何如用軟件濾波的,以及它具體的實(shí)現(xiàn)代碼。
            第五個(gè):本程序第一次出現(xiàn)了一個(gè)按鍵按下去后,如果不松手就會(huì)觸發(fā)兩次事件,第一次是短按,第二次是長按3秒。請留意我是如何在之前的按鍵上略做修改就實(shí)現(xiàn)此功能的具體代碼。
            第六個(gè):繼續(xù)加深了解按鍵與顯示是如何緊密關(guān)聯(lián)起來的程序框架。

            具體內(nèi)容,請看源代碼講解。

            (1) 硬件平臺.
            基于朱兆祺51單片機(jī)學(xué)習(xí)板。
            舊版的朱兆祺51學(xué)習(xí)板在硬件上有一個(gè)bug,DS1302芯片附近的R43,R42兩個(gè)電阻應(yīng)該去掉,并且把R41的電阻換成0歐姆的電阻,或者直接短接起來。新版的朱兆祺51學(xué)習(xí)板已經(jīng)改過來了。

            (2)實(shí)現(xiàn)功能:
            本程序有2兩個(gè)窗口。
            第1個(gè)窗口顯示日期。顯示格式“年-月-日”。注意中間有“-”分開。
            第2個(gè)窗口顯示時(shí)間。顯示格式“時(shí) 分 秒”。注意中間沒“-”,只有空格分開。
            系統(tǒng)上電后,默認(rèn)顯示第2個(gè)窗口,實(shí)時(shí)顯示動(dòng)態(tài)的“時(shí) 分 秒”時(shí)間。此時(shí)按下S13按鍵不松手就會(huì)切換到顯示日期的第1個(gè)窗口。松手后自動(dòng)切換回第2個(gè)顯示動(dòng)態(tài)時(shí)間的窗口。
            需要更改時(shí)間的時(shí)候,長按S9按鍵不松手超過3秒后,系統(tǒng)將進(jìn)入修改時(shí)間的狀態(tài),切換到第1個(gè)日期窗口,并且顯示“年”的兩位數(shù)碼管會(huì)閃爍,此時(shí)可以按S1或者S5加減按鍵修改年的參數(shù),修改完年后,繼續(xù)短按S9按鍵,會(huì)切換到“月”的參數(shù)閃爍狀態(tài),只要依次不斷按下S9按鍵,就會(huì)依次切換年,月,日,時(shí),分,秒的參數(shù)閃爍狀態(tài),最后修改完秒的參數(shù)后,系統(tǒng)會(huì)自動(dòng)把我們修改設(shè)置的日期時(shí)間一次性寫入DS1302芯片內(nèi)部,達(dá)到修改日期時(shí)間的目的。
            S13是電平變化按鍵,用來切換窗口的,專門用來查看當(dāng)前日期。按下S13按鍵時(shí)顯示日期窗口,松手后返回到顯示實(shí)時(shí)時(shí)間的窗口。

            本程序在使用過程中的注意事項(xiàng):
            (a)第一次上電時(shí),蜂鳴器會(huì)報(bào)警,只要DS1302芯片的備用電池電量充足,這個(gè)時(shí)候斷電再重啟一次,就不會(huì)報(bào)警了。
            (b)第一次上電時(shí),時(shí)間沒有走動(dòng),需要重新設(shè)置一下日期時(shí)間才可以。長按S9按鍵可以進(jìn)入修改日期時(shí)間的狀態(tài)。

            (3)源代碼講解如下:
            1. #include "REG52.H"
            2. #define const_dpy_time_half200//數(shù)碼管閃爍時(shí)間的半值
            3. #define const_dpy_time_all 400//數(shù)碼管閃爍時(shí)間的全值 一定要比const_dpy_time_half 大
            4. #define const_voice_short40 //蜂鳴器短叫的持續(xù)時(shí)間
            5. #define const_key_time120 //按鍵去抖動(dòng)延時(shí)的時(shí)間
            6. #define const_key_time220 //按鍵去抖動(dòng)延時(shí)的時(shí)間
            7. #define const_key_time320 //按鍵去抖動(dòng)延時(shí)的時(shí)間
            8. #define const_key_time420 //按鍵去抖動(dòng)延時(shí)的時(shí)間
            9. #define const_key_time171200//長按超過3秒的時(shí)間
            10. #define const_ds1302_0_5s200 //大概0.5秒的時(shí)間
            11. #define const_ds1302_sampling_time 360 //累計(jì)主循環(huán)次數(shù)的時(shí)間,每次刷新采樣時(shí)鐘芯片的時(shí)間
            12. #define WRITE_SECOND 0x80 //DS1302內(nèi)部的相關(guān)地址
            13. #define WRITE_MINUTE 0x82
            14. #define WRITE_HOUR 0x84
            15. #define WRITE_DATE 0x86
            16. #define WRITE_MONTH 0x88
            17. #define WRITE_YEAR 0x8C
            18. #define WRITE_CHECK 0xC2//用來檢查芯片的備用電池是否用完了的地址
            19. #define READ_CHECK 0xC3//用來檢查芯片的備用電池是否用完了的地址
            20. #define READ_SECOND 0x81
            21. #define READ_MINUTE 0x83
            22. #define READ_HOUR 0x85
            23. #define READ_DATE 0x87
            24. #define READ_MONTH 0x89
            25. #define READ_YEAR 0x8D
            26. #define WRITE_PROTECT 0x8E
            27. void initial_myself(void);
            28. void initial_peripheral(void);
            29. void delay_short(unsigned int uiDelayShort);
            30. void delay_long(unsigned int uiDelaylong);
            31. //驅(qū)動(dòng)數(shù)碼管的74HC595
            32. void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01);
            33. void display_drive(void); //顯示數(shù)碼管字模的驅(qū)動(dòng)函數(shù)
            34. void display_service(void); //顯示的窗口菜單服務(wù)程序
            35. //驅(qū)動(dòng)LED的74HC595
            36. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01);
            37. void T0_time(void);//定時(shí)中斷函數(shù)
            38. void key_service(void); //按鍵服務(wù)的應(yīng)用程序
            39. void key_scan(void);//按鍵掃描函數(shù) 放在定時(shí)中斷里
            40. void ds1302_alarm_service(void); //ds1302出錯(cuò)報(bào)警
            41. void ds1302_sampling(void); //ds1302采樣程序,內(nèi)部每秒鐘采集更新一次
            42. void Write1302 ( unsigned char addr, unsigned char dat );//修改時(shí)間的驅(qū)動(dòng)
            43. unsigned char Read1302 ( unsigned char addr );//讀取時(shí)間的驅(qū)動(dòng)
            44. unsigned char bcd_to_number(unsigned char ucBcdTemp);//BCD轉(zhuǎn)原始數(shù)值
            45. unsigned char number_to_bcd(unsigned char ucNumberTemp); //原始數(shù)值轉(zhuǎn)BCD
            46. //日調(diào)整 每個(gè)月份的日最大取值不同,有的最大28日,有的最大29日,有的最大30,有的最大31
            47. unsigned char date_adjust(unsigned char ucYearTemp,unsigned char ucMonthTemp,unsigned char ucDateTemp); //日調(diào)整
            48. sbit SCLK_dr =P1^3;
            49. sbit DIO_dr_sr =P1^4;
            50. sbit DS1302_CE_dr =P1^5;
            51. sbit key_sr1=P0^0; //對應(yīng)朱兆祺學(xué)習(xí)板的S1鍵
            52. sbit key_sr2=P0^1; //對應(yīng)朱兆祺學(xué)習(xí)板的S5鍵
            53. sbit key_sr3=P0^2; //對應(yīng)朱兆祺學(xué)習(xí)板的S9鍵
            54. sbit key_sr4=P0^3; //對應(yīng)朱兆祺學(xué)習(xí)板的S13鍵
            55. sbit key_gnd_dr=P0^4; //模擬獨(dú)立按鍵的地GND,因此必須一直輸出低電平
            56. sbit beep_dr=P2^7; //蜂鳴器的驅(qū)動(dòng)IO口
            57. sbit eeprom_scl_dr=P3^7; //時(shí)鐘線
            58. sbit eeprom_sda_dr_sr=P3^6; //數(shù)據(jù)的輸出線和輸入線
            59. sbit dig_hc595_sh_dr=P2^0; //數(shù)碼管的74HC595程序
            60. sbit dig_hc595_st_dr=P2^1;
            61. sbit dig_hc595_ds_dr=P2^2;
            62. sbit hc595_sh_dr=P2^3; //LED燈的74HC595程序
            63. sbit hc595_st_dr=P2^4;
            64. sbit hc595_ds_dr=P2^5;
            65. unsigned int uiSampingCnt=0; //采集Ds1302的計(jì)時(shí)器,每秒鐘更新采集一次
            66. unsigned char ucKeySec=0; //被觸發(fā)的按鍵編號
            67. unsigned intuiKeyTimeCnt1=0; //按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器
            68. unsigned char ucKeyLock1=0; //按鍵觸發(fā)后自鎖的變量標(biāo)志
            69. unsigned intuiKeyTimeCnt2=0; //按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器
            70. unsigned char ucKeyLock2=0; //按鍵觸發(fā)后自鎖的變量標(biāo)志
            71. unsigned intuiKeyTimeCnt3=0; //按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器
            72. unsigned char ucKeyLock3=0; //按鍵觸發(fā)后自鎖的變量標(biāo)志
            73. unsigned int uiKey4Cnt1=0;//在軟件濾波中,用到的變量
            74. unsigned int uiKey4Cnt2=0;
            75. unsigned char ucKey4Sr=1;//實(shí)時(shí)反映按鍵的電平狀態(tài)
            76. unsigned char ucKey4SrRecord=0; //記錄上一次按鍵的電平狀態(tài)
            77. unsigned intuiVoiceCnt=0;//蜂鳴器鳴叫的持續(xù)時(shí)間計(jì)數(shù)器
            78. unsigned charucVoiceLock=0;//蜂鳴器鳴叫的原子鎖
            79. unsigned char ucDigShow8;//第8位數(shù)碼管要顯示的內(nèi)容
            80. unsigned char ucDigShow7;//第7位數(shù)碼管要顯示的內(nèi)容
            81. unsigned char ucDigShow6;//第6位數(shù)碼管要顯示的內(nèi)容
            82. unsigned char ucDigShow5;//第5位數(shù)碼管要顯示的內(nèi)容
            83. unsigned char ucDigShow4;//第4位數(shù)碼管要顯示的內(nèi)容
            84. unsigned char ucDigShow3;//第3位數(shù)碼管要顯示的內(nèi)容
            85. unsigned char ucDigShow2;//第2位數(shù)碼管要顯示的內(nèi)容
            86. unsigned char ucDigShow1;//第1位數(shù)碼管要顯示的內(nèi)容
            87. unsigned char ucDigDot8;//數(shù)碼管8的小數(shù)點(diǎn)是否顯示的標(biāo)志
            88. unsigned char ucDigDot7;//數(shù)碼管7的小數(shù)點(diǎn)是否顯示的標(biāo)志
            89. unsigned char ucDigDot6;//數(shù)碼管6的小數(shù)點(diǎn)是否顯示的標(biāo)志
            90. unsigned char ucDigDot5;//數(shù)碼管5的小數(shù)點(diǎn)是否顯示的標(biāo)志
            91. unsigned char ucDigDot4;//數(shù)碼管4的小數(shù)點(diǎn)是否顯示的標(biāo)志
            92. unsigned char ucDigDot3;//數(shù)碼管3的小數(shù)點(diǎn)是否顯示的標(biāo)志
            93. unsigned char ucDigDot2;//數(shù)碼管2的小數(shù)點(diǎn)是否顯示的標(biāo)志
            94. unsigned char ucDigDot1;//數(shù)碼管1的小數(shù)點(diǎn)是否顯示的標(biāo)志
            95. unsigned char ucDigShowTemp=0; //臨時(shí)中間變量
            96. unsigned char ucDisplayDriveStep=1;//動(dòng)態(tài)掃描數(shù)碼管的步驟變量
            97. unsigned char ucWd=2;//本程序的核心變量,窗口顯示變量。類似于一級菜單的變量。代表顯示不同的窗口。
            98. unsigned char ucPart=0;//本程序的核心變量,局部顯示變量。類似于二級菜單的變量。代表顯示不同的局部。
            99. unsigned char ucWd1Update=0; //窗口1更新顯示標(biāo)志
            100. unsigned char ucWd2Update=1; //窗口2更新顯示標(biāo)志
            101. unsigned char ucWd1Part1Update=0;//在窗口1中,局部1的更新顯示標(biāo)志
            102. unsigned char ucWd1Part2Update=0; //在窗口1中,局部2的更新顯示標(biāo)志
            103. unsigned char ucWd1Part3Update=0; //在窗口1中,局部3的更新顯示標(biāo)志
            104. unsigned char ucWd2Part1Update=0;//在窗口2中,局部1的更新顯示標(biāo)志
            105. unsigned char ucWd2Part2Update=0; //在窗口2中,局部2的更新顯示標(biāo)志
            106. unsigned char ucWd2Part3Update=0; //在窗口2中,局部3的更新顯示標(biāo)志
            107. unsigned charucYear=0; //原始數(shù)據(jù)
            108. unsigned charucMonth=0;
            109. unsigned charucDate=0;
            110. unsigned charucHour=0;
            111. unsigned charucMinute=0;
            112. unsigned charucSecond=0;
            113. unsigned charucYearBCD=0; //BCD碼的數(shù)據(jù)
            114. unsigned charucMonthBCD=0;
            115. unsigned charucDateBCD=0;
            116. unsigned charucHourBCD=0;
            117. unsigned charucMinuteBCD=0;
            118. unsigned charucSecondBCD=0;
            119. unsigned char ucTemp1=0;//中間過渡變量
            120. unsigned char ucTemp2=0;//中間過渡變量
            121. unsigned char ucTemp4=0;//中間過渡變量
            122. unsigned char ucTemp5=0;//中間過渡變量
            123. unsigned char ucTemp7=0;//中間過渡變量
            124. unsigned char ucTemp8=0;//中間過渡變量
            125. unsigned char ucDelayTimerLock=0; //原子鎖
            126. unsigned intuiDelayTimer=0;
            127. unsigned char ucCheckDs1302=0;//檢查Ds1302芯片是否正常
            128. unsigned char ucDs1302Error=0; //Ds1302芯片的備用電池是否用完了的報(bào)警標(biāo)志
            129. unsigned char ucDs1302Lock=0;//原子鎖
            130. unsigned intuiDs1302Cnt=0; //間歇性蜂鳴器報(bào)警的計(jì)時(shí)器
            131. unsigned char ucDpyTimeLock=0; //原子鎖
            132. unsigned intuiDpyTimeCnt=0;//數(shù)碼管的閃爍計(jì)時(shí)器,放在定時(shí)中斷里不斷累加
            133. //根據(jù)原理圖得出的共陰數(shù)碼管字模表
            134. code unsigned char dig_table[]=
            135. {
            136. 0x3f,//0 序號0
            137. 0x06,//1 序號1
            138. 0x5b,//2 序號2
            139. 0x4f,//3 序號3
            140. 0x66,//4 序號4
            141. 0x6d,//5 序號5
            142. 0x7d,//6 序號6
            143. 0x07,//7 序號7
            144. 0x7f,//8 序號8
            145. 0x6f,//9 序號9
            146. 0x00,//無 序號10
            147. 0x40,//- 序號11
            148. 0x73,//P 序號12
            149. };
            150. void main()
            151. {
            152. initial_myself();
            153. delay_long(100);
            154. initial_peripheral();
            155. while(1)
            156. {
            157. key_service(); //按鍵服務(wù)的應(yīng)用程序
            158. ds1302_sampling(); //ds1302采樣程序,內(nèi)部每秒鐘采集更新一次
            159. display_service(); //顯示的窗口菜單服務(wù)程序
            160. ds1302_alarm_service(); //ds1302出錯(cuò)報(bào)警
            161. }
            162. }
            163. /* 注釋一:
            164. * 系統(tǒng)不用時(shí)時(shí)刻刻采集ds1302的內(nèi)部數(shù)據(jù),每隔一段時(shí)間更新采集一次就可以了。
            165. * 這個(gè)間隔時(shí)間應(yīng)該小于或者等于1秒鐘的時(shí)間,否則在數(shù)碼管上看不到每秒鐘的時(shí)間變化。
            166. */
            167. void ds1302_sampling(void) //ds1302采樣程序,內(nèi)部每秒鐘采集更新一次
            168. {
            169. if(ucPart==0)//當(dāng)系統(tǒng)不是處于設(shè)置日期和時(shí)間的情況下
            170. {
            171. ++uiSampingCnt;//累計(jì)主循環(huán)次數(shù)的時(shí)間
            172. if(uiSampingCnt>const_ds1302_sampling_time)//每隔一段時(shí)間就更新采集一次Ds1302數(shù)據(jù)
            173. {
            174. uiSampingCnt=0;
            175. ucYearBCD=Read1302(READ_YEAR); //讀取年
            176. ucMonthBCD=Read1302(READ_MONTH); //讀取月
            177. ucDateBCD=Read1302(READ_DATE); //讀取日
            178. ucHourBCD=Read1302(READ_HOUR); //讀取時(shí)
            179. ucMinuteBCD=Read1302(READ_MINUTE); //讀取分
            180. ucSecondBCD=Read1302(READ_SECOND); //讀取秒
            181. ucYear=bcd_to_number(ucYearBCD);//BCD轉(zhuǎn)原始數(shù)值
            182. ucMonth=bcd_to_number(ucMonthBCD);//BCD轉(zhuǎn)原始數(shù)值
            183. ucDate=bcd_to_number(ucDateBCD);//BCD轉(zhuǎn)原始數(shù)值
            184. ucHour=bcd_to_number(ucHourBCD);//BCD轉(zhuǎn)原始數(shù)值
            185. ucMinute=bcd_to_number(ucMinuteBCD);//BCD轉(zhuǎn)原始數(shù)值
            186. ucSecond=bcd_to_number(ucSecondBCD);//BCD轉(zhuǎn)原始數(shù)值
            187. ucWd2Update=1; //窗口2更新顯示時(shí)間
            188. }
            189. }
            190. }
            191. //修改ds1302時(shí)間的驅(qū)動(dòng) ,注意,此處寫入的是BCD碼,
            192. void Write1302 ( unsigned char addr, unsigned char dat )
            193. {
            194. unsigned char i,temp; //單片機(jī)驅(qū)動(dòng)DS1302屬于SPI通訊方式,根據(jù)我的經(jīng)驗(yàn),不用關(guān)閉中斷
            195. DS1302_CE_dr=0; //CE引腳為低,數(shù)據(jù)傳送中止
            196. delay_short(1);
            197. SCLK_dr=0; //清零時(shí)鐘總線
            198. delay_short(1);
            199. DS1302_CE_dr = 1; //CE引腳為高,邏輯控制有效
            200. delay_short(1);
            201. //發(fā)送地址
            202. for ( i=0; i<8; i++ ) //循環(huán)8次移位
            203. {
            204. DIO_dr_sr = 0;
            205. temp = addr;
            206. if(temp&0x01)
            207. {
            208. DIO_dr_sr =1;
            209. }
            210. else
            211. {
            212. DIO_dr_sr =0;
            213. }
            214. delay_short(1);
            215. addr >>= 1; //右移一位
            216. SCLK_dr = 1;
            217. delay_short(1);
            218. SCLK_dr = 0;
            219. delay_short(1);
            220. }
            221. //發(fā)送數(shù)據(jù)
            222. for ( i=0; i<8; i++ ) //循環(huán)8次移位
            223. {
            224. DIO_dr_sr = 0;
            225. temp = dat;
            226. if(temp&0x01)
            227. {
            228. DIO_dr_sr =1;
            229. }
            230. else
            231. {
            232. DIO_dr_sr =0;
            233. }
            234. delay_short(1);
            235. dat >>= 1; //右移一位
            236. SCLK_dr = 1;
            237. delay_short(1);
            238. SCLK_dr = 0;
            239. delay_short(1);
            240. }
            241. DS1302_CE_dr = 0;
            242. delay_short(1);
            243. }
            244. //讀取Ds1302時(shí)間的驅(qū)動(dòng) ,注意,此處讀取的是BCD碼,
            245. unsigned char Read1302 ( unsigned char addr )
            246. {
            247. unsigned char i,temp,dat1;
            248. DS1302_CE_dr=0; //單片機(jī)驅(qū)動(dòng)DS1302屬于SPI通訊方式,根據(jù)我的經(jīng)驗(yàn),不用關(guān)閉中斷
            249. delay_short(1);
            250. SCLK_dr=0;
            251. delay_short(1);
            252. DS1302_CE_dr = 1;
            253. delay_short(1);
            254. //發(fā)送地址
            255. for ( i=0; i<8; i++ ) //循環(huán)8次移位
            256. {
            257. DIO_dr_sr = 0;
            258. temp = addr;
            259. if(temp&0x01)
            260. {
            261. DIO_dr_sr =1;
            262. }
            263. else
            264. {
            265. DIO_dr_sr =0;
            266. }
            267. delay_short(1);
            268. addr >>= 1; //右移一位
            269. SCLK_dr = 1;
            270. delay_short(1);
            271. SCLK_dr = 0;
            272. delay_short(1);
            273. }
            274. /* 注釋二:
            275. * 51單片機(jī)IO口的特點(diǎn),在讀取數(shù)據(jù)之前必須先輸出高電平,
            276. * 如果是PIC,AVR等單片機(jī),這里應(yīng)該把IO方向寄存器設(shè)置為輸入
            277. */
            278. DIO_dr_sr =1; //51單片機(jī)IO口的特點(diǎn),在讀取數(shù)據(jù)之前必須先輸出高電平,
            279. temp=0;
            280. for ( i=0; i<8; i++ )
            281. {
            282. temp>>=1;
            283. if(DIO_dr_sr==1)
            284. {
            285. temp=temp+0x80;
            286. }
            287. DIO_dr_sr =1;//51單片機(jī)IO口的特點(diǎn),在讀取數(shù)據(jù)之前必須先輸出高電平
            288. delay_short(1);
            289. SCLK_dr = 1;
            290. delay_short(1);
            291. SCLK_dr = 0;
            292. delay_short(1);
            293. }
            294. DS1302_CE_dr=0;
            295. delay_short(1);
            296. dat1=temp;
            297. return (dat1);
            298. }
            299. unsigned char bcd_to_number(unsigned char ucBcdTemp)//BCD轉(zhuǎn)原始數(shù)值
            300. {
            301. unsigned char ucNumberResult=0;
            302. unsigned char ucBcdTemp10;
            303. unsigned char ucBcdTemp1;
            304. ucBcdTemp10=ucBcdTemp;
            305. ucBcdTemp10=ucBcdTemp10>>4;
            306. ucBcdTemp1=ucBcdTemp;
            307. ucBcdTemp1=ucBcdTemp1&0x0f;
            308. ucNumberResult=ucBcdTemp10*10+ucBcdTemp1;
            309. return ucNumberResult;
            310. }
            311. unsigned char number_to_bcd(unsigned char ucNumberTemp) //原始數(shù)值轉(zhuǎn)BCD
            312. {
            313. unsigned char ucBcdResult=0;
            314. unsigned char ucNumberTemp10;
            315. unsigned char ucNumberTemp1;
            316. ucNumberTemp10=ucNumberTemp;
            317. ucNumberTemp10=ucNumberTemp10/10;
            318. ucNumberTemp10=ucNumberTemp10<<4;
            319. ucNumberTemp10=ucNumberTemp10&0xf0;
            320. ucNumberTemp1=ucNumberTemp;
            321. ucNumberTemp1=ucNumberTemp1%10;
            322. ucBcdResult=ucNumberTemp10|ucNumberTemp1;
            323. return ucBcdResult;
            324. }
            325. //日調(diào)整 每個(gè)月份的日最大取值不同,有的最大28日,有的最大29日,有的最大30,有的最大31
            326. unsigned char date_adjust(unsigned char ucYearTemp,unsigned char ucMonthTemp,unsigned char ucDateTemp) //日調(diào)整
            327. {
            328. unsigned char ucDayResult;
            329. unsigned int uiYearTemp;
            330. unsigned int uiYearYu;
            331. ucDayResult=ucDateTemp;
            332. switch(ucMonthTemp)//根據(jù)不同的月份來修正不同的日最大值
            333. {
            334. case 2://二月份要計(jì)算是否是閏年
            335. uiYearTemp=2000+ucYearTemp;
            336. uiYearYu=uiYearTemp%4;
            337. if(uiYearYu==0) //閏年
            338. {
            339. if(ucDayResult>29)
            340. {
            341. ucDayResult=29;
            342. }
            343. }
            344. else
            345. {
            346. if(ucDayResult>28)
            347. {
            348. ucDayResult=28;
            349. }
            350. }
            351. break;
            352. case 4:
            353. case 6:
            354. case 9:
            355. case 11:
            356. if(ucDayResult>30)
            357. {
            358. ucDayResult=30;
            359. }
            360. break;
            361. }
            362. return ucDayResult;
            363. }
            364. void ds1302_alarm_service(void) //ds1302出錯(cuò)報(bào)警
            365. {
            366. if(ucDs1302Error==1)//備用電池的電量用完了報(bào)警提示
            367. {
            368. if(uiDs1302Cnt>const_ds1302_0_5s)//大概0.5秒鐘蜂鳴器響一次
            369. {
            370. ucDs1302Lock=1;//原子鎖加鎖
            371. uiDs1302Cnt=0; //計(jì)時(shí)器清零
            372. ucDs1302Lock=0;//原子鎖解鎖
            373. ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            374. uiVoiceCnt=const_voice_short; //蜂鳴器聲音觸發(fā),滴一聲就停。
            375. ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            376. }
            377. }
            378. }
            379. void display_service(void) //顯示的窗口菜單服務(wù)程序
            380. {
            381. switch(ucWd)//本程序的核心變量,窗口顯示變量。類似于一級菜單的變量。代表顯示不同的窗口。
            382. {
            383. case 1: //顯示日期窗口的數(shù)據(jù)數(shù)據(jù)格式 NN-YY-RR 年-月-日
            384. if(ucWd1Update==1)//窗口1要全部更新顯示
            385. {
            386. ucWd1Update=0;//及時(shí)清零標(biāo)志,避免一直進(jìn)來掃描
            387. ucDigShow6=11;//顯示一杠"-"
            388. ucDigShow3=11;//顯示一杠"-"
            389. ucWd1Part1Update=1;//局部年更新顯示
            390. ucWd1Part2Update=1;//局部月更新顯示
            391. ucWd1Part3Update=1;//局部日更新顯示
            392. }
            393. if(ucWd1Part1Update==1)//局部年更新顯示
            394. {
            395. ucWd1Part1Update=0;
            396. ucTemp8=ucYear/10;//年
            397. ucTemp7=ucYear%10;
            398. ucDigShow8=ucTemp8; //數(shù)碼管顯示實(shí)際內(nèi)容
            399. ucDigShow7=ucTemp7;
            400. }
            401. if(ucWd1Part2Update==1)//局部月更新顯示
            402. {
            403. ucWd1Part2Update=0;
            404. ucTemp5=ucMonth/10;//月
            405. ucTemp4=ucMonth%10;
            406. ucDigShow5=ucTemp5; //數(shù)碼管顯示實(shí)際內(nèi)容
            407. ucDigShow4=ucTemp4;
            408. }
            409. if(ucWd1Part3Update==1) //局部日更新顯示
            410. {
            411. ucWd1Part3Update=0;
            412. ucTemp2=ucDate/10;//日
            413. ucTemp1=ucDate%10;
            414. ucDigShow2=ucTemp2; //數(shù)碼管顯示實(shí)際內(nèi)容
            415. ucDigShow1=ucTemp1;
            416. }
            417. //數(shù)碼管閃爍
            418. switch(ucPart)//相當(dāng)于二級菜單,根據(jù)局部變量的值,使對應(yīng)的參數(shù)產(chǎn)生閃爍的動(dòng)態(tài)效果。
            419. {
            420. case 0://都不閃爍
            421. break;
            422. case 1://年參數(shù)閃爍
            423. if(uiDpyTimeCnt==const_dpy_time_half)
            424. {
            425. ucDigShow8=ucTemp8; //數(shù)碼管顯示實(shí)際內(nèi)容
            426. ucDigShow7=ucTemp7;
            427. }
            428. else if(uiDpyTimeCnt>const_dpy_time_all) //const_dpy_time_all一定要比const_dpy_time_half 大
            429. {
            430. ucDpyTimeLock=1; //原子鎖加鎖
            431. uiDpyTimeCnt=0; //及時(shí)把閃爍記時(shí)器清零
            432. ucDpyTimeLock=0;//原子鎖解鎖
            433. ucDigShow8=10; //數(shù)碼管顯示空,什么都不顯示
            434. ucDigShow7=10;
            435. }
            436. break;
            437. case 2: //月參數(shù)閃爍
            438. if(uiDpyTimeCnt==const_dpy_time_half)
            439. {
            440. ucDigShow5=ucTemp5; //數(shù)碼管顯示實(shí)際內(nèi)容
            441. ucDigShow4=ucTemp4;
            442. }
            443. else if(uiDpyTimeCnt>const_dpy_time_all) //const_dpy_time_all一定要比const_dpy_time_half 大
            444. {
            445. ucDpyTimeLock=1; //原子鎖加鎖
            446. uiDpyTimeCnt=0; //及時(shí)把閃爍記時(shí)器清零
            447. ucDpyTimeLock=0;//原子鎖解鎖
            448. ucDigShow5=10; //數(shù)碼管顯示空,什么都不顯示
            449. ucDigShow4=10;
            450. }
            451. break;
            452. case 3: //日參數(shù)閃爍
            453. if(uiDpyTimeCnt==const_dpy_time_half)
            454. {
            455. ucDigShow2=ucTemp2; //數(shù)碼管顯示實(shí)際內(nèi)容
            456. ucDigShow1=ucTemp1;
            457. }
            458. else if(uiDpyTimeCnt>const_dpy_time_all) //const_dpy_time_all一定要比const_dpy_time_half 大
            459. {
            460. ucDpyTimeLock=1; //原子鎖加鎖
            461. uiDpyTimeCnt=0; //及時(shí)把閃爍記時(shí)器清零
            462. ucDpyTimeLock=0;//原子鎖解鎖
            463. ucDigShow2=10; //數(shù)碼管顯示空,什么都不顯示
            464. ucDigShow1=10;
            465. }
            466. break;
            467. }
            468. break;
            469. case 2: //顯示時(shí)間窗口的數(shù)據(jù)數(shù)據(jù)格式 SS FF MM 時(shí) 分 秒
            470. if(ucWd2Update==1)//窗口2要全部更新顯示
            471. {
            472. ucWd2Update=0;//及時(shí)清零標(biāo)志,避免一直進(jìn)來掃描
            473. ucDigShow6=10;//顯示空
            474. ucDigShow3=10;//顯示空
            475. ucWd2Part3Update=1;//局部時(shí)更新顯示
            476. ucWd2Part2Update=1;//局部分更新顯示
            477. ucWd2Part1Update=1;//局部秒更新顯示
            478. }
            479. if(ucWd2Part1Update==1)//局部時(shí)更新顯示
            480. {
            481. ucWd2Part1Update=0;
            482. ucTemp8=ucHour/10;//時(shí)
            483. ucTemp7=ucHour%10;
            484. ucDigShow8=ucTemp8; //數(shù)碼管顯示實(shí)際內(nèi)容
            485. ucDigShow7=ucTemp7;
            486. }
            487. if(ucWd2Part2Update==1)//局部分更新顯示
            488. {
            489. ucWd2Part2Update=0;
            490. ucTemp5=ucMinute/10;//分
            491. ucTemp4=ucMinute%10;
            492. ucDigShow5=ucTemp5; //數(shù)碼管顯示實(shí)際內(nèi)容
            493. ucDigShow4=ucTemp4;
            494. }
            495. if(ucWd2Part3Update==1) //局部秒更新顯示
            496. {
            497. ucWd2Part3Update=0;
            498. ucTemp2=ucSecond/10;//秒
            499. ucTemp1=ucSecond%10;
            500. ucDigShow2=ucTemp2; //數(shù)碼管顯示實(shí)際內(nèi)容
            501. ucDigShow1=ucTemp1;
            502. }
            503. //數(shù)碼管閃爍
            504. switch(ucPart)//相當(dāng)于二級菜單,根據(jù)局部變量的值,使對應(yīng)的參數(shù)產(chǎn)生閃爍的動(dòng)態(tài)效果。
            505. {
            506. case 0://都不閃爍
            507. break;
            508. case 1://時(shí)參數(shù)閃爍
            509. if(uiDpyTimeCnt==const_dpy_time_half)
            510. {
            511. ucDigShow8=ucTemp8; //數(shù)碼管顯示實(shí)際內(nèi)容
            512. ucDigShow7=ucTemp7;
            513. }
            514. else if(uiDpyTimeCnt>const_dpy_time_all) //const_dpy_time_all一定要比const_dpy_time_half 大
            515. {
            516. ucDpyTimeLock=1; //原子鎖加鎖
            517. uiDpyTimeCnt=0; //及時(shí)把閃爍記時(shí)器清零
            518. ucDpyTimeLock=0;//原子鎖解鎖
            519. ucDigShow8=10; //數(shù)碼管顯示空,什么都不顯示
            520. ucDigShow7=10;
            521. }
            522. break;
            523. case 2: //分參數(shù)閃爍
            524. if(uiDpyTimeCnt==const_dpy_time_half)
            525. {
            526. ucDigShow5=ucTemp5; //數(shù)碼管顯示實(shí)際內(nèi)容
            527. ucDigShow4=ucTemp4;
            528. }
            529. else if(uiDpyTimeCnt>const_dpy_time_all) //const_dpy_time_all一定要比const_dpy_time_half 大
            530. {
            531. ucDpyTimeLock=1; //原子鎖加鎖
            532. uiDpyTimeCnt=0; //及時(shí)把閃爍記時(shí)器清零
            533. ucDpyTimeLock=0;//原子鎖解鎖
            534. ucDigShow5=10; //數(shù)碼管顯示空,什么都不顯示
            535. ucDigShow4=10;
            536. }
            537. break;
            538. case 3: //秒?yún)?shù)閃爍
            539. if(uiDpyTimeCnt==const_dpy_time_half)
            540. {
            541. ucDigShow2=ucTemp2; //數(shù)碼管顯示實(shí)際內(nèi)容
            542. ucDigShow1=ucTemp1;
            543. }
            544. else if(uiDpyTimeCnt>const_dpy_time_all) //const_dpy_time_all一定要比const_dpy_time_half 大
            545. {
            546. ucDpyTimeLock=1; //原子鎖加鎖
            547. uiDpyTimeCnt=0; //及時(shí)把閃爍記時(shí)器清零
            548. ucDpyTimeLock=0;//原子鎖解鎖
            549. ucDigShow2=10; //數(shù)碼管顯示空,什么都不顯示
            550. ucDigShow1=10;
            551. }
            552. break;
            553. }
            554. break;
            555. }
            556. }
            557. void key_scan(void)//按鍵掃描函數(shù) 放在定時(shí)中斷里
            558. {
            559. if(key_sr1==1)//IO是高電平,說明按鍵沒有被按下,這時(shí)要及時(shí)清零一些標(biāo)志位
            560. {
            561. ucKeyLock1=0; //按鍵自鎖標(biāo)志清零
            562. uiKeyTimeCnt1=0;//按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器清零,此行非常巧妙,是我實(shí)戰(zhàn)中摸索出來的。
            563. }
            564. else if(ucKeyLock1==0)//有按鍵按下,且是第一次被按下
            565. {
            566. uiKeyTimeCnt1++; //累加定時(shí)中斷次數(shù)
            567. if(uiKeyTimeCnt1>const_key_time1)
            568. {
            569. uiKeyTimeCnt1=0;
            570. ucKeyLock1=1;//自鎖按鍵置位,避免一直觸發(fā)
            571. ucKeySec=1; //觸發(fā)1號鍵
            572. }
            573. }
            574. if(key_sr2==1)//IO是高電平,說明按鍵沒有被按下,這時(shí)要及時(shí)清零一些標(biāo)志位
            575. {
            576. ucKeyLock2=0; //按鍵自鎖標(biāo)志清零
            577. uiKeyTimeCnt2=0;//按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器清零,此行非常巧妙,是我實(shí)戰(zhàn)中摸索出來的。
            578. }
            579. else if(ucKeyLock2==0)//有按鍵按下,且是第一次被按下
            580. {
            581. uiKeyTimeCnt2++; //累加定時(shí)中斷次數(shù)
            582. if(uiKeyTimeCnt2>const_key_time2)
            583. {
            584. uiKeyTimeCnt2=0;
            585. ucKeyLock2=1;//自鎖按鍵置位,避免一直觸發(fā)
            586. ucKeySec=2; //觸發(fā)2號鍵
            587. }
            588. }
            589. /* 注釋三:
            590. * 注意,此處把一個(gè)按鍵的短按和長按的功能都實(shí)現(xiàn)了。
            591. */
            592. if(key_sr3==1)//IO是高電平,說明按鍵沒有被按下,這時(shí)要及時(shí)清零一些標(biāo)志位
            593. {
            594. ucKeyLock3=0; //按鍵自鎖標(biāo)志清零
            595. uiKeyTimeCnt3=0;//按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器清零,此行非常巧妙,是我實(shí)戰(zhàn)中摸索出來的。
            596. }
            597. else if(ucKeyLock3==0)//有按鍵按下,且是第一次被按下
            598. {
            599. uiKeyTimeCnt3++; //累加定時(shí)中斷次數(shù)
            600. if(uiKeyTimeCnt3>const_key_time3)
            601. {
            602. uiKeyTimeCnt3=0;
            603. ucKeyLock3=1;//自鎖按鍵置位,避免一直觸發(fā)
            604. ucKeySec=3; //短按觸發(fā)3號鍵
            605. }
            606. }
            607. else if(uiKeyTimeCnt3
            608. {
            609. uiKeyTimeCnt3++; //累加定時(shí)中斷次數(shù)
            610. if(uiKeyTimeCnt3==const_key_time17)//等于3秒鐘,觸發(fā)17號長按按鍵
            611. {
            612. ucKeySec=17; //長按3秒觸發(fā)17號鍵
            613. }
            614. }
            615. /* 注釋四:
            616. * 注意,此處是電平按鍵的濾波抗干擾處理
            617. */
            618. if(key_sr4==1)//對應(yīng)朱兆祺學(xué)習(xí)板的S13鍵
            619. {
            620. uiKey4Cnt1=0; //在軟件濾波中,非常關(guān)鍵的語句!??!類似按鍵去抖動(dòng)程序的及時(shí)清零
            621. uiKey4Cnt2++; //類似獨(dú)立按鍵去抖動(dòng)的軟件抗干擾處理
            622. if(uiKey4Cnt2>const_key_time4)
            623. {
            624. uiKey4Cnt2=0;
            625. ucKey4Sr=1;//實(shí)時(shí)反映按鍵松手時(shí)的電平狀態(tài)
            626. }
            627. }
            628. else
            629. {
            630. uiKey4Cnt2=0; //在軟件濾波中,非常關(guān)鍵的語句?。?!類似按鍵去抖動(dòng)程序的及時(shí)清零
            631. uiKey4Cnt1++;
            632. if(uiKey4Cnt1>const_key_time4)
            633. {
            634. uiKey4Cnt1=0;
            635. ucKey4Sr=0;//實(shí)時(shí)反映按鍵按下時(shí)的電平狀態(tài)
            636. }
            637. }
            638. }
            639. void key_service(void) //按鍵服務(wù)的應(yīng)用程序
            640. {
            641. switch(ucKeySec) //按鍵服務(wù)狀態(tài)切換
            642. {
            643. case 1:// 加按鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S1鍵
            644. switch(ucWd)//在不同的窗口下,設(shè)置不同的參數(shù)
            645. {
            646. case 1:
            647. switch(ucPart) //在不同的局部變量下,相當(dāng)于二級菜單
            648. {
            649. case 1://年
            650. ucYear++;
            651. if(ucYear>99)
            652. {
            653. ucYear=99;
            654. }
            655. ucWd1Part1Update=1;//更新顯示
            656. break;
            657. case 2: //月
            658. ucMonth++;
            659. if(ucMonth>12)
            660. {
            661. ucMonth=12;
            662. }
            663. ucWd1Part2Update=1;//更新顯示
            664. break;
            665. case 3: //日
            666. ucDate++;
            667. if(ucDate>31)
            668. {
            669. ucDate=31;
            670. }
            671. ucWd1Part3Update=1;//更新顯示
            672. break;
            673. }
            674. break;
            675. case 2:
            676. switch(ucPart) //在不同的局部變量下,相當(dāng)于二級菜單
            677. {
            678. case 1://時(shí)
            679. ucHour++;
            680. if(ucHour>23)
            681. {
            682. ucHour=23;
            683. }
            684. ucWd2Part1Update=1;//更新顯示
            685. break;
            686. case 2: //分
            687. ucMinute++;
            688. if(ucMinute>59)
            689. {
            690. ucMinute=59;
            691. }
            692. ucWd2Part2Update=1;//更新顯示
            693. break;
            694. case 3: //秒
            695. ucSecond++;
            696. if(ucSecond>59)
            697. {
            698. ucSecond=59;
            699. }
            700. ucWd2Part3Update=1;//更新顯示
            701. break;
            702. }
            703. break;
            704. }
            705. ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            706. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
            707. ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            708. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
            709. break;
            710. case 2:// 減按鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S5鍵
            711. switch(ucWd)//在不同的窗口下,設(shè)置不同的參數(shù)
            712. {
            713. case 1:
            714. switch(ucPart) //在不同的局部變量下,相當(dāng)于二級菜單
            715. {
            716. case 1://年
            717. ucYear--;
            718. if(ucYear>99)
            719. {
            720. ucYear=0;
            721. }
            722. ucWd1Part1Update=1;//更新顯示
            723. break;
            724. case 2: //月
            725. ucMonth--;
            726. if(ucMonth<1)
            727. {
            728. ucMonth=1;
            729. }
            730. ucWd1Part2Update=1;//更新顯示
            731. break;
            732. case 3: //日
            733. ucDate--;
            734. if(ucDate<1)
            735. {
            736. ucDate=1;
            737. }
            738. ucWd1Part3Update=1;//更新顯示
            739. break;
            740. }
            741. break;
            742. case 2:
            743. switch(ucPart) //在不同的局部變量下,相當(dāng)于二級菜單
            744. {
            745. case 1://時(shí)
            746. ucHour--;
            747. if(ucHour>23)
            748. {
            749. ucHour=0;
            750. }
            751. ucWd2Part1Update=1;//更新顯示
            752. break;
            753. case 2: //分
            754. ucMinute--;
            755. if(ucMinute>59)
            756. {
            757. ucMinute=0;
            758. }
            759. ucWd2Part2Update=1;//更新顯示
            760. break;
            761. case 3: //秒
            762. ucSecond--;
            763. if(ucSecond>59)
            764. {
            765. ucSecond=0;
            766. }
            767. ucWd2Part3Update=1;//更新顯示
            768. break;
            769. }
            770. break;
            771. }
            772. ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            773. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
            774. ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            775. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
            776. break;
            777. case 3://短按設(shè)置按鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S9鍵
            778. switch(ucWd)//在不同的窗口下,設(shè)置不同的參數(shù)
            779. {
            780. case 1:
            781. ucPart++;
            782. if(ucPart>3)
            783. {
            784. ucPart=1;
            785. ucWd=2; //切換到第二個(gè)窗口,設(shè)置時(shí)分秒
            786. ucWd2Update=1;//窗口2更新顯示
            787. }
            788. ucWd1Update=1;//窗口1更新顯示
            789. break;
            790. case 2:
            791. if(ucPart>0) //在窗口2的時(shí)候,要第一次激活設(shè)置時(shí)間,必須是長按3秒才可以,這里短按激活不了第一次
            792. {
            793. ucPart++;
            794. if(ucPart>3)//設(shè)置時(shí)間結(jié)束
            795. {
            796. ucPart=0;
            797. /* 注釋五:
            798. * 每個(gè)月份的天數(shù)最大值是不一樣的,在寫入ds1302時(shí)鐘芯片內(nèi)部數(shù)據(jù)前,應(yīng)該做一次調(diào)整。
            799. * 有的月份最大28天,有的月份最大29天,有的月份最大30天,有的月份最大31天,
            800. */
            801. ucDate=date_adjust(ucYear,ucMonth,ucDate); //日調(diào)整 避免日的數(shù)值在某個(gè)月份超范圍
            802. ucYearBCD=number_to_bcd(ucYear);//原始數(shù)值轉(zhuǎn)BCD
            803. ucMonthBCD=number_to_bcd(ucMonth); //原始數(shù)值轉(zhuǎn)BCD
            804. ucDateBCD=number_to_bcd(ucDate);//原始數(shù)值轉(zhuǎn)BCD
            805. ucHourBCD=number_to_bcd(ucHour);//原始數(shù)值轉(zhuǎn)BCD
            806. ucMinuteBCD=number_to_bcd(ucMinute);//原始數(shù)值轉(zhuǎn)BCD
            807. ucSecondBCD=number_to_bcd(ucSecond);//原始數(shù)值轉(zhuǎn)BCD
            808. Write1302 (WRITE_PROTECT,0X00); //禁止寫保護(hù)
            809. Write1302 (WRITE_YEAR,ucYearBCD); //年修改
            810. Write1302 (WRITE_MONTH,ucMonthBCD); //月修改
            811. Write1302 (WRITE_DATE,ucDateBCD); //日修改
            812. Write1302 (WRITE_HOUR,ucHourBCD); //小時(shí)修改
            813. Write1302 (WRITE_MINUTE,ucMinuteBCD); //分鐘修改
            814. Write1302 (WRITE_SECOND,ucSecondBCD); //秒位修改
            815. Write1302 (WRITE_PROTECT,0x80); //允許寫保護(hù)
            816. }
            817. ucWd2Update=1;//窗口2更新顯示
            818. }
            819. break;
            820. }
            821. ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            822. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
            823. ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            824. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
            825. break;
            826. case 17://長按3秒設(shè)置按鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S9鍵
            827. switch(ucWd)//在不同的窗口下,設(shè)置不同的參數(shù)
            828. {
            829. case 2:
            830. if(ucPart==0) //處于非設(shè)置時(shí)間的狀態(tài)下,要第一次激活設(shè)置時(shí)間,必須是長按3秒才可以
            831. {
            832. ucWd=1;
            833. ucPart=1;//進(jìn)入到設(shè)置日期的狀態(tài)下
            834. ucWd1Update=1;//窗口1更新顯示
            835. }
            836. break;
            837. }
            838. ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            839. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
            840. ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            841. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
            842. break;
            843. }
            844. /* 注釋六:
            845. * 注意,此處就是第一次出現(xiàn)的電平按鍵程序,跟以往的下降沿按鍵不一樣。
            846. * ucKey4Sr是經(jīng)過軟件濾波處理后,直接反應(yīng)IO口電平狀態(tài)的變量.當(dāng)電平發(fā)生
            847. * 變化時(shí),就會(huì)切換到不同的顯示界面,這里多用了一個(gè)ucKey4SrRecord變量
            848. * 記錄上一次的電平狀態(tài),是為了避免一直刷新顯示。
            849. */
            850. if(ucKey4Sr!=ucKey4SrRecord)//說明S13的切換按鍵電平狀態(tài)發(fā)生變化
            851. {
            852. ucKey4SrRecord=ucKey4Sr;//及時(shí)記錄當(dāng)前最新的按鍵電平狀態(tài)避免一直進(jìn)來觸發(fā)
            853. if(ucKey4Sr==1) //松手后切換到顯示時(shí)間的窗口
            854. {
            855. ucWd=2; //顯示時(shí)分秒的窗口
            856. ucPart=0;//進(jìn)入到非設(shè)置時(shí)間的狀態(tài)下
            857. ucWd2Update=1;//窗口2更新顯示
            858. }
            859. else//按下去切換到顯示日期的窗口
            860. {
            861. ucWd=1; //顯示年月日的窗口
            862. ucPart=0;//進(jìn)入到非設(shè)置時(shí)間的狀態(tài)下
            863. ucWd1Update=1;//窗口1更新顯示
            864. }
            865. }
            866. }
            867. void display_drive(void)
            868. {
            869. //以下程序,如果加一些數(shù)組和移位的元素,還可以壓縮容量。但是鴻哥追求的不是容量,而是清晰的講解思路
            870. switch(ucDisplayDriveStep)
            871. {
            872. case 1://顯示第1位
            873. ucDigShowTemp=dig_table[ucDigShow1];
            874. if(ucDigDot1==1)
            875. {
            876. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            877. }
            878. dig_hc595_drive(ucDigShowTemp,0xfe);
            879. break;
            880. case 2://顯示第2位
            881. ucDigShowTemp=dig_table[ucDigShow2];
            882. if(ucDigDot2==1)
            883. {
            884. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            885. }
            886. dig_hc595_drive(ucDigShowTemp,0xfd);
            887. break;
            888. case 3://顯示第3位
            889. ucDigShowTemp=dig_table[ucDigShow3];
            890. if(ucDigDot3==1)
            891. {
            892. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            893. }
            894. dig_hc595_drive(ucDigShowTemp,0xfb);
            895. break;
            896. case 4://顯示第4位
            897. ucDigShowTemp=dig_table[ucDigShow4];
            898. if(ucDigDot4==1)
            899. {
            900. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            901. }
            902. dig_hc595_drive(ucDigShowTemp,0xf7);
            903. break;
            904. case 5://顯示第5位
            905. ucDigShowTemp=dig_table[ucDigShow5];
            906. if(ucDigDot5==1)
            907. {
            908. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            909. }
            910. dig_hc595_drive(ucDigShowTemp,0xef);
            911. break;
            912. case 6://顯示第6位
            913. ucDigShowTemp=dig_table[ucDigShow6];
            914. if(ucDigDot6==1)
            915. {
            916. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            917. }
            918. dig_hc595_drive(ucDigShowTemp,0xdf);
            919. break;
            920. case 7://顯示第7位
            921. ucDigShowTemp=dig_table[ucDigShow7];
            922. if(ucDigDot7==1)
            923. {
            924. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            925. }
            926. dig_hc595_drive(ucDigShowTemp,0xbf);
            927. break;
            928. case 8://顯示第8位
            929. ucDigShowTemp=dig_table[ucDigShow8];
            930. if(ucDigDot8==1)
            931. {
            932. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            933. }
            934. dig_hc595_drive(ucDigShowTemp,0x7f);
            935. break;
            936. }
            937. ucDisplayDriveStep++;
            938. if(ucDisplayDriveStep>8)//掃描完8個(gè)數(shù)碼管后,重新從第一個(gè)開始掃描
            939. {
            940. ucDisplayDriveStep=1;
            941. }
            942. }
            943. //數(shù)碼管的74HC595驅(qū)動(dòng)函數(shù)
            944. void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01)
            945. {
            946. unsigned char i;
            947. unsigned char ucTempData;
            948. dig_hc595_sh_dr=0;
            949. dig_hc595_st_dr=0;
            950. ucTempData=ucDigStatusTemp16_09;//先送高8位
            951. for(i=0;i<8;i++)
            952. {
            953. if(ucTempData>=0x80)dig_hc595_ds_dr=1;
            954. else dig_hc595_ds_dr=0;
            955. dig_hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
            956. delay_short(1);
            957. dig_hc595_sh_dr=1;
            958. delay_short(1);
            959. ucTempData=ucTempData<<1;
            960. }
            961. ucTempData=ucDigStatusTemp08_01;//再先送低8位
            962. for(i=0;i<8;i++)
            963. {
            964. if(ucTempData>=0x80)dig_hc595_ds_dr=1;
            965. else dig_hc595_ds_dr=0;
            966. dig_hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
            967. delay_short(1);
            968. dig_hc595_sh_dr=1;
            969. delay_short(1);
            970. ucTempData=ucTempData<<1;
            971. }
            972. dig_hc595_st_dr=0;//ST引腳把兩個(gè)寄存器的數(shù)據(jù)更新輸出到74HC595的輸出引腳上并且鎖存起來
            973. delay_short(1);
            974. dig_hc595_st_dr=1;
            975. delay_short(1);
            976. dig_hc595_sh_dr=0; //拉低,抗干擾就增強(qiáng)
            977. dig_hc595_st_dr=0;
            978. dig_hc595_ds_dr=0;
            979. }
            980. //LED燈的74HC595驅(qū)動(dòng)函數(shù)
            981. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01)
            982. {
            983. unsigned char i;
            984. unsigned char ucTempData;
            985. hc595_sh_dr=0;
            986. hc595_st_dr=0;
            987. ucTempData=ucLedStatusTemp16_09;//先送高8位
            988. for(i=0;i<8;i++)
            989. {
            990. if(ucTempData>=0x80)hc595_ds_dr=1;
            991. else hc595_ds_dr=0;
            992. hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
            993. delay_short(1);
            994. hc595_sh_dr=1;
            995. delay_short(1);
            996. ucTempData=ucTempData<<1;
            997. }
            998. ucTempData=ucLedStatusTemp08_01;//再先送低8位
            999. for(i=0;i<8;i++)
            1000. {
            1001. if(ucTempData>=0x80)hc595_ds_dr=1;
            1002. else hc595_ds_dr=0;
            1003. hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
            1004. delay_short(1);
            1005. hc595_sh_dr=1;
            1006. delay_short(1);
            1007. ucTempData=ucTempData<<1;
            1008. }
            1009. hc595_st_dr=0;//ST引腳把兩個(gè)寄存器的數(shù)據(jù)更新輸出到74HC595的輸出引腳上并且鎖存起來
            1010. delay_short(1);
            1011. hc595_st_dr=1;
            1012. delay_short(1);
            1013. hc595_sh_dr=0; //拉低,抗干擾就增強(qiáng)
            1014. hc595_st_dr=0;
            1015. hc595_ds_dr=0;
            1016. }
            1017. void T0_time(void) interrupt 1 //定時(shí)中斷
            1018. {
            1019. TF0=0;//清除中斷標(biāo)志
            1020. TR0=0; //關(guān)中斷
            1021. if(ucVoiceLock==0) //原子鎖判斷
            1022. {
            1023. if(uiVoiceCnt!=0)
            1024. {
            1025. uiVoiceCnt--; //每次進(jìn)入定時(shí)中斷都自減1,直到等于零為止。才停止鳴叫
            1026. beep_dr=0;//蜂鳴器是PNP三極管控制,低電平就開始鳴叫。
            1027. }
            1028. else
            1029. {
            1030. ; //此處多加一個(gè)空指令,想維持跟if括號語句的數(shù)量對稱,都是兩條指令。不加也可以。
            1031. beep_dr=1;//蜂鳴器是PNP三極管控制,高電平就停止鳴叫。
            1032. }
            1033. }
            1034. if(ucDs1302Error>0) //EEPROM出錯(cuò)
            1035. {
            1036. if(ucDs1302Lock==0)//原子鎖判斷
            1037. {
            1038. uiDs1302Cnt++;//間歇性蜂鳴器報(bào)警的計(jì)時(shí)器
            1039. }
            1040. }
            1041. if(ucDpyTimeLock==0) //原子鎖判斷
            1042. {
            1043. uiDpyTimeCnt++;//數(shù)碼管的閃爍計(jì)時(shí)器
            1044. }
            1045. key_scan(); //按鍵掃描函數(shù)
            1046. display_drive();//數(shù)碼管字模的驅(qū)動(dòng)函數(shù)
            1047. TH0=0xfe; //重裝初始值(65535-500)=65035=0xfe0b
            1048. TL0=0x0b;
            1049. TR0=1;//開中斷
            1050. }
            1051. void delay_short(unsigned int uiDelayShort)
            1052. {
            1053. unsigned int i;
            1054. for(i=0;i
            1055. {
            1056. ; //一個(gè)分號相當(dāng)于執(zhí)行一條空語句
            1057. }
            1058. }
            1059. void delay_long(unsigned int uiDelayLong)
            1060. {
            1061. unsigned int i;
            1062. unsigned int j;
            1063. for(i=0;i
            1064. {
            1065. for(j=0;j<500;j++)//內(nèi)嵌循環(huán)的空指令數(shù)量
            1066. {
            1067. ; //一個(gè)分號相當(dāng)于執(zhí)行一條空語句
            1068. }
            1069. }
            1070. }
            1071. void initial_myself(void)//第一區(qū) 初始化單片機(jī)
            1072. {
            1073. key_gnd_dr=0; //模擬獨(dú)立按鍵的地GND,因此必須一直輸出低電平
            1074. beep_dr=1; //用PNP三極管控制蜂鳴器,輸出高電平時(shí)不叫。
            1075. hc595_drive(0x00,0x00);//關(guān)閉所有經(jīng)過另外兩個(gè)74HC595驅(qū)動(dòng)的LED燈
            1076. TMOD=0x01;//設(shè)置定時(shí)器0為工作方式1
            1077. TH0=0xfe; //重裝初始值(65535-500)=65035=0xfe0b
            1078. TL0=0x0b;
            1079. }
            1080. void initial_peripheral(void) //第二區(qū) 初始化外圍
            1081. {
            1082. ucDigDot8=0; //小數(shù)點(diǎn)全部不顯示
            1083. ucDigDot7=0;
            1084. ucDigDot6=0;
            1085. ucDigDot5=0;
            1086. ucDigDot4=0;
            1087. ucDigDot3=0;
            1088. ucDigDot2=0;
            1089. ucDigDot1=0;
            1090. EA=1; //開總中斷
            1091. ET0=1; //允許定時(shí)中斷
            1092. TR0=1; //啟動(dòng)定時(shí)中斷
            1093. /* 注釋七:
            1094. * 檢查ds1302芯片的備用電池電量是否用完了。
            1095. * 在上電的時(shí)候,在一個(gè)特定的地址里把數(shù)據(jù)讀出來,如果發(fā)現(xiàn)不等于0x5a,
            1096. * 則是因?yàn)閭溆秒姵仉娏坑猛炅?,?dǎo)致保存在ds1302內(nèi)部RAM數(shù)據(jù)區(qū)的數(shù)據(jù)被更改,
            1097. * 與此同時(shí),應(yīng)該重新寫入一次0x5a,為下一次通電判斷做準(zhǔn)備
            1098. */
            1099. ucCheckDs1302=Read1302(READ_CHECK); //判斷ds1302內(nèi)部的數(shù)據(jù)是否被更改
            1100. if(ucCheckDs1302!=0x5a)
            1101. {
            1102. Write1302 (WRITE_PROTECT,0X00); //禁止寫保護(hù)
            1103. Write1302 (WRITE_CHECK,0x5a); //重新寫入標(biāo)志數(shù)據(jù),方便下一次更換新電池后的判斷
            1104. Write1302 (WRITE_PROTECT,0x80); //允許寫保護(hù)
            1105. ucDs1302Error=1;//表示ds1302備用電池沒電了,報(bào)警提示更換新電池
            1106. }
            1107. }

            總結(jié)陳詞:
            下一節(jié)開始講單片機(jī)驅(qū)動(dòng)溫度傳感器芯片的內(nèi)容,欲知詳情,請聽下回分解-----利用DS18B20做一個(gè)溫控器。


            評論


            技術(shù)專區(qū)

            關(guān)閉