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

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 第35節(jié):帶數(shù)碼管顯示的象棋比賽專用計時器

          第35節(jié):帶數(shù)碼管顯示的象棋比賽專用計時器

          作者: 時間:2016-11-22 來源:網(wǎng)絡(luò) 收藏
          開場白:
          2014年春節(jié)的時候,一幫朋友舉行小規(guī)模的象棋比賽,有一些朋友下棋的速度實在是太慢了,為了限制比賽時間,我專門用朱兆祺的51學(xué)習(xí)板做了一個棋類比賽專用計時器給他們用。這一節(jié)要教會大家兩個知識點:
          第一個:按鍵服務(wù)程序操作的精髓在于根據(jù)當(dāng)前系統(tǒng)處于什么窗口狀態(tài)下就執(zhí)行什么操作。緊緊圍繞著不同的窗口ucWd來執(zhí)行不同的操作。
          第二個:繼續(xù)加深熟悉鴻哥首次提出的“一二級菜單顯示理論”:凡是人機界面顯示,不管是數(shù)碼管還是液晶屏,都可以把顯示的內(nèi)容分成不同的窗口來顯示,每個顯示的窗口中又可以分成不同的局部顯示。其中窗口就是一級菜單,用ucWd變量表示。局部就是二級菜單,用ucPart來表示。不同的窗口,會有不同的更新顯示變量ucWdXUpdate來對應(yīng),表示整屏全部更新顯示。不同的局部,也會有不同的更新顯示變量ucWdXPartYUpdate來對應(yīng),表示局部更新顯示。

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

          (1)硬件平臺:基于朱兆祺51單片機學(xué)習(xí)板。
          剛上電開機時,紅棋加時鍵對應(yīng)S1鍵,紅棋減時鍵對應(yīng)S2鍵.。
          剛上電開機時,黑棋加時鍵對應(yīng)S3鍵,黑棋減時鍵對應(yīng)S4鍵.。
          比賽中途暫停雙方計時的暫停按鍵對應(yīng)S6鍵。剛上電時,復(fù)位雙方默認20分時間的復(fù)位按鍵對應(yīng)S7按鍵。
          紅棋的搶時按鍵對應(yīng)S13鍵,黑棋的搶時按鍵對應(yīng)S16按鍵。

          (2)實現(xiàn)功能:
          棋類計時器有點像搶答器,本質(zhì)上有兩個計時器。比賽的時候?qū)牡膬蓚€棋友各用一個不同的按鍵搶時間,紅棋走一步棋后,就按一下自己的搶時按鍵,這個時候紅棋的計時器停止計時,而黑棋的計時器開始計時,黑棋走了一步棋后,按一下自己的計時器,黑棋停止計時,紅棋繼續(xù)計時,依次循環(huán),誰的時間最先用完誰就輸,蜂鳴器也會發(fā)出長鳴的聲音提示時間到。
          上電開機默認雙方各有20分鐘的時間,左邊顯示的是紅棋的時間,右邊顯示的是黑棋的時間。此時可以通過S1,S2.,S3,S4的加減按鍵來設(shè)置各自的最大倒計時時間。此時如果按下復(fù)位按鍵S7,會自動把雙方的時間設(shè)置為默認的20分鐘。
          設(shè)置好最大倒計時的時間后,此時任意一方按下各自的搶時按鍵(S13或者S16),則自己的計時器停止計時,而對方開始倒計時。此時數(shù)碼管顯示的是對方的時間,而自己的時間屏蔽不顯示。
          在開始倒計時的時候,如果中途有棋友要接聽電話或者忙別的事情,需要暫時暫停一下雙方的時間,這個時候可以按S6暫停按鍵來暫停雙方的計時,忙完后再次按下暫停按鍵會繼續(xù)倒計時。任何一方的時間走完,都會蜂鳴器長鳴提示。
          (3)源代碼講解如下:
          1. #include "REG52.H"
          2. #define const_voice_short40 //蜂鳴器短叫的持續(xù)時間
          3. #define const_voice_long 900 //蜂鳴器長叫的持續(xù)時間
          4. #define const_key_time10 //按鍵去抖動延時的時間
          5. #define const_1s 422 //產(chǎn)生一秒鐘的時間基準
          6. void initial_myself();
          7. void initial_peripheral();
          8. void delay_short(unsigned int uiDelayShort);
          9. void delay_long(unsigned int uiDelaylong);
          10. void T0_time();//定時中斷函數(shù)
          11. void key_service();
          12. void key_scan(); //按鍵掃描函數(shù) 放在定時中斷里
          13. void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01);
          14. void display_drive();//放在定時中斷里的數(shù)碼管驅(qū)動函數(shù)
          15. void time_service();//放在定時中斷里的時間應(yīng)用程序
          16. void display_service();
          17. sbit key_sr1=P0^0; //第一行輸入
          18. sbit key_sr2=P0^1; //第二行輸入
          19. sbit key_sr3=P0^2; //第三行輸入
          20. sbit key_sr4=P0^3; //第四行輸入
          21. sbit key_dr1=P0^4; //第一列輸出
          22. sbit key_dr2=P0^5; //第二列輸出
          23. sbit key_dr3=P0^6; //第三列輸出
          24. sbit key_dr4=P0^7; //第四列輸出
          25. sbit beep_dr=P2^7; //蜂鳴器的驅(qū)動IO口
          26. sbit led_dr=P3^5;//作為中途暫停指示燈 亮的時候表示中途暫停
          27. sbit dig_hc595_sh_dr=P2^0; //數(shù)碼管 的74HC595程序
          28. sbit dig_hc595_st_dr=P2^1;
          29. sbit dig_hc595_ds_dr=P2^2;
          30. sbit hc595_sh_dr=P2^3; //LED燈的74HC595程序
          31. sbit hc595_st_dr=P2^4;
          32. sbit hc595_ds_dr=P2^5;
          33. unsigned char ucKeyStep=1;//按鍵掃描步驟變量
          34. unsigned char ucKeySec=0; //被觸發(fā)的按鍵編號
          35. unsigned intuiKeyTimeCnt=0; //按鍵去抖動延時計數(shù)器
          36. unsigned char ucKeyLock=0; //按鍵觸發(fā)后自鎖的變量標志
          37. unsigned char ucRowRecord=1; //記錄當(dāng)前掃描到第幾列了
          38. unsigned intuiVoiceCnt=0;//蜂鳴器鳴叫的持續(xù)時間計數(shù)器
          39. unsigned char ucDigShow8=0;//第8位數(shù)碼管要顯示的內(nèi)容
          40. unsigned char ucDigShow7=0;//第7位數(shù)碼管要顯示的內(nèi)容
          41. unsigned char ucDigShow6=0;//第6位數(shù)碼管要顯示的內(nèi)容
          42. unsigned char ucDigShow5=0;//第5位數(shù)碼管要顯示的內(nèi)容
          43. unsigned char ucDigShow4=0;//第4位數(shù)碼管要顯示的內(nèi)容
          44. unsigned char ucDigShow3=0;//第3位數(shù)碼管要顯示的內(nèi)容
          45. unsigned char ucDigShow2=0;//第2位數(shù)碼管要顯示的內(nèi)容
          46. unsigned char ucDigShow1=0;//第1位數(shù)碼管要顯示的內(nèi)容
          47. unsigned char ucDigDot3=1;//數(shù)碼管3的小數(shù)點是否顯示的標志
          48. unsigned char ucDigDot7=1;//數(shù)碼管7的小數(shù)點是否顯示的標志
          49. unsigned char ucDigShowTemp=0; //臨時中間變量
          50. unsigned char ucDisplayDriveStep=1;//動態(tài)掃描數(shù)碼管的步驟變量
          51. unsigned int uiRedTimeCnt=0; //紅棋產(chǎn)生秒基準的時間計時器
          52. unsigned int uiBlackTimeCnt=0;//黑棋產(chǎn)生秒基準的時間計時器
          53. unsigned int uiRedTotal=1200; //紅棋的總時間
          54. unsigned int uiBlackTotal=1200;//黑棋的總時間
          55. unsigned char ucRedFlag=0;//紅棋是否開始計時的標志
          56. unsigned char ucBlackFlag=0;//黑棋是否開始計時的標志
          57. unsigned char ucDisplayUpdate=1; //更新顯示標志
          58. /* 注釋一:
          59. *ucWd變量是本程序最核心的變量,代表顯示哪一個窗口和系統(tǒng)處于當(dāng)前哪種狀態(tài)
          60. */
          61. unsigned char ucWd=1;
          62. code unsigned char dig_table[]=
          63. {
          64. 0x3f,//0 序號0
          65. 0x06,//1 序號1
          66. 0x5b,//2 序號2
          67. 0x4f,//3 序號3
          68. 0x66,//4 序號4
          69. 0x6d,//5 序號5
          70. 0x7d,//6 序號6
          71. 0x07,//7 序號7
          72. 0x7f,//8 序號8
          73. 0x6f,//9 序號9
          74. 0x00,//不顯示序號10
          75. };
          76. void main()
          77. {
          78. initial_myself();
          79. delay_long(100);
          80. initial_peripheral();
          81. while(1)
          82. {
          83. key_service();
          84. display_service();
          85. }
          86. }
          87. void time_service()//放在定時中斷里的時間應(yīng)用程序
          88. {
          89. if(ucRedFlag==1)//1代表紅棋在運行中
          90. {
          91. uiRedTimeCnt++;
          92. if(uiRedTimeCnt>const_1s)
          93. {
          94. uiRedTimeCnt=0;
          95. if(uiRedTotal>0)
          96. {
          97. uiRedTotal--;
          98. }
          99. else//時間到
          100. {
          101. ucRedFlag=0; //紅棋和黑棋同時停止計時
          102. ucBlackFlag=0;
          103. ucWd=1;//切換到第一個窗口的狀態(tài)
          104. uiVoiceCnt=const_voice_long; //報警聲音觸發(fā)
          105. }
          106. ucDisplayUpdate=1;//更新顯示
          107. }
          108. }
          109. if(ucBlackFlag==1)//1代表黑棋在運行中
          110. {
          111. uiBlackTimeCnt++;
          112. if(uiBlackTimeCnt>const_1s)
          113. {
          114. uiBlackTimeCnt=0;
          115. if(uiBlackTotal>0)
          116. {
          117. uiBlackTotal--;
          118. }
          119. else//時間到
          120. {
          121. ucRedFlag=0;//紅棋和黑棋同時停止計時
          122. ucBlackFlag=0;
          123. ucWd=1;//切換到第一個窗口的狀態(tài)
          124. uiVoiceCnt=const_voice_long; //報警聲音觸發(fā)
          125. }
          126. ucDisplayUpdate=1;//更新顯示
          127. }
          128. }
          129. }
          130. void display_service()//放在定時中斷里的顯示應(yīng)用程序
          131. {
          132. if(ucDisplayUpdate==1)//有數(shù)據(jù)更新顯示
          133. {
          134. ucDisplayUpdate=0;
          135. switch(ucWd) //本程序最核心的變量ucWd
          136. {
          137. case 1://窗口1,代表剛上電或者復(fù)位后的狀態(tài)
          138. //紅棋分解出分
          139. ucDigShowTemp=uiRedTotal/60;
          140. ucDigShow8=ucDigShowTemp/10;
          141. ucDigShow7=ucDigShowTemp%10;
          142. //紅棋分解出秒
          143. ucDigShowTemp=uiRedTotal%60;
          144. ucDigShow6=ucDigShowTemp/10;
          145. ucDigShow5=ucDigShowTemp%10;
          146. ucDigDot7=1;//數(shù)碼管7的小數(shù)點顯示
          147. //黑棋分解出分
          148. ucDigShowTemp=uiBlackTotal/60;
          149. ucDigShow4=ucDigShowTemp/10;
          150. ucDigShow3=ucDigShowTemp%10;
          151. //黑棋分解出秒
          152. ucDigShowTemp=uiBlackTotal%60;
          153. ucDigShow2=ucDigShowTemp/10;
          154. ucDigShow1=ucDigShowTemp%10;
          155. ucDigDot3=1;//數(shù)碼管3的小數(shù)點顯示
          156. led_dr=1;//計時器處于停止狀態(tài),LED亮
          157. break;
          158. case 2://窗口2,代表黑棋正在運行中的狀態(tài)
          159. //紅棋全部不顯示
          160. ucDigShow8=10;
          161. ucDigShow7=10;
          162. ucDigShow6=10;
          163. ucDigShow5=10;
          164. ucDigDot7=0;//數(shù)碼管7的小數(shù)點不顯示
          165. //黑棋分解出分
          166. ucDigShowTemp=uiBlackTotal/60;
          167. ucDigShow4=ucDigShowTemp/10;
          168. ucDigShow3=ucDigShowTemp%10;
          169. //黑棋分解出秒
          170. ucDigShowTemp=uiBlackTotal%60;
          171. ucDigShow2=ucDigShowTemp/10;
          172. ucDigShow1=ucDigShowTemp%10;
          173. ucDigDot3=1;//數(shù)碼管3的小數(shù)點顯示
          174. led_dr=0;//計時器處于計時狀態(tài),LED滅
          175. break;
          176. case 3://窗口3,代表黑棋在中途暫停的狀態(tài)
          177. //紅棋全部不顯示
          178. ucDigShow8=10;
          179. ucDigShow7=10;
          180. ucDigShow6=10;
          181. ucDigShow5=10;
          182. ucDigDot7=0;//數(shù)碼管7的小數(shù)點不顯示
          183. //黑棋分解出分
          184. ucDigShowTemp=uiBlackTotal/60;
          185. ucDigShow4=ucDigShowTemp/10;
          186. ucDigShow3=ucDigShowTemp%10;
          187. //黑棋分解出秒
          188. ucDigShowTemp=uiBlackTotal%60;
          189. ucDigShow2=ucDigShowTemp/10;
          190. ucDigShow1=ucDigShowTemp%10;
          191. ucDigDot3=1;//數(shù)碼管3的小數(shù)點顯示
          192. led_dr=1;//計時器處于暫停狀態(tài),LED亮
          193. break;
          194. case 4://窗口4,代表紅棋正在運行中的狀態(tài)
          195. //紅棋分解出分
          196. ucDigShowTemp=uiRedTotal/60;
          197. ucDigShow8=ucDigShowTemp/10;
          198. ucDigShow7=ucDigShowTemp%10;
          199. //紅棋分解出秒
          200. ucDigShowTemp=uiRedTotal%60;
          201. ucDigShow6=ucDigShowTemp/10;
          202. ucDigShow5=ucDigShowTemp%10;
          203. ucDigDot7=1;//數(shù)碼管7的小數(shù)點顯示
          204. //黑棋全部不顯示
          205. ucDigShow4=10;
          206. ucDigShow3=10;
          207. ucDigShow2=10;
          208. ucDigShow1=10;
          209. ucDigDot3=0;//數(shù)碼管3的小數(shù)點不顯示
          210. led_dr=0;//計時器處于倒計時狀態(tài),LED滅
          211. break;
          212. case 5://窗口5,代表紅棋在中途暫停的狀態(tài)
          213. //紅棋分解出分
          214. ucDigShowTemp=uiRedTotal/60;
          215. ucDigShow8=ucDigShowTemp/10;
          216. ucDigShow7=ucDigShowTemp%10;
          217. //紅棋分解出秒
          218. ucDigShowTemp=uiRedTotal%60;
          219. ucDigShow6=ucDigShowTemp/10;
          220. ucDigShow5=ucDigShowTemp%10;
          221. ucDigDot7=1;//數(shù)碼管7的小數(shù)點顯示
          222. //黑棋全部不顯示
          223. ucDigShow4=10;
          224. ucDigShow3=10;
          225. ucDigShow2=10;
          226. ucDigShow1=10;
          227. ucDigDot3=0;//數(shù)碼管3的小數(shù)點不顯示
          228. led_dr=1;//計時器處于暫停狀態(tài),LED亮
          229. break;
          230. }
          231. }
          232. }
          233. void display_drive()//放在定時中斷里的數(shù)碼管驅(qū)動函數(shù)
          234. {
          235. //以下程序,如果加一些數(shù)組和移位的元素,還可以壓縮容量。但是鴻哥追求的不是容量,而是清晰的講解思路
          236. switch(ucDisplayDriveStep)
          237. {
          238. case 1://顯示第1位
          239. ucDigShowTemp=dig_table[ucDigShow1];
          240. dig_hc595_drive(ucDigShowTemp,0xfe);
          241. break;
          242. case 2://顯示第2位
          243. ucDigShowTemp=dig_table[ucDigShow2];
          244. dig_hc595_drive(ucDigShowTemp,0xfd);
          245. break;
          246. case 3://顯示第3位
          247. ucDigShowTemp=dig_table[ucDigShow3];
          248. if(ucDigDot3==1)
          249. {
          250. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點
          251. }
          252. dig_hc595_drive(ucDigShowTemp,0xfb);
          253. break;
          254. case 4://顯示第4位
          255. ucDigShowTemp=dig_table[ucDigShow4];
          256. dig_hc595_drive(ucDigShowTemp,0xf7);
          257. break;
          258. case 5://顯示第5位
          259. ucDigShowTemp=dig_table[ucDigShow5];
          260. dig_hc595_drive(ucDigShowTemp,0xef);
          261. break;
          262. case 6://顯示第6位
          263. ucDigShowTemp=dig_table[ucDigShow6];
          264. dig_hc595_drive(ucDigShowTemp,0xdf);
          265. break;
          266. case 7://顯示第7位
          267. ucDigShowTemp=dig_table[ucDigShow7];
          268. if(ucDigDot7==1)
          269. {
          270. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點
          271. }
          272. dig_hc595_drive(ucDigShowTemp,0xbf);
          273. break;
          274. case 8://顯示第8位
          275. ucDigShowTemp=dig_table[ucDigShow8];
          276. dig_hc595_drive(ucDigShowTemp,0x7f);
          277. break;
          278. }
          279. ucDisplayDriveStep++;
          280. if(ucDisplayDriveStep>8)//掃描完8個數(shù)碼管后,重新從第一個開始掃描
          281. {
          282. ucDisplayDriveStep=1;
          283. }
          284. }
          285. //數(shù)碼管的74HC595驅(qū)動函數(shù)
          286. void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01)
          287. {
          288. unsigned char i;
          289. unsigned char ucTempData;
          290. dig_hc595_sh_dr=0;
          291. dig_hc595_st_dr=0;
          292. ucTempData=ucDigStatusTemp16_09;//先送高8位
          293. for(i=0;i<8;i++)
          294. {
          295. if(ucTempData>=0x80)dig_hc595_ds_dr=1;
          296. else dig_hc595_ds_dr=0;
          297. /* 注釋二:
          298. *注意,此處的延時delay_short必須盡可能小,否則動態(tài)掃描數(shù)碼管的速度就不夠。
          299. */
          300. dig_hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
          301. delay_short(1);
          302. dig_hc595_sh_dr=1;
          303. delay_short(1);
          304. ucTempData=ucTempData<<1;
          305. }
          306. ucTempData=ucDigStatusTemp08_01;//再先送低8位
          307. for(i=0;i<8;i++)
          308. {
          309. if(ucTempData>=0x80)dig_hc595_ds_dr=1;
          310. else dig_hc595_ds_dr=0;
          311. dig_hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
          312. delay_short(1);
          313. dig_hc595_sh_dr=1;
          314. delay_short(1);
          315. ucTempData=ucTempData<<1;
          316. }
          317. dig_hc595_st_dr=0;//ST引腳把兩個寄存器的數(shù)據(jù)更新輸出到74HC595的輸出引腳上并且鎖存起來
          318. delay_short(1);
          319. dig_hc595_st_dr=1;
          320. delay_short(1);
          321. dig_hc595_sh_dr=0; //拉低,抗干擾就增強
          322. dig_hc595_st_dr=0;
          323. dig_hc595_ds_dr=0;
          324. }
          325. //LED燈的74HC595驅(qū)動函數(shù)
          326. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01)
          327. {
          328. unsigned char i;
          329. unsigned char ucTempData;
          330. hc595_sh_dr=0;
          331. hc595_st_dr=0;
          332. ucTempData=ucLedStatusTemp16_09;//先送高8位
          333. for(i=0;i<8;i++)
          334. {
          335. if(ucTempData>=0x80)hc595_ds_dr=1;
          336. else hc595_ds_dr=0;
          337. hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
          338. delay_short(1);
          339. hc595_sh_dr=1;
          340. delay_short(1);
          341. ucTempData=ucTempData<<1;
          342. }
          343. ucTempData=ucLedStatusTemp08_01;//再先送低8位
          344. for(i=0;i<8;i++)
          345. {
          346. if(ucTempData>=0x80)hc595_ds_dr=1;
          347. else hc595_ds_dr=0;
          348. hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
          349. delay_short(1);
          350. hc595_sh_dr=1;
          351. delay_short(1);
          352. ucTempData=ucTempData<<1;
          353. }
          354. hc595_st_dr=0;//ST引腳把兩個寄存器的數(shù)據(jù)更新輸出到74HC595的輸出引腳上并且鎖存起來
          355. delay_short(1);
          356. hc595_st_dr=1;
          357. delay_short(1);
          358. hc595_sh_dr=0; //拉低,抗干擾就增強
          359. hc595_st_dr=0;
          360. hc595_ds_dr=0;
          361. }
          362. void key_scan()//按鍵掃描函數(shù) 放在定時中斷里
          363. {
          364. switch(ucKeyStep)
          365. {
          366. case 1: //按鍵掃描輸出第ucRowRecord列低電平
          367. if(ucRowRecord==1)//第一列輸出低電平
          368. {
          369. key_dr1=0;
          370. key_dr2=1;
          371. key_dr3=1;
          372. key_dr4=1;
          373. }
          374. else if(ucRowRecord==2)//第二列輸出低電平
          375. {
          376. key_dr1=1;
          377. key_dr2=0;
          378. key_dr3=1;
          379. key_dr4=1;
          380. }
          381. else if(ucRowRecord==3)//第三列輸出低電平
          382. {
          383. key_dr1=1;
          384. key_dr2=1;
          385. key_dr3=0;
          386. key_dr4=1;
          387. }
          388. else //第四列輸出低電平
          389. {
          390. key_dr1=1;
          391. key_dr2=1;
          392. key_dr3=1;
          393. key_dr4=0;
          394. }
          395. uiKeyTimeCnt=0;//延時計數(shù)器清零
          396. ucKeyStep++; //切換到下一個運行步驟
          397. break;
          398. case 2: //此處的小延時用來等待剛才列輸出信號穩(wěn)定,再判斷輸入信號。不是去抖動延時。
          399. uiKeyTimeCnt++;
          400. if(uiKeyTimeCnt>1)
          401. {
          402. uiKeyTimeCnt=0;
          403. ucKeyStep++; //切換到下一個運行步驟
          404. }
          405. break;
          406. case 3:
          407. if(key_sr1==1&&key_sr2==1&&key_sr3==1&&key_sr4==1)
          408. {
          409. ucKeyStep=1;//如果沒有按鍵按下,返回到第一個運行步驟重新開始掃描
          410. ucKeyLock=0;//按鍵自鎖標志清零
          411. uiKeyTimeCnt=0; //按鍵去抖動延時計數(shù)器清零,此行非常巧妙
          412. ucRowRecord++;//輸出下一列
          413. if(ucRowRecord>4)
          414. {
          415. ucRowRecord=1; //依次輸出完四列之后,繼續(xù)從第一列開始輸出低電平
          416. }
          417. }
          418. else if(ucKeyLock==0)//有按鍵按下,且是第一次觸發(fā)
          419. {
          420. if(key_sr1==0&&key_sr2==1&&key_sr3==1&&key_sr4==1)
          421. {
          422. uiKeyTimeCnt++;//去抖動延時計數(shù)器
          423. if(uiKeyTimeCnt>const_key_time)
          424. {
          425. uiKeyTimeCnt=0;
          426. ucKeyLock=1;//自鎖按鍵置位,避免一直觸發(fā),只有松開按鍵,此標志位才會被清零
          427. if(ucRowRecord==1)//第一列輸出低電平
          428. {
          429. ucKeySec=1;//觸發(fā)1號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S1鍵
          430. }
          431. else if(ucRowRecord==2)//第二列輸出低電平
          432. {
          433. ucKeySec=2;//觸發(fā)2號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S2鍵
          434. }
          435. else if(ucRowRecord==3)//第三列輸出低電平
          436. {
          437. ucKeySec=3;//觸發(fā)3號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S3鍵
          438. }
          439. else //第四列輸出低電平
          440. {
          441. ucKeySec=4;//觸發(fā)4號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S4鍵
          442. }
          443. }
          444. }
          445. else if(key_sr1==1&&key_sr2==0&&key_sr3==1&&key_sr4==1)
          446. {
          447. uiKeyTimeCnt++;//去抖動延時計數(shù)器
          448. if(uiKeyTimeCnt>const_key_time)
          449. {
          450. uiKeyTimeCnt=0;
          451. ucKeyLock=1;//自鎖按鍵置位,避免一直觸發(fā),只有松開按鍵,此標志位才會被清零
          452. if(ucRowRecord==1)//第一列輸出低電平
          453. {
          454. ucKeySec=5;//觸發(fā)5號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S5鍵
          455. }
          456. else if(ucRowRecord==2)//第二列輸出低電平
          457. {
          458. ucKeySec=6;//觸發(fā)6號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S6鍵
          459. }
          460. else if(ucRowRecord==3)//第三列輸出低電平
          461. {
          462. ucKeySec=7;//觸發(fā)7號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S7鍵
          463. }
          464. else //第四列輸出低電平
          465. {
          466. ucKeySec=8;//觸發(fā)8號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S8鍵
          467. }
          468. }
          469. }
          470. else if(key_sr1==1&&key_sr2==1&&key_sr3==0&&key_sr4==1)
          471. {
          472. uiKeyTimeCnt++;//去抖動延時計數(shù)器
          473. if(uiKeyTimeCnt>const_key_time)
          474. {
          475. uiKeyTimeCnt=0;
          476. ucKeyLock=1;//自鎖按鍵置位,避免一直觸發(fā),只有松開按鍵,此標志位才會被清零
          477. if(ucRowRecord==1)//第一列輸出低電平
          478. {
          479. ucKeySec=9;//觸發(fā)9號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S9鍵
          480. }
          481. else if(ucRowRecord==2)//第二列輸出低電平
          482. {
          483. ucKeySec=10;//觸發(fā)10號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S10鍵
          484. }
          485. else if(ucRowRecord==3)//第三列輸出低電平
          486. {
          487. ucKeySec=11;//觸發(fā)11號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S11鍵
          488. }
          489. else //第四列輸出低電平
          490. {
          491. ucKeySec=12;//觸發(fā)12號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S12鍵
          492. }
          493. }
          494. }
          495. else if(key_sr1==1&&key_sr2==1&&key_sr3==1&&key_sr4==0)
          496. {
          497. uiKeyTimeCnt++;//去抖動延時計數(shù)器
          498. if(uiKeyTimeCnt>const_key_time)
          499. {
          500. uiKeyTimeCnt=0;
          501. ucKeyLock=1;//自鎖按鍵置位,避免一直觸發(fā),只有松開按鍵,此標志位才會被清零
          502. if(ucRowRecord==1)//第一列輸出低電平
          503. {
          504. ucKeySec=13;//觸發(fā)13號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S13鍵
          505. }
          506. else if(ucRowRecord==2)//第二列輸出低電平
          507. {
          508. ucKeySec=14;//觸發(fā)14號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S14鍵
          509. }
          510. else if(ucRowRecord==3)//第三列輸出低電平
          511. {
          512. ucKeySec=15;//觸發(fā)15號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S15鍵
          513. }
          514. else //第四列輸出低電平
          515. {
          516. ucKeySec=16;//觸發(fā)16號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S16鍵
          517. }
          518. }
          519. }
          520. }
          521. break;
          522. }
          523. }
          524. /* 注釋三:
          525. *按鍵服務(wù)程序操作的精髓在于根據(jù)當(dāng)前系統(tǒng)處于什么窗口下就執(zhí)行什么操作。
          526. *緊緊圍繞著不同的窗口ucWd來執(zhí)行不同的操作。
          527. */
          528. void key_service() //第三區(qū) 放在定時中斷里的按鍵服務(wù)應(yīng)用程序
          529. {
          530. switch(ucKeySec) //按鍵服務(wù)狀態(tài)切換
          531. {
          532. case 1:// 1號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S1鍵紅棋加分 按鍵
          533. switch(ucWd)//本程序最核心的變量ucWd
          534. {
          535. case 1://窗口1,代表剛上電,完成或者復(fù)位后的狀態(tài)
          536. uiRedTotal=uiRedTotal+60;//加紅棋分的時間,此處60秒代表一分
          537. if(uiRedTotal>5940)
          538. {
          539. uiRedTotal=5940;
          540. }
          541. uiRedTotal=uiRedTotal-(uiRedTotal%60);//去秒取整分
          542. ucDisplayUpdate=1;//更新顯示
          543. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
          544. break;
          545. case 2://窗口2,代表黑棋正在運行中的狀態(tài)
          546. break;
          547. case 3://窗口3,代表黑棋在中途暫停的狀態(tài)
          548. break;
          549. case 4://窗口4,代表紅棋正在運行中的狀態(tài)
          550. break;
          551. case 5://窗口5,代表紅棋在中途暫停的狀態(tài)
          552. break;
          553. }
          554. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
          555. break;
          556. case 2:// 2號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S2鍵紅棋減分 按鍵
          557. switch(ucWd)//本程序最核心的變量ucWd
          558. {
          559. case 1://窗口1,代表剛上電,完成或者復(fù)位后的狀態(tài)
          560. if(uiRedTotal>=60)
          561. {
          562. uiRedTotal=uiRedTotal-60;//減紅棋分的時間,此處60秒代表一分
          563. }
          564. uiRedTotal=uiRedTotal-(uiRedTotal%60);//去秒取整分
          565. ucDisplayUpdate=1;//更新顯示
          566. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
          567. break;
          568. case 2://窗口2,代表黑棋正在運行中的狀態(tài)
          569. break;
          570. case 3://窗口3,代表黑棋在中途暫停的狀態(tài)
          571. break;
          572. case 4://窗口4,代表紅棋正在運行中的狀態(tài)
          573. break;
          574. case 5://窗口5,代表紅棋在中途暫停的狀態(tài)
          575. break;
          576. }
          577. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
          578. break;
          579. case 3:// 3號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S3鍵黑棋加分 按鍵
          580. switch(ucWd)//本程序最核心的變量ucWd
          581. {
          582. case 1://窗口1,代表剛上電,完成或者復(fù)位后的狀態(tài)
          583. uiBlackTotal=uiBlackTotal+60;//加黑棋分的時間,此處60秒代表一分
          584. if(uiBlackTotal>5940)
          585. {
          586. uiBlackTotal=5940;
          587. }
          588. uiBlackTotal=uiBlackTotal-(uiBlackTotal%60);//去秒取整分
          589. ucDisplayUpdate=1;//更新顯示
          590. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
          591. break;
          592. case 2://窗口2,代表黑棋正在運行中的狀態(tài)
          593. break;
          594. case 3://窗口3,代表黑棋在中途暫停的狀態(tài)
          595. break;
          596. case 4://窗口4,代表紅棋正在運行中的狀態(tài)
          597. break;
          598. case 5://窗口5,代表紅棋在中途暫停的狀態(tài)
          599. break;
          600. }
          601. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
          602. break;
          603. case 4:// 4號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S4鍵黑棋減分 按鍵
          604. switch(ucWd)//本程序最核心的變量ucWd
          605. {
          606. case 1://窗口1,代表剛上電,完成或者復(fù)位后的狀態(tài)
          607. if(uiBlackTotal>=60)
          608. {
          609. uiBlackTotal=uiBlackTotal-60;//減黑棋分的時間,此處60秒代表一分
          610. }
          611. uiBlackTotal=uiBlackTotal-(uiBlackTotal%60);//去秒取整分
          612. ucDisplayUpdate=1;//更新顯示
          613. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
          614. break;
          615. case 2://窗口2,代表黑棋正在運行中的狀態(tài)
          616. break;
          617. case 3://窗口3,代表黑棋在中途暫停的狀態(tài)
          618. break;
          619. case 4://窗口4,代表紅棋正在運行中的狀態(tài)
          620. break;
          621. case 5://窗口5,代表紅棋在中途暫停的狀態(tài)
          622. break;
          623. }
          624. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
          625. break;
          626. case 5:// 5號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S5鍵
          627. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
          628. break;
          629. case 6:// 6號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S6鍵中途暫停和啟動按鍵
          630. switch(ucWd)//本程序最核心的變量ucWd
          631. {
          632. case 1://窗口1,代表剛上電,完成或者復(fù)位后的狀態(tài)
          633. break;
          634. case 2://窗口2,代表黑棋正在運行中的狀態(tài)
          635. ucRedFlag=0; //暫停計時
          636. ucBlackFlag=0;//暫停計時
          637. ucWd=3; //切換到黑棋中途暫停的狀態(tài)
          638. ucDisplayUpdate=1;//更新顯示
          639. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
          640. break;
          641. case 3://窗口3,代表黑棋在中途暫停的狀態(tài)
          642. ucRedFlag=0; //紅棋暫停計時
          643. ucBlackFlag=1; //黑棋繼續(xù)計時
          644. ucWd=2; //切換到黑棋正在運行中的狀態(tài)
          645. ucDisplayUpdate=1;//更新顯示
          646. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
          647. break;
          648. case 4://窗口4,代表紅棋正在運行中的狀態(tài)
          649. ucRedFlag=0; //暫停計時
          650. ucBlackFlag=0;//暫停計時
          651. ucWd=5; //切換到紅棋中途暫停的狀態(tài)
          652. ucDisplayUpdate=1;//更新顯示
          653. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
          654. break;
          655. case 5://窗口5,代表紅棋在中途暫停的狀態(tài)
          656. ucRedFlag=1; //紅棋繼續(xù)計時
          657. ucBlackFlag=0; //黑棋暫停計時
          658. ucWd=4; //切換到紅棋正在運行中的狀態(tài)
          659. ucDisplayUpdate=1;//更新顯示
          660. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
          661. break;
          662. }
          663. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
          664. break;
          665. case 7:// 7號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S7鍵在第一個窗口下,把計時器的值恢復(fù)為開機時的默認值20分鐘
          666. switch(ucWd)//本程序最核心的變量ucWd
          667. {
          668. case 1://窗口1,代表剛上電,完成或者復(fù)位后的狀態(tài)
          669. uiRedTotal=1200; //紅棋的總時間
          670. uiBlackTotal=1200;//黑棋的總時間
          671. ucDisplayUpdate=1;//更新顯示
          672. uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
          673. break;
          674. case 2://窗口2,代表黑棋正在運行中的狀態(tài)
          675. break;
          676. case 3://窗口3,代表黑棋在中途暫停的狀態(tài)
          677. break;
          678. case 4://窗口4,代表紅棋正在運行中的狀態(tài)
          679. break;
          680. case 5://窗口5,代表紅棋在中途暫停的狀態(tài)
          681. break;
          682. }
          683. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
          684. break;
          685. case 8:// 8號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S8鍵
          686. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
          687. break;
          688. case 9:// 9號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S9鍵
          689. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
          690. break;
          691. case 10:// 10號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S10鍵
          692. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
          693. break;
          694. case 11:// 11號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S11鍵
          695. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
          696. break;
          697. case 12:// 12號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S12鍵
          698. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
          699. break;
          700. case 13:// 13號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S13鍵紅棋按下
          701. switch(ucWd)//本程序最核心的變量ucWd
          702. {
          703. case 1://窗口1,代表剛上電,完成或者復(fù)位后的狀態(tài)
          704. ucRedFlag=0; //紅棋暫停計時
          705. ucBlackFlag=1;//黑棋繼續(xù)計時
          706. ucWd=2; //切換到黑棋正在運行中的狀態(tài)
          707. ucDisplayUpdate=1;//更新顯示
          708. break;
          709. case 2://窗口2,代表黑棋正在運行中的狀態(tài)
          710. break;
          711. case 3://窗口3,代表黑棋在中途暫停的狀態(tài)
          712. break;
          713. case 4://窗口4,代表紅棋正在運行中的狀態(tài)
          714. ucRedFlag=0; //紅棋暫停計時
          715. ucBlackFlag=1;//黑棋繼續(xù)計時
          716. ucWd=2; //切換到黑棋正在運行中的狀態(tài)
          717. ucDisplayUpdate=1;//更新顯示
          718. break;
          719. case 5://窗口5,代表紅棋在中途暫停的狀態(tài)
          720. break;
          721. }
          722. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
          723. break;
          724. case 14:// 14號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S14鍵
          725. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
          726. break;
          727. case 15:// 15號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S15鍵
          728. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
          729. break;
          730. case 16:// 16號鍵 對應(yīng)朱兆祺學(xué)習(xí)板的S16鍵 黑棋按下
          731. switch(ucWd)//本程序最核心的變量ucWd
          732. {
          733. case 1://窗口1,代表剛上電,完成或者復(fù)位后的狀態(tài)
          734. ucRedFlag=1; //紅棋繼續(xù)計時
          735. ucBlackFlag=0;//黑棋暫停計時
          736. ucWd=4; //切換到紅棋正在運行中的狀態(tài)
          737. ucDisplayUpdate=1;//更新顯示
          738. break;
          739. case 2://窗口2,代表黑棋正在運行中的狀態(tài)
          740. ucRedFlag=1; //紅棋繼續(xù)計時
          741. ucBlackFlag=0;//黑棋暫停計時
          742. ucWd=4; //切換到紅棋正在運行中的狀態(tài)
          743. ucDisplayUpdate=1;//更新顯示
          744. break;
          745. case 3://窗口3,代表黑棋在中途暫停的狀態(tài)
          746. break;
          747. case 4://窗口4,代表紅棋正在運行中的狀態(tài)
          748. break;
          749. case 5://窗口5,代表紅棋在中途暫停的狀態(tài)
          750. break;
          751. }
          752. ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號清零,避免一致觸發(fā)
          753. break;
          754. }
          755. }
          756. void T0_time() interrupt 1
          757. {
          758. TF0=0;//清除中斷標志
          759. TR0=0; //關(guān)中斷
          760. key_scan(); //放在定時中斷里的按鍵掃描函數(shù)
          761. time_service();//放在定時中斷里的時間應(yīng)用程序
          762. if(uiVoiceCnt!=0)
          763. {
          764. uiVoiceCnt--; //每次進入定時中斷都自減1,直到等于零為止。才停止鳴叫
          765. beep_dr=0;//蜂鳴器是PNP三極管控制,低電平就開始鳴叫。
          766. }
          767. else
          768. {
          769. ; //此處多加一個空指令,想維持跟if括號語句的數(shù)量對稱,都是兩條指令。不加也可以。
          770. beep_dr=1;//蜂鳴器是PNP三極管控制,高電平就停止鳴叫。
          771. }
          772. display_drive();//放在定時中斷里的數(shù)碼管驅(qū)動函數(shù)
          773. /* 注釋四:
          774. *注意,此處的重裝初始值不能太大,否則動態(tài)掃描數(shù)碼管的速度就不夠。我把原來常用的2000改成了500。
          775. */
          776. TH0=0xfe; //重裝初始值(65535-500)=65035=0xfe0b
          777. TL0=0x0b;
          778. TR0=1;//開中斷
          779. }
          780. void delay_short(unsigned int uiDelayShort)
          781. {
          782. unsigned int i;
          783. for(i=0;i
          784. {
          785. ; //一個分號相當(dāng)于執(zhí)行一條空語句
          786. }
          787. }
          788. void delay_long(unsigned int uiDelayLong)
          789. {
          790. unsigned int i;
          791. unsigned int j;
          792. for(i=0;i
          793. {
          794. for(j=0;j<500;j++)//內(nèi)嵌循環(huán)的空指令數(shù)量
          795. {
          796. ; //一個分號相當(dāng)于執(zhí)行一條空語句
          797. }
          798. }
          799. }
          800. void initial_myself()//第一區(qū) 初始化單片機
          801. {
          802. led_dr=1;
          803. beep_dr=1; //用PNP三極管控制蜂鳴器,輸出高電平時不叫。
          804. hc595_drive(0x00,0x00);
          805. TMOD=0x01;//設(shè)置定時器0為工作方式1
          806. TH0=0xfe; //重裝初始值(65535-500)=65035=0xfe0b
          807. TL0=0x0b;
          808. }
          809. void initial_peripheral() //第二區(qū) 初始化外圍
          810. {
          811. EA=1; //開總中斷
          812. ET0=1; //允許定時中斷
          813. TR0=1; //啟動定時中斷
          814. }


          總結(jié)陳詞:
          這節(jié)講了象棋比賽專用計時器的項目程序。為了繼續(xù)加深讀者理解按鍵和顯示是如何有規(guī)律關(guān)聯(lián)起來的,下節(jié)會繼續(xù)講一個相關(guān)的小項目程序。欲知詳情,請聽下回分解-----帶數(shù)碼管顯示的加法簡易計算器。


          評論


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