在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,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)用 > 第89節(jié):用單片機(jī)內(nèi)部定時(shí)器做一個(gè)時(shí)鐘

            第89節(jié):用單片機(jī)內(nèi)部定時(shí)器做一個(gè)時(shí)鐘

            作者: 時(shí)間:2016-11-22 來源:網(wǎng)絡(luò) 收藏
            開場白:
            很多網(wǎng)友建議,為了方便初學(xué)者學(xué)習(xí)編程思路,我應(yīng)該用單片機(jī)定時(shí)器做一個(gè)時(shí)鐘程序供大家參考學(xué)習(xí)。其實(shí)我前面第48節(jié)就已經(jīng)用ds1302做了一個(gè)可以顯示和更高時(shí)間的時(shí)鐘,這一節(jié)只要在第48節(jié)的源代碼基礎(chǔ)上,大的框架不用動(dòng),只需要把ds1302產(chǎn)生的時(shí)間改成用定時(shí)中斷產(chǎn)生的時(shí)間就可以了,改動(dòng)的地方非常小。但是為了讓時(shí)間的精度更高,最后必須跟標(biāo)準(zhǔn)時(shí)間進(jìn)行校驗(yàn),來修正系統(tǒng)中一秒鐘需要多個(gè)定時(shí)中斷的誤差,這個(gè)誤差決定了系統(tǒng)的時(shí)間精度,其實(shí)這個(gè)校驗(yàn)方法我在前面很多章節(jié)上跟大家介紹過了:
            第一步:在程序代碼上先寫入1秒鐘大概需要200個(gè)定時(shí)中斷。
            第二步:把程序燒錄進(jìn)單片機(jī)后,上電開始測試,手上同步打開手機(jī)里的秒表,當(dāng)手機(jī)的標(biāo)準(zhǔn)時(shí)間跑了780秒(這個(gè)標(biāo)準(zhǔn)時(shí)間跑得越長校驗(yàn)精度越高),而此時(shí)單片機(jī)僅僅跑了1632秒。那么最終得出1秒鐘需要的定時(shí)中斷次數(shù)是:const_time_1s=(200*1632)/780=418。
            第三步:如果發(fā)現(xiàn)時(shí)鐘還是不太準(zhǔn),可以繼續(xù)返回第一步根據(jù)最新1秒鐘的時(shí)間是418次,多校驗(yàn)幾次,來不斷調(diào)整const_time_1s的數(shù)值,直到找到相對精度的時(shí)間為止。
            本系統(tǒng)僅供學(xué)習(xí),精度不可能做得很好,因?yàn)橛绊憰r(shí)間精度的因素還有定時(shí)中斷的重裝值,定時(shí)中斷里面的代碼盡量少,以及晶振等不好控制的因素。所以鴻哥一直不推薦在實(shí)際項(xiàng)目中用單片機(jī)的內(nèi)部定時(shí)器做實(shí)時(shí)時(shí)鐘,因?yàn)榫扔邢蕖U嬲胍獪?zhǔn)確的時(shí)鐘時(shí)間,還是強(qiáng)烈建議大家用外部專用的時(shí)鐘芯片或者用CPLD/FPGA來做。
            具體內(nèi)容,請看源代碼講解。
            (1硬件平臺.
            基于朱兆祺51單片機(jī)學(xué)習(xí)板
            (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í)間一次性更改到定時(shí)中斷函數(shù)內(nèi)部的時(shí)間變量,達(dá)到修改日期時(shí)間的目的。
            S13是電平變化按鍵,用來切換窗口的,專門用來查看當(dāng)前日期。按下S13按鍵時(shí)顯示日期窗口,松手后返回到顯示實(shí)時(shí)時(shí)間的窗口。
            [size=10.5000pt](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. /* 注釋一:
            11. * const_timer_1s這個(gè)是產(chǎn)生多少次定時(shí)中斷才算1秒鐘的標(biāo)準(zhǔn)。這個(gè)標(biāo)準(zhǔn)決定了時(shí)鐘的精度。這個(gè)標(biāo)準(zhǔn)最后是需要校驗(yàn)的。
            12. * 那么是如何檢驗(yàn)的呢?根據(jù)我們前面介紹的校驗(yàn)時(shí)間方法:
            13. * 步驟:
            14. * 第一步:在程序代碼上先寫入1秒鐘大概需要200個(gè)定時(shí)中斷。
            15. * 第二步:把程序燒錄進(jìn)單片機(jī)后,上電開始測試,手上同步打開手機(jī)里的秒表,當(dāng)手機(jī)的標(biāo)準(zhǔn)時(shí)間跑了780秒(這個(gè)標(biāo)準(zhǔn)時(shí)間跑得越長校驗(yàn)精度越高),
            16. * 而此時(shí)單片機(jī)僅僅跑了1632秒。那么最終得出1秒鐘需要的定時(shí)中斷次數(shù)是:const_time_1s=(200*1632)/780=418。
            17. * 第三步:如果發(fā)現(xiàn)時(shí)鐘還是不太準(zhǔn),可以繼續(xù)返回第一步根據(jù)最新1秒鐘的時(shí)間是418次,多校驗(yàn)幾次。本系統(tǒng)僅供學(xué)習(xí),精度不可能做得很好,因?yàn)?/li>
            18. * 影響時(shí)間精度的因素還有定時(shí)中斷的重裝值,定時(shí)中斷里面的代碼盡量少,以及晶振等不好控制的因素。所以鴻哥一直不推薦在實(shí)際項(xiàng)目中
            19. * 用單片機(jī)的內(nèi)部定時(shí)器做實(shí)時(shí)時(shí)鐘,因?yàn)榫扔邢?。真正想要?zhǔn)確的時(shí)鐘時(shí)間,還是強(qiáng)烈建議大家用外部專用的時(shí)鐘芯片或者用CPLD/FPGA來做。
            20. */
            21. //#define const_timer_1s200 //第一次假設(shè)大概1秒的時(shí)間需要200個(gè)定時(shí)中斷
            22. #define const_timer_1s418//第二次校驗(yàn)后,最終選定大概1秒的時(shí)間需要418個(gè)定時(shí)中斷。如果發(fā)現(xiàn)時(shí)間還是不準(zhǔn),可以在此基礎(chǔ)上繼續(xù)校驗(yàn)來調(diào)整此數(shù)據(jù)。
            23. void initial_myself(void);
            24. void initial_peripheral(void);
            25. void delay_short(unsigned int uiDelayShort);
            26. void delay_long(unsigned int uiDelaylong);
            27. //驅(qū)動(dòng)數(shù)碼管的74HC595
            28. void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01);
            29. void display_drive(void); //顯示數(shù)碼管字模的驅(qū)動(dòng)函數(shù)
            30. void display_service(void); //顯示的窗口菜單服務(wù)程序
            31. //驅(qū)動(dòng)LED的74HC595
            32. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01);
            33. void T0_time(void);//定時(shí)中斷函數(shù)
            34. void key_service(void); //按鍵服務(wù)的應(yīng)用程序
            35. void key_scan(void);//按鍵掃描函數(shù) 放在定時(shí)中斷里
            36. void timer_sampling(void); //定時(shí)器采樣程序,內(nèi)部每秒鐘采集更新一次
            37. unsigned char get_date(unsigned char ucYearTemp,unsigned char ucMonthTemp);//獲取當(dāng)前月份的最大天數(shù)
            38. //日調(diào)整 每個(gè)月份的日最大取值不同,有的最大28日,有的最大29日,有的最大30,有的最大31
            39. unsigned char date_adjust(unsigned char ucYearTemp,unsigned char ucMonthTemp,unsigned char ucDateTemp); //日調(diào)整
            40. sbit key_sr1=P0^0; //對應(yīng)朱兆祺學(xué)習(xí)板的S1鍵
            41. sbit key_sr2=P0^1; //對應(yīng)朱兆祺學(xué)習(xí)板的S5鍵
            42. sbit key_sr3=P0^2; //對應(yīng)朱兆祺學(xué)習(xí)板的S9鍵
            43. sbit key_sr4=P0^3; //對應(yīng)朱兆祺學(xué)習(xí)板的S13鍵
            44. sbit key_gnd_dr=P0^4; //模擬獨(dú)立按鍵的地GND,因此必須一直輸出低電平
            45. sbit beep_dr=P2^7; //蜂鳴器的驅(qū)動(dòng)IO口
            46. sbit dig_hc595_sh_dr=P2^0; //數(shù)碼管的74HC595程序
            47. sbit dig_hc595_st_dr=P2^1;
            48. sbit dig_hc595_ds_dr=P2^2;
            49. sbit hc595_sh_dr=P2^3; //LED燈的74HC595程序
            50. sbit hc595_st_dr=P2^4;
            51. sbit hc595_ds_dr=P2^5;
            52. unsigned char ucKeySec=0; //被觸發(fā)的按鍵編號
            53. unsigned intuiKeyTimeCnt1=0; //按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器
            54. unsigned char ucKeyLock1=0; //按鍵觸發(fā)后自鎖的變量標(biāo)志
            55. unsigned intuiKeyTimeCnt2=0; //按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器
            56. unsigned char ucKeyLock2=0; //按鍵觸發(fā)后自鎖的變量標(biāo)志
            57. unsigned intuiKeyTimeCnt3=0; //按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器
            58. unsigned char ucKeyLock3=0; //按鍵觸發(fā)后自鎖的變量標(biāo)志
            59. unsigned int uiKey4Cnt1=0;//在軟件濾波中,用到的變量
            60. unsigned int uiKey4Cnt2=0;
            61. unsigned char ucKey4Sr=1;//實(shí)時(shí)反映按鍵的電平狀態(tài)
            62. unsigned char ucKey4SrRecord=0; //記錄上一次按鍵的電平狀態(tài)
            63. unsigned intuiVoiceCnt=0;//蜂鳴器鳴叫的持續(xù)時(shí)間計(jì)數(shù)器
            64. unsigned charucVoiceLock=0;//蜂鳴器鳴叫的原子鎖
            65. unsigned char ucDigShow8;//第8位數(shù)碼管要顯示的內(nèi)容
            66. unsigned char ucDigShow7;//第7位數(shù)碼管要顯示的內(nèi)容
            67. unsigned char ucDigShow6;//第6位數(shù)碼管要顯示的內(nèi)容
            68. unsigned char ucDigShow5;//第5位數(shù)碼管要顯示的內(nèi)容
            69. unsigned char ucDigShow4;//第4位數(shù)碼管要顯示的內(nèi)容
            70. unsigned char ucDigShow3;//第3位數(shù)碼管要顯示的內(nèi)容
            71. unsigned char ucDigShow2;//第2位數(shù)碼管要顯示的內(nèi)容
            72. unsigned char ucDigShow1;//第1位數(shù)碼管要顯示的內(nèi)容
            73. unsigned char ucDigDot8;//數(shù)碼管8的小數(shù)點(diǎn)是否顯示的標(biāo)志
            74. unsigned char ucDigDot7;//數(shù)碼管7的小數(shù)點(diǎn)是否顯示的標(biāo)志
            75. unsigned char ucDigDot6;//數(shù)碼管6的小數(shù)點(diǎn)是否顯示的標(biāo)志
            76. unsigned char ucDigDot5;//數(shù)碼管5的小數(shù)點(diǎn)是否顯示的標(biāo)志
            77. unsigned char ucDigDot4;//數(shù)碼管4的小數(shù)點(diǎn)是否顯示的標(biāo)志
            78. unsigned char ucDigDot3;//數(shù)碼管3的小數(shù)點(diǎn)是否顯示的標(biāo)志
            79. unsigned char ucDigDot2;//數(shù)碼管2的小數(shù)點(diǎn)是否顯示的標(biāo)志
            80. unsigned char ucDigDot1;//數(shù)碼管1的小數(shù)點(diǎn)是否顯示的標(biāo)志
            81. unsigned char ucDigShowTemp=0; //臨時(shí)中間變量
            82. unsigned char ucDisplayDriveStep=1;//動(dòng)態(tài)掃描數(shù)碼管的步驟變量
            83. unsigned char ucWd=2;//本程序的核心變量,窗口顯示變量。類似于一級菜單的變量。代表顯示不同的窗口。
            84. unsigned char ucPart=0;//本程序的核心變量,局部顯示變量。類似于二級菜單的變量。代表顯示不同的局部。
            85. unsigned char ucWd1Update=0; //窗口1更新顯示標(biāo)志
            86. unsigned char ucWd2Update=1; //窗口2更新顯示標(biāo)志
            87. unsigned char ucWd1Part1Update=0;//在窗口1中,局部1的更新顯示標(biāo)志
            88. unsigned char ucWd1Part2Update=0; //在窗口1中,局部2的更新顯示標(biāo)志
            89. unsigned char ucWd1Part3Update=0; //在窗口1中,局部3的更新顯示標(biāo)志
            90. unsigned char ucWd2Part1Update=0;//在窗口2中,局部1的更新顯示標(biāo)志
            91. unsigned char ucWd2Part2Update=0; //在窗口2中,局部2的更新顯示標(biāo)志
            92. unsigned char ucWd2Part3Update=0; //在窗口2中,局部3的更新顯示標(biāo)志
            93. unsigned charucYear=15; //用來顯示和設(shè)置的時(shí)間變量
            94. unsigned charucMonth=1;
            95. unsigned charucDate=1;
            96. unsigned charucHour=12;
            97. unsigned charucMinute=0;
            98. unsigned charucSecond=0;
            99. unsigned int uiTimerCnt=0; //計(jì)時(shí)器的時(shí)基
            100. unsigned charucTimerYear=15; //在定時(shí)器內(nèi)部時(shí)基產(chǎn)生的時(shí)間變量
            101. unsigned charucTimerMonth=1;
            102. unsigned charucTimerDate=1;
            103. unsigned charucTimerHour=12;
            104. unsigned charucTimerMinute=0;
            105. unsigned charucTimerSecond=0;
            106. unsigned charucTimerDateMax=31; //當(dāng)前月份的最大天數(shù)
            107. unsigned charucTimerUpdate=0; //定時(shí)器每1秒鐘所產(chǎn)生的標(biāo)志
            108. unsigned charucTimerStart=1;//是否打開定時(shí)器內(nèi)部時(shí)間的標(biāo)志,在本程序相當(dāng)于原子鎖的作用。
            109. unsigned char ucTemp1=0;//中間過渡變量
            110. unsigned char ucTemp2=0;//中間過渡變量
            111. unsigned char ucTemp4=0;//中間過渡變量
            112. unsigned char ucTemp5=0;//中間過渡變量
            113. unsigned char ucTemp7=0;//中間過渡變量
            114. unsigned char ucTemp8=0;//中間過渡變量
            115. unsigned char ucDelayTimerLock=0; //原子鎖
            116. unsigned intuiDelayTimer=0;
            117. unsigned char ucDpyTimeLock=0; //原子鎖
            118. unsigned intuiDpyTimeCnt=0;//數(shù)碼管的閃爍計(jì)時(shí)器,放在定時(shí)中斷里不斷累加
            119. //根據(jù)原理圖得出的共陰數(shù)碼管字模表
            120. code unsigned char dig_table[]=
            121. {
            122. 0x3f,//0 序號0
            123. 0x06,//1 序號1
            124. 0x5b,//2 序號2
            125. 0x4f,//3 序號3
            126. 0x66,//4 序號4
            127. 0x6d,//5 序號5
            128. 0x7d,//6 序號6
            129. 0x07,//7 序號7
            130. 0x7f,//8 序號8
            131. 0x6f,//9 序號9
            132. 0x00,//無 序號10
            133. 0x40,//- 序號11
            134. 0x73,//P 序號12
            135. };
            136. void main()
            137. {
            138. initial_myself();
            139. delay_long(100);
            140. initial_peripheral();
            141. while(1)
            142. {
            143. key_service(); //按鍵服務(wù)的應(yīng)用程序
            144. timer_sampling(); //定時(shí)器采樣程序,內(nèi)部每秒鐘采集更新一次
            145. display_service(); //顯示的窗口菜單服務(wù)程序
            146. }
            147. }
            148. /* 注釋二:
            149. * 系統(tǒng)不用時(shí)時(shí)刻刻采集定時(shí)器的內(nèi)部數(shù)據(jù),每隔1秒鐘的時(shí)間更新采集一次就可以了。
            150. * 這個(gè)1秒鐘的時(shí)間是根據(jù)定時(shí)器內(nèi)部ucTimerUpdate變量來判斷。
            151. */
            152. void timer_sampling(void) //采樣定時(shí)器的程序,內(nèi)部每秒鐘采集更新一次
            153. {
            154. if(ucPart==0)//當(dāng)系統(tǒng)不是處于設(shè)置日期和時(shí)間的情況下
            155. {
            156. if(ucTimerUpdate==1)//每隔1秒鐘時(shí)間就更新采集一次定時(shí)器的時(shí)間數(shù)據(jù)
            157. {
            158. ucTimerUpdate=0;//及時(shí)清零,避免一直更新。
            159. ucYear=ucTimerYear; //讀取定時(shí)器內(nèi)部的年
            160. ucMonth=ucTimerMonth; //讀取定時(shí)器內(nèi)部的月
            161. ucDate=ucTimerDate;//讀取定時(shí)器內(nèi)部的日
            162. ucHour=ucTimerHour; //讀取定時(shí)器內(nèi)部的時(shí)
            163. ucMinute=ucTimerMinute;//讀取定時(shí)器內(nèi)部的分
            164. ucSecond=ucTimerSecond;//讀取定時(shí)器內(nèi)部的秒
            165. ucWd2Update=1; //窗口2更新顯示時(shí)間
            166. }
            167. }
            168. }
            169. /* 注釋三:
            170. * 根據(jù)年份和月份來獲取當(dāng)前這個(gè)月的最大天數(shù)。每個(gè)月份的天數(shù)最大取值不同,有的最大28日,
            171. * 有的最大29日,有的最大30,有的最大31。
            172. */
            173. unsigned char get_date(unsigned char ucYearTemp,unsigned char ucMonthTemp)
            174. {
            175. unsigned char ucDayResult;
            176. unsigned int uiYearTemp;
            177. unsigned int uiYearYu;
            178. ucDayResult=31; //默認(rèn)最大是31天,以下根據(jù)不同的年份和月份來決定是否需要修正這個(gè)值
            179. switch(ucMonthTemp)//根據(jù)不同的月份來獲取當(dāng)前月份天數(shù)的最大值
            180. {
            181. case 2://二月份要計(jì)算是否是閏年
            182. uiYearTemp=2000+ucYearTemp;
            183. uiYearYu=uiYearTemp%4;
            184. if(uiYearYu==0) //閏年
            185. {
            186. ucDayResult=29;
            187. }
            188. else
            189. {
            190. ucDayResult=28;
            191. }
            192. break;
            193. case 4:
            194. case 6:
            195. case 9:
            196. case 11:
            197. ucDayResult=30;
            198. break;
            199. }
            200. return ucDayResult;
            201. }
            202. //日調(diào)整 每個(gè)月份的日最大取值不同,有的最大28日,有的最大29日,有的最大30,有的最大31
            203. unsigned char date_adjust(unsigned char ucYearTemp,unsigned char ucMonthTemp,unsigned char ucDateTemp) //日調(diào)整
            204. {
            205. unsigned char ucDayResult;
            206. unsigned int uiYearTemp;
            207. unsigned int uiYearYu;
            208. ucDayResult=ucDateTemp;
            209. switch(ucMonthTemp)//根據(jù)不同的月份來修正不同的日最大值
            210. {
            211. case 2://二月份要計(jì)算是否是閏年
            212. uiYearTemp=2000+ucYearTemp;
            213. uiYearYu=uiYearTemp%4;
            214. if(uiYearYu==0) //閏年
            215. {
            216. if(ucDayResult>29)
            217. {
            218. ucDayResult=29;
            219. }
            220. }
            221. else
            222. {
            223. if(ucDayResult>28)
            224. {
            225. ucDayResult=28;
            226. }
            227. }
            228. break;
            229. case 4:
            230. case 6:
            231. case 9:
            232. case 11:
            233. if(ucDayResult>30)
            234. {
            235. ucDayResult=30;
            236. }
            237. break;
            238. }
            239. return ucDayResult;
            240. }
            241. void display_service(void) //顯示的窗口菜單服務(wù)程序
            242. {
            243. switch(ucWd)//本程序的核心變量,窗口顯示變量。類似于一級菜單的變量。代表顯示不同的窗口。
            244. {
            245. case 1: //顯示日期窗口的數(shù)據(jù)數(shù)據(jù)格式 NN-YY-RR 年-月-日
            246. if(ucWd1Update==1)//窗口1要全部更新顯示
            247. {
            248. ucWd1Update=0;//及時(shí)清零標(biāo)志,避免一直進(jìn)來掃描
            249. ucDigShow6=11;//顯示一杠"-"
            250. ucDigShow3=11;//顯示一杠"-"
            251. ucWd1Part1Update=1;//局部年更新顯示
            252. ucWd1Part2Update=1;//局部月更新顯示
            253. ucWd1Part3Update=1;//局部日更新顯示
            254. }
            255. if(ucWd1Part1Update==1)//局部年更新顯示
            256. {
            257. ucWd1Part1Update=0;
            258. ucTemp8=ucYear/10;//年
            259. ucTemp7=ucYear%10;
            260. ucDigShow8=ucTemp8; //數(shù)碼管顯示實(shí)際內(nèi)容
            261. ucDigShow7=ucTemp7;
            262. }
            263. if(ucWd1Part2Update==1)//局部月更新顯示
            264. {
            265. ucWd1Part2Update=0;
            266. ucTemp5=ucMonth/10;//月
            267. ucTemp4=ucMonth%10;
            268. ucDigShow5=ucTemp5; //數(shù)碼管顯示實(shí)際內(nèi)容
            269. ucDigShow4=ucTemp4;
            270. }
            271. if(ucWd1Part3Update==1) //局部日更新顯示
            272. {
            273. ucWd1Part3Update=0;
            274. ucTemp2=ucDate/10;//日
            275. ucTemp1=ucDate%10;
            276. ucDigShow2=ucTemp2; //數(shù)碼管顯示實(shí)際內(nèi)容
            277. ucDigShow1=ucTemp1;
            278. }
            279. //數(shù)碼管閃爍
            280. switch(ucPart)//相當(dāng)于二級菜單,根據(jù)局部變量的值,使對應(yīng)的參數(shù)產(chǎn)生閃爍的動(dòng)態(tài)效果。
            281. {
            282. case 0://都不閃爍
            283. break;
            284. case 1://年參數(shù)閃爍
            285. if(uiDpyTimeCnt==const_dpy_time_half)
            286. {
            287. ucDigShow8=ucTemp8; //數(shù)碼管顯示實(shí)際內(nèi)容
            288. ucDigShow7=ucTemp7;
            289. }
            290. else if(uiDpyTimeCnt>const_dpy_time_all) //const_dpy_time_all一定要比const_dpy_time_half 大
            291. {
            292. ucDpyTimeLock=1; //原子鎖加鎖
            293. uiDpyTimeCnt=0; //及時(shí)把閃爍記時(shí)器清零
            294. ucDpyTimeLock=0;//原子鎖解鎖
            295. ucDigShow8=10; //數(shù)碼管顯示空,什么都不顯示
            296. ucDigShow7=10;
            297. }
            298. break;
            299. case 2: //月參數(shù)閃爍
            300. if(uiDpyTimeCnt==const_dpy_time_half)
            301. {
            302. ucDigShow5=ucTemp5; //數(shù)碼管顯示實(shí)際內(nèi)容
            303. ucDigShow4=ucTemp4;
            304. }
            305. else if(uiDpyTimeCnt>const_dpy_time_all) //const_dpy_time_all一定要比const_dpy_time_half 大
            306. {
            307. ucDpyTimeLock=1; //原子鎖加鎖
            308. uiDpyTimeCnt=0; //及時(shí)把閃爍記時(shí)器清零
            309. ucDpyTimeLock=0;//原子鎖解鎖
            310. ucDigShow5=10; //數(shù)碼管顯示空,什么都不顯示
            311. ucDigShow4=10;
            312. }
            313. break;
            314. case 3: //日參數(shù)閃爍
            315. if(uiDpyTimeCnt==const_dpy_time_half)
            316. {
            317. ucDigShow2=ucTemp2; //數(shù)碼管顯示實(shí)際內(nèi)容
            318. ucDigShow1=ucTemp1;
            319. }
            320. else if(uiDpyTimeCnt>const_dpy_time_all) //const_dpy_time_all一定要比const_dpy_time_half 大
            321. {
            322. ucDpyTimeLock=1; //原子鎖加鎖
            323. uiDpyTimeCnt=0; //及時(shí)把閃爍記時(shí)器清零
            324. ucDpyTimeLock=0;//原子鎖解鎖
            325. ucDigShow2=10; //數(shù)碼管顯示空,什么都不顯示
            326. ucDigShow1=10;
            327. }
            328. break;
            329. }
            330. break;
            331. case 2: //顯示時(shí)間窗口的數(shù)據(jù)數(shù)據(jù)格式 SS FF MM 時(shí) 分 秒
            332. if(ucWd2Update==1)//窗口2要全部更新顯示
            333. {
            334. ucWd2Update=0;//及時(shí)清零標(biāo)志,避免一直進(jìn)來掃描
            335. ucDigShow6=10;//顯示空
            336. ucDigShow3=10;//顯示空
            337. ucWd2Part3Update=1;//局部時(shí)更新顯示
            338. ucWd2Part2Update=1;//局部分更新顯示
            339. ucWd2Part1Update=1;//局部秒更新顯示
            340. }
            341. if(ucWd2Part1Update==1)//局部時(shí)更新顯示
            342. {
            343. ucWd2Part1Update=0;
            344. ucTemp8=ucHour/10;//時(shí)
            345. ucTemp7=ucHour%10;
            346. ucDigShow8=ucTemp8; //數(shù)碼管顯示實(shí)際內(nèi)容
            347. ucDigShow7=ucTemp7;
            348. }
            349. if(ucWd2Part2Update==1)//局部分更新顯示
            350. {
            351. ucWd2Part2Update=0;
            352. ucTemp5=ucMinute/10;//分
            353. ucTemp4=ucMinute%10;
            354. ucDigShow5=ucTemp5; //數(shù)碼管顯示實(shí)際內(nèi)容
            355. ucDigShow4=ucTemp4;
            356. }
            357. if(ucWd2Part3Update==1) //局部秒更新顯示
            358. {
            359. ucWd2Part3Update=0;
            360. ucTemp2=ucSecond/10;//秒
            361. ucTemp1=ucSecond%10;
            362. ucDigShow2=ucTemp2; //數(shù)碼管顯示實(shí)際內(nèi)容
            363. ucDigShow1=ucTemp1;
            364. }
            365. //數(shù)碼管閃爍
            366. switch(ucPart)//相當(dāng)于二級菜單,根據(jù)局部變量的值,使對應(yīng)的參數(shù)產(chǎn)生閃爍的動(dòng)態(tài)效果。
            367. {
            368. case 0://都不閃爍
            369. break;
            370. case 1://時(shí)參數(shù)閃爍
            371. if(uiDpyTimeCnt==const_dpy_time_half)
            372. {
            373. ucDigShow8=ucTemp8; //數(shù)碼管顯示實(shí)際內(nèi)容
            374. ucDigShow7=ucTemp7;
            375. }
            376. else if(uiDpyTimeCnt>const_dpy_time_all) //const_dpy_time_all一定要比const_dpy_time_half 大
            377. {
            378. ucDpyTimeLock=1; //原子鎖加鎖
            379. uiDpyTimeCnt=0; //及時(shí)把閃爍記時(shí)器清零
            380. ucDpyTimeLock=0;//原子鎖解鎖
            381. ucDigShow8=10; //數(shù)碼管顯示空,什么都不顯示
            382. ucDigShow7=10;
            383. }
            384. break;
            385. case 2: //分參數(shù)閃爍
            386. if(uiDpyTimeCnt==const_dpy_time_half)
            387. {
            388. ucDigShow5=ucTemp5; //數(shù)碼管顯示實(shí)際內(nèi)容
            389. ucDigShow4=ucTemp4;
            390. }
            391. else if(uiDpyTimeCnt>const_dpy_time_all) //const_dpy_time_all一定要比const_dpy_time_half 大
            392. {
            393. ucDpyTimeLock=1; //原子鎖加鎖
            394. uiDpyTimeCnt=0; //及時(shí)把閃爍記時(shí)器清零
            395. ucDpyTimeLock=0;//原子鎖解鎖
            396. ucDigShow5=10; //數(shù)碼管顯示空,什么都不顯示
            397. ucDigShow4=10;
            398. }
            399. break;
            400. case 3: //秒?yún)?shù)閃爍
            401. if(uiDpyTimeCnt==const_dpy_time_half)
            402. {
            403. ucDigShow2=ucTemp2; //數(shù)碼管顯示實(shí)際內(nèi)容
            404. ucDigShow1=ucTemp1;
            405. }
            406. else if(uiDpyTimeCnt>const_dpy_time_all) //const_dpy_time_all一定要比const_dpy_time_half 大
            407. {
            408. ucDpyTimeLock=1; //原子鎖加鎖
            409. uiDpyTimeCnt=0; //及時(shí)把閃爍記時(shí)器清零
            410. ucDpyTimeLock=0;//原子鎖解鎖
            411. ucDigShow2=10; //數(shù)碼管顯示空,什么都不顯示
            412. ucDigShow1=10;
            413. }
            414. break;
            415. }
            416. break;
            417. }
            418. }
            419. void key_scan(void)//按鍵掃描函數(shù) 放在定時(shí)中斷里
            420. {
            421. if(key_sr1==1)//IO是高電平,說明按鍵沒有被按下,這時(shí)要及時(shí)清零一些標(biāo)志位
            422. {
            423. ucKeyLock1=0; //按鍵自鎖標(biāo)志清零
            424. uiKeyTimeCnt1=0;//按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器清零,此行非常巧妙,是我實(shí)戰(zhàn)中摸索出來的。
            425. }
            426. else if(ucKeyLock1==0)//有按鍵按下,且是第一次被按下
            427. {
            428. uiKeyTimeCnt1++; //累加定時(shí)中斷次數(shù)
            429. if(uiKeyTimeCnt1>const_key_time1)
            430. {
            431. uiKeyTimeCnt1=0;
            432. ucKeyLock1=1;//自鎖按鍵置位,避免一直觸發(fā)
            433. ucKeySec=1; //觸發(fā)1號鍵
            434. }
            435. }
            436. if(key_sr2==1)//IO是高電平,說明按鍵沒有被按下,這時(shí)要及時(shí)清零一些標(biāo)志位
            437. {
            438. ucKeyLock2=0; //按鍵自鎖標(biāo)志清零
            439. uiKeyTimeCnt2=0;//按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器清零,此行非常巧妙,是我實(shí)戰(zhàn)中摸索出來的。
            440. }
            441. else if(ucKeyLock2==0)//有按鍵按下,且是第一次被按下
            442. {
            443. uiKeyTimeCnt2++; //累加定時(shí)中斷次數(shù)
            444. if(uiKeyTimeCnt2>const_key_time2)
            445. {
            446. uiKeyTimeCnt2=0;
            447. ucKeyLock2=1;//自鎖按鍵置位,避免一直觸發(fā)
            448. ucKeySec=2; //觸發(fā)2號鍵
            449. }
            450. }
            451. /* 注釋四:
            452. * 注意,此處把一個(gè)按鍵的短按和長按的功能都實(shí)現(xiàn)了。
            453. */
            454. if(key_sr3==1)//IO是高電平,說明按鍵沒有被按下,這時(shí)要及時(shí)清零一些標(biāo)志位
            455. {
            456. ucKeyLock3=0; //按鍵自鎖標(biāo)志清零
            457. uiKeyTimeCnt3=0;//按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器清零,此行非常巧妙,是我實(shí)戰(zhàn)中摸索出來的。
            458. }
            459. else if(ucKeyLock3==0)//有按鍵按下,且是第一次被按下
            460. {
            461. uiKeyTimeCnt3++; //累加定時(shí)中斷次數(shù)
            462. if(uiKeyTimeCnt3>const_key_time3)
            463. {
            464. uiKeyTimeCnt3=0;
            465. ucKeyLock3=1;//自鎖按鍵置位,避免一直觸發(fā)
            466. ucKeySec=3; //短按觸發(fā)3號鍵
            467. }
            468. }
            469. else if(uiKeyTimeCnt3
            470. {
            471. uiKeyTimeCnt3++; //累加定時(shí)中斷次數(shù)
            472. if(uiKeyTimeCnt3==const_key_time17)//等于3秒鐘,觸發(fā)17號長按按鍵
            473. {
            474. ucKeySec=17; //長按3秒觸發(fā)17號鍵
            475. }
            476. }
            477. /* 注釋五:
            478. * 注意,此處是電平按鍵的濾波抗干擾處理
            479. */
            480. if(key_sr4==1)//對應(yīng)朱兆祺學(xué)習(xí)板的S13鍵
            481. {
            482. uiKey4Cnt1=0; //在軟件濾波中,非常關(guān)鍵的語句!?。☆愃瓢存I去抖動(dòng)程序的及時(shí)清零
            483. uiKey4Cnt2++; //類似獨(dú)立按鍵去抖動(dòng)的軟件抗干擾處理
            484. if(uiKey4Cnt2>const_key_time4)
            485. {
            486. uiKey4Cnt2=0;
            487. ucKey4Sr=1;//實(shí)時(shí)反映按鍵松手時(shí)的電平狀態(tài)
            488. }
            489. }
            490. else
            491. {
            492. uiKey4Cnt2=0; //在軟件濾波中,非常關(guān)鍵的語句?。。☆愃瓢存I去抖動(dòng)程序的及時(shí)清零
            493. uiKey4Cnt1++;
            494. if(uiKey4Cnt1>const_key_time4)
            495. {
            496. uiKey4Cnt1=0;
            497. ucKey4Sr=0;//實(shí)時(shí)反映按鍵按下時(shí)的電平狀態(tài)
            498. }
            499. }
            500. }
            501. void key_service(void) //按鍵服務(wù)的應(yīng)用程序
            502. {
            503. switch(ucKeySec) //按鍵服務(wù)狀態(tài)切換
            504. {
            505. case 1:// 加按鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S1鍵
            506. switch(ucWd)//在不同的窗口下,設(shè)置不同的參數(shù)
            507. {
            508. case 1:
            509. switch(ucPart) //在不同的局部變量下,相當(dāng)于二級菜單
            510. {
            511. case 1://年
            512. ucYear++;
            513. if(ucYear>99)
            514. {
            515. ucYear=99;
            516. }
            517. ucWd1Part1Update=1;//更新顯示
            518. break;
            519. case 2: //月
            520. ucMonth++;
            521. if(ucMonth>12)
            522. {
            523. ucMonth=12;
            524. }
            525. ucWd1Part2Update=1;//更新顯示
            526. break;
            527. case 3: //日
            528. ucDate++;
            529. if(ucDate>31)
            530. {
            531. ucDate=31;
            532. }
            533. ucWd1Part3Update=1;//更新顯示
            534. break;
            535. }
            536. break;
            537. case 2:
            538. switch(ucPart) //在不同的局部變量下,相當(dāng)于二級菜單
            539. {
            540. case 1://時(shí)
            541. ucHour++;
            542. if(ucHour>23)
            543. {
            544. ucHour=23;
            545. }
            546. ucWd2Part1Update=1;//更新顯示
            547. break;
            548. case 2: //分
            549. ucMinute++;
            550. if(ucMinute>59)
            551. {
            552. ucMinute=59;
            553. }
            554. ucWd2Part2Update=1;//更新顯示
            555. break;
            556. case 3: //秒
            557. ucSecond++;
            558. if(ucSecond>59)
            559. {
            560. ucSecond=59;
            561. }
            562. ucWd2Part3Update=1;//更新顯示
            563. break;
            564. }
            565. break;
            566. }
            567. ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            568. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
            569. ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            570. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
            571. break;
            572. case 2:// 減按鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S5鍵
            573. switch(ucWd)//在不同的窗口下,設(shè)置不同的參數(shù)
            574. {
            575. case 1:
            576. switch(ucPart) //在不同的局部變量下,相當(dāng)于二級菜單
            577. {
            578. case 1://年
            579. ucYear--;
            580. if(ucYear>99)
            581. {
            582. ucYear=0;
            583. }
            584. ucWd1Part1Update=1;//更新顯示
            585. break;
            586. case 2: //月
            587. ucMonth--;
            588. if(ucMonth<1)
            589. {
            590. ucMonth=1;
            591. }
            592. ucWd1Part2Update=1;//更新顯示
            593. break;
            594. case 3: //日
            595. ucDate--;
            596. if(ucDate<1)
            597. {
            598. ucDate=1;
            599. }
            600. ucWd1Part3Update=1;//更新顯示
            601. break;
            602. }
            603. break;
            604. case 2:
            605. switch(ucPart) //在不同的局部變量下,相當(dāng)于二級菜單
            606. {
            607. case 1://時(shí)
            608. ucHour--;
            609. if(ucHour>23)
            610. {
            611. ucHour=0;
            612. }
            613. ucWd2Part1Update=1;//更新顯示
            614. break;
            615. case 2: //分
            616. ucMinute--;
            617. if(ucMinute>59)
            618. {
            619. ucMinute=0;
            620. }
            621. ucWd2Part2Update=1;//更新顯示
            622. break;
            623. case 3: //秒
            624. ucSecond--;
            625. if(ucSecond>59)
            626. {
            627. ucSecond=0;
            628. }
            629. ucWd2Part3Update=1;//更新顯示
            630. break;
            631. }
            632. break;
            633. }
            634. ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            635. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
            636. ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            637. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
            638. break;
            639. case 3://短按設(shè)置按鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S9鍵
            640. switch(ucWd)//在不同的窗口下,設(shè)置不同的參數(shù)
            641. {
            642. case 1:
            643. ucPart++;
            644. if(ucPart>3)
            645. {
            646. ucPart=1;
            647. ucWd=2; //切換到第二個(gè)窗口,設(shè)置時(shí)分秒
            648. ucWd2Update=1;//窗口2更新顯示
            649. }
            650. ucWd1Update=1;//窗口1更新顯示
            651. break;
            652. case 2:
            653. if(ucPart>0) //在窗口2的時(shí)候,要第一次激活設(shè)置時(shí)間,必須是長按3秒才可以,這里短按激活不了第一次
            654. {
            655. ucPart++;
            656. if(ucPart>3)//設(shè)置時(shí)間結(jié)束
            657. {
            658. ucPart=0;
            659. /* 注釋六:
            660. * 每個(gè)月份的天數(shù)最大值是不一樣的,在寫入ds1302時(shí)鐘芯片內(nèi)部數(shù)據(jù)前,應(yīng)該做一次調(diào)整。
            661. * 有的月份最大28天,有的月份最大29天,有的月份最大30天,有的月份最大31天,
            662. */
            663. ucDate=date_adjust(ucYear,ucMonth,ucDate); //日調(diào)整 避免日的數(shù)值在某個(gè)月份超范圍
            664. ucTimerStart=0;//關(guān)閉定時(shí)器的時(shí)間。在更改定時(shí)器內(nèi)部時(shí)間數(shù)據(jù)時(shí),先關(guān)閉它,相當(dāng)于原子鎖的加鎖作用。
            665. ucTimerYear=ucYear;//把設(shè)置和顯示的數(shù)據(jù)更改到定時(shí)器內(nèi)部的時(shí)間變量
            666. ucTimerMonth=ucMonth;
            667. ucTimerDate=ucDate;
            668. ucTimerHour=ucHour;
            669. ucTimerMinute=ucMinute;
            670. ucTimerSecond=ucSecond;
            671. ucTimerStart=1;//打開定時(shí)器的時(shí)間。在更改定時(shí)器內(nèi)部時(shí)間數(shù)據(jù)后,再打開它,相當(dāng)于原子鎖的解鎖作用。
            672. }
            673. ucWd2Update=1;//窗口2更新顯示
            674. }
            675. break;
            676. }
            677. ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            678. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
            679. ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            680. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
            681. break;
            682. case 17://長按3秒設(shè)置按鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S9鍵
            683. switch(ucWd)//在不同的窗口下,設(shè)置不同的參數(shù)
            684. {
            685. case 2:
            686. if(ucPart==0) //處于非設(shè)置時(shí)間的狀態(tài)下,要第一次激活設(shè)置時(shí)間,必須是長按3秒才可以
            687. {
            688. ucWd=1;
            689. ucPart=1;//進(jìn)入到設(shè)置日期的狀態(tài)下
            690. ucWd1Update=1;//窗口1更新顯示
            691. }
            692. break;
            693. }
            694. ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            695. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
            696. ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
            697. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
            698. break;
            699. }
            700. /* 注釋七:
            701. * 注意,此處就是第一次出現(xiàn)的電平按鍵程序,跟以往的下降沿按鍵不一樣。
            702. * ucKey4Sr是經(jīng)過軟件濾波處理后,直接反應(yīng)IO口電平狀態(tài)的變量.當(dāng)電平發(fā)生
            703. * 變化時(shí),就會(huì)切換到不同的顯示界面,這里多用了一個(gè)ucKey4SrRecord變量
            704. * 記錄上一次的電平狀態(tài),是為了避免一直刷新顯示。
            705. */
            706. if(ucKey4Sr!=ucKey4SrRecord)//說明S13的切換按鍵電平狀態(tài)發(fā)生變化
            707. {
            708. ucKey4SrRecord=ucKey4Sr;//及時(shí)記錄當(dāng)前最新的按鍵電平狀態(tài)避免一直進(jìn)來觸發(fā)
            709. if(ucKey4Sr==1) //松手后切換到顯示時(shí)間的窗口
            710. {
            711. ucWd=2; //顯示時(shí)分秒的窗口
            712. ucPart=0;//進(jìn)入到非設(shè)置時(shí)間的狀態(tài)下
            713. ucWd2Update=1;//窗口2更新顯示
            714. }
            715. else//按下去切換到顯示日期的窗口
            716. {
            717. ucWd=1; //顯示年月日的窗口
            718. ucPart=0;//進(jìn)入到非設(shè)置時(shí)間的狀態(tài)下
            719. ucWd1Update=1;//窗口1更新顯示
            720. }
            721. }
            722. }
            723. void display_drive(void)
            724. {
            725. //以下程序,如果加一些數(shù)組和移位的元素,還可以壓縮容量。但是鴻哥追求的不是容量,而是清晰的講解思路
            726. switch(ucDisplayDriveStep)
            727. {
            728. case 1://顯示第1位
            729. ucDigShowTemp=dig_table[ucDigShow1];
            730. if(ucDigDot1==1)
            731. {
            732. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            733. }
            734. dig_hc595_drive(ucDigShowTemp,0xfe);
            735. break;
            736. case 2://顯示第2位
            737. ucDigShowTemp=dig_table[ucDigShow2];
            738. if(ucDigDot2==1)
            739. {
            740. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            741. }
            742. dig_hc595_drive(ucDigShowTemp,0xfd);
            743. break;
            744. case 3://顯示第3位
            745. ucDigShowTemp=dig_table[ucDigShow3];
            746. if(ucDigDot3==1)
            747. {
            748. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            749. }
            750. dig_hc595_drive(ucDigShowTemp,0xfb);
            751. break;
            752. case 4://顯示第4位
            753. ucDigShowTemp=dig_table[ucDigShow4];
            754. if(ucDigDot4==1)
            755. {
            756. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            757. }
            758. dig_hc595_drive(ucDigShowTemp,0xf7);
            759. break;
            760. case 5://顯示第5位
            761. ucDigShowTemp=dig_table[ucDigShow5];
            762. if(ucDigDot5==1)
            763. {
            764. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            765. }
            766. dig_hc595_drive(ucDigShowTemp,0xef);
            767. break;
            768. case 6://顯示第6位
            769. ucDigShowTemp=dig_table[ucDigShow6];
            770. if(ucDigDot6==1)
            771. {
            772. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            773. }
            774. dig_hc595_drive(ucDigShowTemp,0xdf);
            775. break;
            776. case 7://顯示第7位
            777. ucDigShowTemp=dig_table[ucDigShow7];
            778. if(ucDigDot7==1)
            779. {
            780. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            781. }
            782. dig_hc595_drive(ucDigShowTemp,0xbf);
            783. break;
            784. case 8://顯示第8位
            785. ucDigShowTemp=dig_table[ucDigShow8];
            786. if(ucDigDot8==1)
            787. {
            788. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
            789. }
            790. dig_hc595_drive(ucDigShowTemp,0x7f);
            791. break;
            792. }
            793. ucDisplayDriveStep++;
            794. if(ucDisplayDriveStep>8)//掃描完8個(gè)數(shù)碼管后,重新從第一個(gè)開始掃描
            795. {
            796. ucDisplayDriveStep=1;
            797. }
            798. }
            799. //數(shù)碼管的74HC595驅(qū)動(dòng)函數(shù)
            800. void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01)
            801. {
            802. unsigned char i;
            803. unsigned char ucTempData;
            804. dig_hc595_sh_dr=0;
            805. dig_hc595_st_dr=0;
            806. ucTempData=ucDigStatusTemp16_09;//先送高8位
            807. for(i=0;i<8;i++)
            808. {
            809. if(ucTempData>=0x80)dig_hc595_ds_dr=1;
            810. else dig_hc595_ds_dr=0;
            811. dig_hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
            812. delay_short(1);
            813. dig_hc595_sh_dr=1;
            814. delay_short(1);
            815. ucTempData=ucTempData<<1;
            816. }
            817. ucTempData=ucDigStatusTemp08_01;//再先送低8位
            818. for(i=0;i<8;i++)
            819. {
            820. if(ucTempData>=0x80)dig_hc595_ds_dr=1;
            821. else dig_hc595_ds_dr=0;
            822. dig_hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
            823. delay_short(1);
            824. dig_hc595_sh_dr=1;
            825. delay_short(1);
            826. ucTempData=ucTempData<<1;
            827. }
            828. dig_hc595_st_dr=0;//ST引腳把兩個(gè)寄存器的數(shù)據(jù)更新輸出到74HC595的輸出引腳上并且鎖存起來
            829. delay_short(1);
            830. dig_hc595_st_dr=1;
            831. delay_short(1);
            832. dig_hc595_sh_dr=0; //拉低,抗干擾就增強(qiáng)
            833. dig_hc595_st_dr=0;
            834. dig_hc595_ds_dr=0;
            835. }
            836. //LED燈的74HC595驅(qū)動(dòng)函數(shù)
            837. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01)
            838. {
            839. unsigned char i;
            840. unsigned char ucTempData;
            841. hc595_sh_dr=0;
            842. hc595_st_dr=0;
            843. ucTempData=ucLedStatusTemp16_09;//先送高8位
            844. for(i=0;i<8;i++)
            845. {
            846. if(ucTempData>=0x80)hc595_ds_dr=1;
            847. else hc595_ds_dr=0;
            848. hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
            849. delay_short(1);
            850. hc595_sh_dr=1;
            851. delay_short(1);
            852. ucTempData=ucTempData<<1;
            853. }
            854. ucTempData=ucLedStatusTemp08_01;//再先送低8位
            855. for(i=0;i<8;i++)
            856. {
            857. if(ucTempData>=0x80)hc595_ds_dr=1;
            858. else hc595_ds_dr=0;
            859. hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
            860. delay_short(1);
            861. hc595_sh_dr=1;
            862. delay_short(1);
            863. ucTempData=ucTempData<<1;
            864. }
            865. hc595_st_dr=0;//ST引腳把兩個(gè)寄存器的數(shù)據(jù)更新輸出到74HC595的輸出引腳上并且鎖存起來
            866. delay_short(1);
            867. hc595_st_dr=1;
            868. delay_short(1);
            869. hc595_sh_dr=0; //拉低,抗干擾就增強(qiáng)
            870. hc595_st_dr=0;
            871. hc595_ds_dr=0;
            872. }
            873. void T0_time(void) interrupt 1 //定時(shí)中斷
            874. {
            875. TF0=0;//清除中斷標(biāo)志
            876. TR0=0; //關(guān)中斷
            877. /* 注釋八:
            878. * 以下是本節(jié)內(nèi)容的核心程序,是定時(shí)器內(nèi)部產(chǎn)生的時(shí)間。const_timer_1s這個(gè)是產(chǎn)生多少次定時(shí)中斷才
            879. * 算1秒鐘的標(biāo)準(zhǔn)。這個(gè)標(biāo)準(zhǔn)決定了時(shí)鐘的精度。這個(gè)標(biāo)準(zhǔn)最后是需要校驗(yàn)的。
            880. */
            881. if(ucTimerStart==1)//定時(shí)器的時(shí)間已經(jīng)打開
            882. {
            883. uiTimerCnt++;//產(chǎn)生1秒鐘的時(shí)基
            884. if(uiTimerCnt>=const_timer_1s) //一秒鐘的時(shí)間到。這個(gè)const_timer_1s具體數(shù)值最后需要校驗(yàn)得出。
            885. {
            886. uiTimerCnt=0; //清零為產(chǎn)生下一個(gè)1秒鐘準(zhǔn)備
            887. ucTimerUpdate=1; //定時(shí)器每1秒鐘所產(chǎn)生的標(biāo)志,通知主函數(shù)及時(shí)更新采集時(shí)間數(shù)據(jù)
            888. ucTimerSecond++; //秒時(shí)間累加1
            889. if(ucTimerSecond>=60)
            890. {
            891. ucTimerSecond=0;
            892. ucTimerMinute++; //分時(shí)間累加1
            893. if(ucTimerMinute>=60)
            894. {
            895. ucTimerMinute=0;
            896. ucTimerHour++;//小時(shí)的時(shí)間累加1,為了避免if的嵌套過多,把小時(shí)的判斷放到外面兩層的if來繼續(xù)判斷
            897. }
            898. }
            899. if(ucTimerHour>=24)
            900. {
            901. ucTimerHour=0;
            902. ucTimerDate++; //天時(shí)間累加1
            903. ucTimerDateMax=get_date(ucTimerYear,ucTimerMonth);//根據(jù)年和月獲取當(dāng)前月份的最大天數(shù)
            904. if(ucTimerDate>ucTimerDateMax)//
            905. {
            906. ucTimerDate=1; //每個(gè)月都是從1號開始
            907. ucTimerMonth++;//月時(shí)間累加1
            908. if(ucTimerMonth>12)
            909. {
            910. ucTimerMonth=1; //每年從1月份開始
            911. ucTimerYear++; //年時(shí)間累加1
            912. if(ucTimerYear>99) //本系統(tǒng)的最高有效年份是2099年
            913. {
            914. ucTimerYear=99;
            915. }
            916. }
            917. }
            918. }
            919. }
            920. }
            921. if(ucVoiceLock==0) //原子鎖判斷
            922. {
            923. if(uiVoiceCnt!=0)
            924. {
            925. uiVoiceCnt--; //每次進(jìn)入定時(shí)中斷都自減1,直到等于零為止。才停止鳴叫
            926. beep_dr=0;//蜂鳴器是PNP三極管控制,低電平就開始鳴叫。
            927. }
            928. else
            929. {
            930. ; //此處多加一個(gè)空指令,想維持跟if括號語句的數(shù)量對稱,都是兩條指令。不加也可以。
            931. beep_dr=1;//蜂鳴器是PNP三極管控制,高電平就停止鳴叫。
            932. }
            933. }
            934. if(ucDpyTimeLock==0) //原子鎖判斷
            935. {
            936. uiDpyTimeCnt++;//數(shù)碼管的閃爍計(jì)時(shí)器
            937. }
            938. key_scan(); //按鍵掃描函數(shù)
            939. display_drive();//數(shù)碼管字模的驅(qū)動(dòng)函數(shù)
            940. TH0=0xfe; //重裝初始值(65535-500)=65035=0xfe0b
            941. TL0=0x0b;
            942. TR0=1;//開中斷
            943. }
            944. void delay_short(unsigned int uiDelayShort)
            945. {
            946. unsigned int i;
            947. for(i=0;i
            948. {
            949. ; //一個(gè)分號相當(dāng)于執(zhí)行一條空語句
            950. }
            951. }
            952. void delay_long(unsigned int uiDelayLong)
            953. {
            954. unsigned int i;
            955. unsigned int j;
            956. for(i=0;i
            957. {
            958. for(j=0;j<500;j++)//內(nèi)嵌循環(huán)的空指令數(shù)量
            959. {
            960. ; //一個(gè)分號相當(dāng)于執(zhí)行一條空語句
            961. }
            962. }
            963. }
            964. void initial_myself(void)//第一區(qū) 初始化單片機(jī)
            965. {
            966. key_gnd_dr=0; //模擬獨(dú)立按鍵的地GND,因此必須一直輸出低電平
            967. beep_dr=1; //用PNP三極管控制蜂鳴器,輸出高電平時(shí)不叫。
            968. hc595_drive(0x00,0x00);//關(guān)閉所有經(jīng)過另外兩個(gè)74HC595驅(qū)動(dòng)的LED燈
            969. TMOD=0x01;//設(shè)置定時(shí)器0為工作方式1
            970. TH0=0xfe; //重裝初始值(65535-500)=65035=0xfe0b
            971. TL0=0x0b;
            972. }
            973. void initial_peripheral(void) //第二區(qū) 初始化外圍
            974. {
            975. ucDigDot8=0; //小數(shù)點(diǎn)全部不顯示
            976. ucDigDot7=0;
            977. ucDigDot6=0;
            978. ucDigDot5=0;
            979. ucDigDot4=0;
            980. ucDigDot3=0;
            981. ucDigDot2=0;
            982. ucDigDot1=0;
            983. EA=1; //開總中斷
            984. ET0=1; //允許定時(shí)中斷
            985. TR0=1; //啟動(dòng)定時(shí)中斷
            986. }
            總結(jié)陳詞:
            任何一個(gè)電子產(chǎn)品在投入生產(chǎn)的時(shí)候都要考慮到生產(chǎn)的測試,朱兆祺51單片機(jī)學(xué)習(xí)板在生產(chǎn)加工后也一樣要進(jìn)行測試。那么這個(gè)測試的程序如何能夠做到快速,全面,易用這三個(gè)要求呢?欲知詳情,請聽下回分解-----生產(chǎn)朱兆祺51學(xué)習(xí)板的從機(jī)自檢測試程序源代碼.。


            評論


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

            關(guān)閉