<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          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ù)都會變成0x00或者0xff,也就是數(shù)據(jù)掉電會丟失,我們可以利用這個(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é)要教會大家六個(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è)按鍵按下去后,如果不松手就會觸發(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按鍵不松手就會切換到顯示日期的第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ù)碼管會閃爍,此時(shí)可以按S1或者S5加減按鍵修改年的參數(shù),修改完年后,繼續(xù)短按S9按鍵,會切換到“月”的參數(shù)閃爍狀態(tài),只要依次不斷按下S9按鍵,就會依次切換年,月,日,時(shí),分,秒的參數(shù)閃爍狀態(tài),最后修改完秒的參數(shù)后,系統(tǒng)會自動(dòng)把我們修改設(shè)置的日期時(shí)間一次性寫入DS1302芯片內(nèi)部,達(dá)到修改日期時(shí)間的目的。
          S13是電平變化按鍵,用來切換窗口的,專門用來查看當(dāng)前日期。按下S13按鍵時(shí)顯示日期窗口,松手后返回到顯示實(shí)時(shí)時(shí)間的窗口。

          本程序在使用過程中的注意事項(xiàng):
          (a)第一次上電時(shí),蜂鳴器會報(bào)警,只要DS1302芯片的備用電池電量充足,這個(gè)時(shí)候斷電再重啟一次,就不會報(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í),就會切換到不同的顯示界面,這里多用了一個(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)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();