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

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > 第89節(jié):用單片機內(nèi)部定時器做一個時鐘

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

          作者: 時間:2016-11-22 來源:網(wǎng)絡 收藏
          開場白:
          很多網(wǎng)友建議,為了方便初學者學習編程思路,我應該用單片機定時器做一個時鐘程序供大家參考學習。其實我前面第48節(jié)就已經(jīng)用ds1302做了一個可以顯示和更高時間的時鐘,這一節(jié)只要在第48節(jié)的源代碼基礎(chǔ)上,大的框架不用動,只需要把ds1302產(chǎn)生的時間改成用定時中斷產(chǎn)生的時間就可以了,改動的地方非常小。但是為了讓時間的精度更高,最后必須跟標準時間進行校驗,來修正系統(tǒng)中一秒鐘需要多個定時中斷的誤差,這個誤差決定了系統(tǒng)的時間精度,其實這個校驗方法我在前面很多章節(jié)上跟大家介紹過了:
          第一步:在程序代碼上先寫入1秒鐘大概需要200個定時中斷。
          第二步:把程序燒錄進單片機后,上電開始測試,手上同步打開手機里的秒表,當手機的標準時間跑了780秒(這個標準時間跑得越長校驗精度越高),而此時單片機僅僅跑了1632秒。那么最終得出1秒鐘需要的定時中斷次數(shù)是:const_time_1s=(200*1632)/780=418。
          第三步:如果發(fā)現(xiàn)時鐘還是不太準,可以繼續(xù)返回第一步根據(jù)最新1秒鐘的時間是418次,多校驗幾次,來不斷調(diào)整const_time_1s的數(shù)值,直到找到相對精度的時間為止。
          本系統(tǒng)僅供學習,精度不可能做得很好,因為影響時間精度的因素還有定時中斷的重裝值,定時中斷里面的代碼盡量少,以及晶振等不好控制的因素。所以鴻哥一直不推薦在實際項目中用單片機的內(nèi)部定時器做實時時鐘,因為精度有限。真正想要準確的時鐘時間,還是強烈建議大家用外部專用的時鐘芯片或者用CPLD/FPGA來做。
          具體內(nèi)容,請看源代碼講解。
          (1硬件平臺.
          基于朱兆祺51單片機學習板
          (2)實現(xiàn)功能:
          本程序有2兩個窗口。
          第1個窗口顯示日期。顯示格式“年-月-日”。注意中間有“-”分開。
          第2個窗口顯示時間。顯示格式“時 分 秒”。注意中間沒“-”,只有空格分開。
          系統(tǒng)上電后,默認顯示第2個窗口,實時顯示動態(tài)的“時 分 秒”時間。此時按下S13按鍵不松手就會切換到顯示日期的第1個窗口。松手后自動切換回第2個顯示動態(tài)時間的窗口。
          需要更改時間的時候,長按S9按鍵不松手超過3秒后,系統(tǒng)將進入修改時間的狀態(tài),切換到第1個日期窗口,并且顯示“年”的兩位數(shù)碼管會閃爍,此時可以按S1或者S5加減按鍵修改年的參數(shù),修改完年后,繼續(xù)短按S9按鍵,會切換到“月”的參數(shù)閃爍狀態(tài),只要依次不斷按下S9按鍵,就會依次切換年,月,日,時,分,秒的參數(shù)閃爍狀態(tài),最后修改完秒的參數(shù)后,系統(tǒng)會自動把我們修改設置的日期時間一次性更改到定時中斷函數(shù)內(nèi)部的時間變量,達到修改日期時間的目的。
          S13是電平變化按鍵,用來切換窗口的,專門用來查看當前日期。按下S13按鍵時顯示日期窗口,松手后返回到顯示實時時間的窗口。
          [size=10.5000pt](3)源代碼講解如下:
          1. #include "REG52.H"
          2. #define const_dpy_time_half200//數(shù)碼管閃爍時間的半值
          3. #define const_dpy_time_all 400//數(shù)碼管閃爍時間的全值 一定要比const_dpy_time_half 大
          4. #define const_voice_short40 //蜂鳴器短叫的持續(xù)時間
          5. #define const_key_time120 //按鍵去抖動延時的時間
          6. #define const_key_time220 //按鍵去抖動延時的時間
          7. #define const_key_time320 //按鍵去抖動延時的時間
          8. #define const_key_time420 //按鍵去抖動延時的時間
          9. #define const_key_time171200//長按超過3秒的時間
          10. /* 注釋一:
          11. * const_timer_1s這個是產(chǎn)生多少次定時中斷才算1秒鐘的標準。這個標準決定了時鐘的精度。這個標準最后是需要校驗的。
          12. * 那么是如何檢驗的呢?根據(jù)我們前面介紹的校驗時間方法:
          13. * 步驟:
          14. * 第一步:在程序代碼上先寫入1秒鐘大概需要200個定時中斷。
          15. * 第二步:把程序燒錄進單片機后,上電開始測試,手上同步打開手機里的秒表,當手機的標準時間跑了780秒(這個標準時間跑得越長校驗精度越高),
          16. * 而此時單片機僅僅跑了1632秒。那么最終得出1秒鐘需要的定時中斷次數(shù)是:const_time_1s=(200*1632)/780=418。
          17. * 第三步:如果發(fā)現(xiàn)時鐘還是不太準,可以繼續(xù)返回第一步根據(jù)最新1秒鐘的時間是418次,多校驗幾次。本系統(tǒng)僅供學習,精度不可能做得很好,因為
          18. * 影響時間精度的因素還有定時中斷的重裝值,定時中斷里面的代碼盡量少,以及晶振等不好控制的因素。所以鴻哥一直不推薦在實際項目中
          19. * 用單片機的內(nèi)部定時器做實時時鐘,因為精度有限。真正想要準確的時鐘時間,還是強烈建議大家用外部專用的時鐘芯片或者用CPLD/FPGA來做。
          20. */
          21. //#define const_timer_1s200 //第一次假設大概1秒的時間需要200個定時中斷
          22. #define const_timer_1s418//第二次校驗后,最終選定大概1秒的時間需要418個定時中斷。如果發(fā)現(xiàn)時間還是不準,可以在此基礎(chǔ)上繼續(xù)校驗來調(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ū)動數(shù)碼管的74HC595
          28. void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01);
          29. void display_drive(void); //顯示數(shù)碼管字模的驅(qū)動函數(shù)
          30. void display_service(void); //顯示的窗口菜單服務程序
          31. //驅(qū)動LED的74HC595
          32. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01);
          33. void T0_time(void);//定時中斷函數(shù)
          34. void key_service(void); //按鍵服務的應用程序
          35. void key_scan(void);//按鍵掃描函數(shù) 放在定時中斷里
          36. void timer_sampling(void); //定時器采樣程序,內(nèi)部每秒鐘采集更新一次
          37. unsigned char get_date(unsigned char ucYearTemp,unsigned char ucMonthTemp);//獲取當前月份的最大天數(shù)
          38. //日調(diào)整 每個月份的日最大取值不同,有的最大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; //對應朱兆祺學習板的S1鍵
          41. sbit key_sr2=P0^1; //對應朱兆祺學習板的S5鍵
          42. sbit key_sr3=P0^2; //對應朱兆祺學習板的S9鍵
          43. sbit key_sr4=P0^3; //對應朱兆祺學習板的S13鍵
          44. sbit key_gnd_dr=P0^4; //模擬獨立按鍵的地GND,因此必須一直輸出低電平
          45. sbit beep_dr=P2^7; //蜂鳴器的驅(qū)動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; //按鍵去抖動延時計數(shù)器
          54. unsigned char ucKeyLock1=0; //按鍵觸發(fā)后自鎖的變量標志
          55. unsigned intuiKeyTimeCnt2=0; //按鍵去抖動延時計數(shù)器
          56. unsigned char ucKeyLock2=0; //按鍵觸發(fā)后自鎖的變量標志
          57. unsigned intuiKeyTimeCnt3=0; //按鍵去抖動延時計數(shù)器
          58. unsigned char ucKeyLock3=0; //按鍵觸發(fā)后自鎖的變量標志
          59. unsigned int uiKey4Cnt1=0;//在軟件濾波中,用到的變量
          60. unsigned int uiKey4Cnt2=0;
          61. unsigned char ucKey4Sr=1;//實時反映按鍵的電平狀態(tài)
          62. unsigned char ucKey4SrRecord=0; //記錄上一次按鍵的電平狀態(tài)
          63. unsigned intuiVoiceCnt=0;//蜂鳴器鳴叫的持續(xù)時間計數(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ù)點是否顯示的標志
          74. unsigned char ucDigDot7;//數(shù)碼管7的小數(shù)點是否顯示的標志
          75. unsigned char ucDigDot6;//數(shù)碼管6的小數(shù)點是否顯示的標志
          76. unsigned char ucDigDot5;//數(shù)碼管5的小數(shù)點是否顯示的標志
          77. unsigned char ucDigDot4;//數(shù)碼管4的小數(shù)點是否顯示的標志
          78. unsigned char ucDigDot3;//數(shù)碼管3的小數(shù)點是否顯示的標志
          79. unsigned char ucDigDot2;//數(shù)碼管2的小數(shù)點是否顯示的標志
          80. unsigned char ucDigDot1;//數(shù)碼管1的小數(shù)點是否顯示的標志
          81. unsigned char ucDigShowTemp=0; //臨時中間變量
          82. unsigned char ucDisplayDriveStep=1;//動態(tài)掃描數(shù)碼管的步驟變量
          83. unsigned char ucWd=2;//本程序的核心變量,窗口顯示變量。類似于一級菜單的變量。代表顯示不同的窗口。
          84. unsigned char ucPart=0;//本程序的核心變量,局部顯示變量。類似于二級菜單的變量。代表顯示不同的局部。
          85. unsigned char ucWd1Update=0; //窗口1更新顯示標志
          86. unsigned char ucWd2Update=1; //窗口2更新顯示標志
          87. unsigned char ucWd1Part1Update=0;//在窗口1中,局部1的更新顯示標志
          88. unsigned char ucWd1Part2Update=0; //在窗口1中,局部2的更新顯示標志
          89. unsigned char ucWd1Part3Update=0; //在窗口1中,局部3的更新顯示標志
          90. unsigned char ucWd2Part1Update=0;//在窗口2中,局部1的更新顯示標志
          91. unsigned char ucWd2Part2Update=0; //在窗口2中,局部2的更新顯示標志
          92. unsigned char ucWd2Part3Update=0; //在窗口2中,局部3的更新顯示標志
          93. unsigned charucYear=15; //用來顯示和設置的時間變量
          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; //計時器的時基
          100. unsigned charucTimerYear=15; //在定時器內(nèi)部時基產(chǎn)生的時間變量
          101. unsigned charucTimerMonth=1;
          102. unsigned charucTimerDate=1;
          103. unsigned charucTimerHour=12;
          104. unsigned charucTimerMinute=0;
          105. unsigned charucTimerSecond=0;
          106. unsigned charucTimerDateMax=31; //當前月份的最大天數(shù)
          107. unsigned charucTimerUpdate=0; //定時器每1秒鐘所產(chǎn)生的標志
          108. unsigned charucTimerStart=1;//是否打開定時器內(nèi)部時間的標志,在本程序相當于原子鎖的作用。
          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ù)碼管的閃爍計時器,放在定時中斷里不斷累加
          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(); //按鍵服務的應用程序
          144. timer_sampling(); //定時器采樣程序,內(nèi)部每秒鐘采集更新一次
          145. display_service(); //顯示的窗口菜單服務程序
          146. }
          147. }
          148. /* 注釋二:
          149. * 系統(tǒng)不用時時刻刻采集定時器的內(nèi)部數(shù)據(jù),每隔1秒鐘的時間更新采集一次就可以了。
          150. * 這個1秒鐘的時間是根據(jù)定時器內(nèi)部ucTimerUpdate變量來判斷。
          151. */
          152. void timer_sampling(void) //采樣定時器的程序,內(nèi)部每秒鐘采集更新一次
          153. {
          154. if(ucPart==0)//當系統(tǒng)不是處于設置日期和時間的情況下
          155. {
          156. if(ucTimerUpdate==1)//每隔1秒鐘時間就更新采集一次定時器的時間數(shù)據(jù)
          157. {
          158. ucTimerUpdate=0;//及時清零,避免一直更新。
          159. ucYear=ucTimerYear; //讀取定時器內(nèi)部的年
          160. ucMonth=ucTimerMonth; //讀取定時器內(nèi)部的月
          161. ucDate=ucTimerDate;//讀取定時器內(nèi)部的日
          162. ucHour=ucTimerHour; //讀取定時器內(nèi)部的時
          163. ucMinute=ucTimerMinute;//讀取定時器內(nèi)部的分
          164. ucSecond=ucTimerSecond;//讀取定時器內(nèi)部的秒
          165. ucWd2Update=1; //窗口2更新顯示時間
          166. }
          167. }
          168. }
          169. /* 注釋三:
          170. * 根據(jù)年份和月份來獲取當前這個月的最大天數(shù)。每個月份的天數(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; //默認最大是31天,以下根據(jù)不同的年份和月份來決定是否需要修正這個值
          179. switch(ucMonthTemp)//根據(jù)不同的月份來獲取當前月份天數(shù)的最大值
          180. {
          181. case 2://二月份要計算是否是閏年
          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)整 每個月份的日最大取值不同,有的最大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://二月份要計算是否是閏年
          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) //顯示的窗口菜單服務程序
          242. {
          243. switch(ucWd)//本程序的核心變量,窗口顯示變量。類似于一級菜單的變量。代表顯示不同的窗口。
          244. {
          245. case 1: //顯示日期窗口的數(shù)據(jù)數(shù)據(jù)格式 NN-YY-RR 年-月-日
          246. if(ucWd1Update==1)//窗口1要全部更新顯示
          247. {
          248. ucWd1Update=0;//及時清零標志,避免一直進來掃描
          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ù)碼管顯示實際內(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ù)碼管顯示實際內(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ù)碼管顯示實際內(nèi)容
          277. ucDigShow1=ucTemp1;
          278. }
          279. //數(shù)碼管閃爍
          280. switch(ucPart)//相當于二級菜單,根據(jù)局部變量的值,使對應的參數(shù)產(chǎn)生閃爍的動態(tài)效果。
          281. {
          282. case 0://都不閃爍
          283. break;
          284. case 1://年參數(shù)閃爍
          285. if(uiDpyTimeCnt==const_dpy_time_half)
          286. {
          287. ucDigShow8=ucTemp8; //數(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; //及時把閃爍記時器清零
          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ù)碼管顯示實際內(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; //及時把閃爍記時器清零
          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ù)碼管顯示實際內(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; //及時把閃爍記時器清零
          324. ucDpyTimeLock=0;//原子鎖解鎖
          325. ucDigShow2=10; //數(shù)碼管顯示空,什么都不顯示
          326. ucDigShow1=10;
          327. }
          328. break;
          329. }
          330. break;
          331. case 2: //顯示時間窗口的數(shù)據(jù)數(shù)據(jù)格式 SS FF MM 時 分 秒
          332. if(ucWd2Update==1)//窗口2要全部更新顯示
          333. {
          334. ucWd2Update=0;//及時清零標志,避免一直進來掃描
          335. ucDigShow6=10;//顯示空
          336. ucDigShow3=10;//顯示空
          337. ucWd2Part3Update=1;//局部時更新顯示
          338. ucWd2Part2Update=1;//局部分更新顯示
          339. ucWd2Part1Update=1;//局部秒更新顯示
          340. }
          341. if(ucWd2Part1Update==1)//局部時更新顯示
          342. {
          343. ucWd2Part1Update=0;
          344. ucTemp8=ucHour/10;//時
          345. ucTemp7=ucHour%10;
          346. ucDigShow8=ucTemp8; //數(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ù)碼管顯示實際內(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ù)碼管顯示實際內(nèi)容
          363. ucDigShow1=ucTemp1;
          364. }
          365. //數(shù)碼管閃爍
          366. switch(ucPart)//相當于二級菜單,根據(jù)局部變量的值,使對應的參數(shù)產(chǎn)生閃爍的動態(tài)效果。
          367. {
          368. case 0://都不閃爍
          369. break;
          370. case 1://時參數(shù)閃爍
          371. if(uiDpyTimeCnt==const_dpy_time_half)
          372. {
          373. ucDigShow8=ucTemp8; //數(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; //及時把閃爍記時器清零
          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ù)碼管顯示實際內(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; //及時把閃爍記時器清零
          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ù)碼管顯示實際內(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; //及時把閃爍記時器清零
          410. ucDpyTimeLock=0;//原子鎖解鎖
          411. ucDigShow2=10; //數(shù)碼管顯示空,什么都不顯示
          412. ucDigShow1=10;
          413. }
          414. break;
          415. }
          416. break;
          417. }
          418. }
          419. void key_scan(void)//按鍵掃描函數(shù) 放在定時中斷里
          420. {
          421. if(key_sr1==1)//IO是高電平,說明按鍵沒有被按下,這時要及時清零一些標志位
          422. {
          423. ucKeyLock1=0; //按鍵自鎖標志清零
          424. uiKeyTimeCnt1=0;//按鍵去抖動延時計數(shù)器清零,此行非常巧妙,是我實戰(zhàn)中摸索出來的。
          425. }
          426. else if(ucKeyLock1==0)//有按鍵按下,且是第一次被按下
          427. {
          428. uiKeyTimeCnt1++; //累加定時中斷次數(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是高電平,說明按鍵沒有被按下,這時要及時清零一些標志位
          437. {
          438. ucKeyLock2=0; //按鍵自鎖標志清零
          439. uiKeyTimeCnt2=0;//按鍵去抖動延時計數(shù)器清零,此行非常巧妙,是我實戰(zhàn)中摸索出來的。
          440. }
          441. else if(ucKeyLock2==0)//有按鍵按下,且是第一次被按下
          442. {
          443. uiKeyTimeCnt2++; //累加定時中斷次數(shù)
          444. if(uiKeyTimeCnt2>const_key_time2)
          445. {
          446. uiKeyTimeCnt2=0;
          447. ucKeyLock2=1;//自鎖按鍵置位,避免一直觸發(fā)
          448. ucKeySec=2; //觸發(fā)2號鍵
          449. }
          450. }
          451. /* 注釋四:
          452. * 注意,此處把一個按鍵的短按和長按的功能都實現(xiàn)了。
          453. */
          454. if(key_sr3==1)//IO是高電平,說明按鍵沒有被按下,這時要及時清零一些標志位
          455. {
          456. ucKeyLock3=0; //按鍵自鎖標志清零
          457. uiKeyTimeCnt3=0;//按鍵去抖動延時計數(shù)器清零,此行非常巧妙,是我實戰(zhàn)中摸索出來的。
          458. }
          459. else if(ucKeyLock3==0)//有按鍵按下,且是第一次被按下
          460. {
          461. uiKeyTimeCnt3++; //累加定時中斷次數(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ù)
          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)//對應朱兆祺學習板的S13鍵
          481. {
          482. uiKey4Cnt1=0; //在軟件濾波中,非常關(guān)鍵的語句?。?!類似按鍵去抖動程序的及時清零
          483. uiKey4Cnt2++; //類似獨立按鍵去抖動的軟件抗干擾處理
          484. if(uiKey4Cnt2>const_key_time4)
          485. {
          486. uiKey4Cnt2=0;
          487. ucKey4Sr=1;//實時反映按鍵松手時的電平狀態(tài)
          488. }
          489. }
          490. else
          491. {
          492. uiKey4Cnt2=0; //在軟件濾波中,非常關(guān)鍵的語句?。。☆愃瓢存I去抖動程序的及時清零
          493. uiKey4Cnt1++;
          494. if(uiKey4Cnt1>const_key_time4)
          495. {
          496. uiKey4Cnt1=0;
          497. ucKey4Sr=0;//實時反映按鍵按下時的電平狀態(tài)
          498. }
          499. }
          500. }
          501. void key_service(void) //按鍵服務的應用程序
          502. {
          503. switch(ucKeySec) //按鍵服務狀態(tài)切換
          504. {
          505. case 1:// 加按鍵 對應朱兆祺學習板的S1鍵
          506. switch(ucWd)//在不同的窗口下,設置不同的參數(shù)
          507. {
          508. case 1:
          509. switch(ucPart) //在不同的局部變量下,相當于二級菜單
          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) //在不同的局部變量下,相當于二級菜單
          539. {
          540. case 1://時
          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;//原子鎖加鎖,保護主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
          568. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
          569. ucVoiceLock=0;//原子鎖解鎖,保護主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
          570. ucKeySec=0;//響應按鍵服務處理程序后,按鍵編號清零,避免一致觸發(fā)
          571. break;
          572. case 2:// 減按鍵 對應朱兆祺學習板的S5鍵
          573. switch(ucWd)//在不同的窗口下,設置不同的參數(shù)
          574. {
          575. case 1:
          576. switch(ucPart) //在不同的局部變量下,相當于二級菜單
          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) //在不同的局部變量下,相當于二級菜單
          606. {
          607. case 1://時
          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;//原子鎖加鎖,保護主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
          635. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
          636. ucVoiceLock=0;//原子鎖解鎖,保護主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
          637. ucKeySec=0;//響應按鍵服務處理程序后,按鍵編號清零,避免一致觸發(fā)
          638. break;
          639. case 3://短按設置按鍵 對應朱兆祺學習板的S9鍵
          640. switch(ucWd)//在不同的窗口下,設置不同的參數(shù)
          641. {
          642. case 1:
          643. ucPart++;
          644. if(ucPart>3)
          645. {
          646. ucPart=1;
          647. ucWd=2; //切換到第二個窗口,設置時分秒
          648. ucWd2Update=1;//窗口2更新顯示
          649. }
          650. ucWd1Update=1;//窗口1更新顯示
          651. break;
          652. case 2:
          653. if(ucPart>0) //在窗口2的時候,要第一次激活設置時間,必須是長按3秒才可以,這里短按激活不了第一次
          654. {
          655. ucPart++;
          656. if(ucPart>3)//設置時間結(jié)束
          657. {
          658. ucPart=0;
          659. /* 注釋六:
          660. * 每個月份的天數(shù)最大值是不一樣的,在寫入ds1302時鐘芯片內(nèi)部數(shù)據(jù)前,應該做一次調(diào)整。
          661. * 有的月份最大28天,有的月份最大29天,有的月份最大30天,有的月份最大31天,
          662. */
          663. ucDate=date_adjust(ucYear,ucMonth,ucDate); //日調(diào)整 避免日的數(shù)值在某個月份超范圍
          664. ucTimerStart=0;//關(guān)閉定時器的時間。在更改定時器內(nèi)部時間數(shù)據(jù)時,先關(guān)閉它,相當于原子鎖的加鎖作用。
          665. ucTimerYear=ucYear;//把設置和顯示的數(shù)據(jù)更改到定時器內(nèi)部的時間變量
          666. ucTimerMonth=ucMonth;
          667. ucTimerDate=ucDate;
          668. ucTimerHour=ucHour;
          669. ucTimerMinute=ucMinute;
          670. ucTimerSecond=ucSecond;
          671. ucTimerStart=1;//打開定時器的時間。在更改定時器內(nèi)部時間數(shù)據(jù)后,再打開它,相當于原子鎖的解鎖作用。
          672. }
          673. ucWd2Update=1;//窗口2更新顯示
          674. }
          675. break;
          676. }
          677. ucVoiceLock=1;//原子鎖加鎖,保護主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
          678. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
          679. ucVoiceLock=0;//原子鎖解鎖,保護主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
          680. ucKeySec=0;//響應按鍵服務處理程序后,按鍵編號清零,避免一致觸發(fā)
          681. break;
          682. case 17://長按3秒設置按鍵 對應朱兆祺學習板的S9鍵
          683. switch(ucWd)//在不同的窗口下,設置不同的參數(shù)
          684. {
          685. case 2:
          686. if(ucPart==0) //處于非設置時間的狀態(tài)下,要第一次激活設置時間,必須是長按3秒才可以
          687. {
          688. ucWd=1;
          689. ucPart=1;//進入到設置日期的狀態(tài)下
          690. ucWd1Update=1;//窗口1更新顯示
          691. }
          692. break;
          693. }
          694. ucVoiceLock=1;//原子鎖加鎖,保護主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
          695. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
          696. ucVoiceLock=0;//原子鎖解鎖,保護主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
          697. ucKeySec=0;//響應按鍵服務處理程序后,按鍵編號清零,避免一致觸發(fā)
          698. break;
          699. }
          700. /* 注釋七:
          701. * 注意,此處就是第一次出現(xiàn)的電平按鍵程序,跟以往的下降沿按鍵不一樣。
          702. * ucKey4Sr是經(jīng)過軟件濾波處理后,直接反應IO口電平狀態(tài)的變量.當電平發(fā)生
          703. * 變化時,就會切換到不同的顯示界面,這里多用了一個ucKey4SrRecord變量
          704. * 記錄上一次的電平狀態(tài),是為了避免一直刷新顯示。
          705. */
          706. if(ucKey4Sr!=ucKey4SrRecord)//說明S13的切換按鍵電平狀態(tài)發(fā)生變化
          707. {
          708. ucKey4SrRecord=ucKey4Sr;//及時記錄當前最新的按鍵電平狀態(tài)避免一直進來觸發(fā)
          709. if(ucKey4Sr==1) //松手后切換到顯示時間的窗口
          710. {
          711. ucWd=2; //顯示時分秒的窗口
          712. ucPart=0;//進入到非設置時間的狀態(tài)下
          713. ucWd2Update=1;//窗口2更新顯示
          714. }
          715. else//按下去切換到顯示日期的窗口
          716. {
          717. ucWd=1; //顯示年月日的窗口
          718. ucPart=0;//進入到非設置時間的狀態(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ù)點
          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ù)點
          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ù)點
          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ù)點
          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ù)點
          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ù)點
          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ù)點
          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ù)點
          789. }
          790. dig_hc595_drive(ucDigShowTemp,0x7f);
          791. break;
          792. }
          793. ucDisplayDriveStep++;
          794. if(ucDisplayDriveStep>8)//掃描完8個數(shù)碼管后,重新從第一個開始掃描
          795. {
          796. ucDisplayDriveStep=1;
          797. }
          798. }
          799. //數(shù)碼管的74HC595驅(qū)動函數(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引腳把兩個寄存器的數(shù)據(jù)更新輸出到74HC595的輸出引腳上并且鎖存起來
          829. delay_short(1);
          830. dig_hc595_st_dr=1;
          831. delay_short(1);
          832. dig_hc595_sh_dr=0; //拉低,抗干擾就增強
          833. dig_hc595_st_dr=0;
          834. dig_hc595_ds_dr=0;
          835. }
          836. //LED燈的74HC595驅(qū)動函數(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引腳把兩個寄存器的數(shù)據(jù)更新輸出到74HC595的輸出引腳上并且鎖存起來
          866. delay_short(1);
          867. hc595_st_dr=1;
          868. delay_short(1);
          869. hc595_sh_dr=0; //拉低,抗干擾就增強
          870. hc595_st_dr=0;
          871. hc595_ds_dr=0;
          872. }
          873. void T0_time(void) interrupt 1 //定時中斷
          874. {
          875. TF0=0;//清除中斷標志
          876. TR0=0; //關(guān)中斷
          877. /* 注釋八:
          878. * 以下是本節(jié)內(nèi)容的核心程序,是定時器內(nèi)部產(chǎn)生的時間。const_timer_1s這個是產(chǎn)生多少次定時中斷才
          879. * 算1秒鐘的標準。這個標準決定了時鐘的精度。這個標準最后是需要校驗的。
          880. */
          881. if(ucTimerStart==1)//定時器的時間已經(jīng)打開
          882. {
          883. uiTimerCnt++;//產(chǎn)生1秒鐘的時基
          884. if(uiTimerCnt>=const_timer_1s) //一秒鐘的時間到。這個const_timer_1s具體數(shù)值最后需要校驗得出。
          885. {
          886. uiTimerCnt=0; //清零為產(chǎn)生下一個1秒鐘準備
          887. ucTimerUpdate=1; //定時器每1秒鐘所產(chǎn)生的標志,通知主函數(shù)及時更新采集時間數(shù)據(jù)
          888. ucTimerSecond++; //秒時間累加1
          889. if(ucTimerSecond>=60)
          890. {
          891. ucTimerSecond=0;
          892. ucTimerMinute++; //分時間累加1
          893. if(ucTimerMinute>=60)
          894. {
          895. ucTimerMinute=0;
          896. ucTimerHour++;//小時的時間累加1,為了避免if的嵌套過多,把小時的判斷放到外面兩層的if來繼續(xù)判斷
          897. }
          898. }
          899. if(ucTimerHour>=24)
          900. {
          901. ucTimerHour=0;
          902. ucTimerDate++; //天時間累加1
          903. ucTimerDateMax=get_date(ucTimerYear,ucTimerMonth);//根據(jù)年和月獲取當前月份的最大天數(shù)
          904. if(ucTimerDate>ucTimerDateMax)//
          905. {
          906. ucTimerDate=1; //每個月都是從1號開始
          907. ucTimerMonth++;//月時間累加1
          908. if(ucTimerMonth>12)
          909. {
          910. ucTimerMonth=1; //每年從1月份開始
          911. ucTimerYear++; //年時間累加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--; //每次進入定時中斷都自減1,直到等于零為止。才停止鳴叫
          926. beep_dr=0;//蜂鳴器是PNP三極管控制,低電平就開始鳴叫。
          927. }
          928. else
          929. {
          930. ; //此處多加一個空指令,想維持跟if括號語句的數(shù)量對稱,都是兩條指令。不加也可以。
          931. beep_dr=1;//蜂鳴器是PNP三極管控制,高電平就停止鳴叫。
          932. }
          933. }
          934. if(ucDpyTimeLock==0) //原子鎖判斷
          935. {
          936. uiDpyTimeCnt++;//數(shù)碼管的閃爍計時器
          937. }
          938. key_scan(); //按鍵掃描函數(shù)
          939. display_drive();//數(shù)碼管字模的驅(qū)動函數(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. ; //一個分號相當于執(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. ; //一個分號相當于執(zhí)行一條空語句
          961. }
          962. }
          963. }
          964. void initial_myself(void)//第一區(qū) 初始化單片機
          965. {
          966. key_gnd_dr=0; //模擬獨立按鍵的地GND,因此必須一直輸出低電平
          967. beep_dr=1; //用PNP三極管控制蜂鳴器,輸出高電平時不叫。
          968. hc595_drive(0x00,0x00);//關(guān)閉所有經(jīng)過另外兩個74HC595驅(qū)動的LED燈
          969. TMOD=0x01;//設置定時器0為工作方式1
          970. TH0=0xfe; //重裝初始值(65535-500)=65035=0xfe0b
          971. TL0=0x0b;
          972. }
          973. void initial_peripheral(void) //第二區(qū) 初始化外圍
          974. {
          975. ucDigDot8=0; //小數(shù)點全部不顯示
          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; //允許定時中斷
          985. TR0=1; //啟動定時中斷
          986. }
          總結(jié)陳詞:
          任何一個電子產(chǎn)品在投入生產(chǎn)的時候都要考慮到生產(chǎn)的測試,朱兆祺51單片機學習板在生產(chǎn)加工后也一樣要進行測試。那么這個測試的程序如何能夠做到快速,全面,易用這三個要求呢?欲知詳情,請聽下回分解-----生產(chǎn)朱兆祺51學習板的從機自檢測試程序源代碼.。


          評論


          技術(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); })();