新聞中心

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)生一秒鐘的時間基準(zhǔ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ā)后自鎖的變量標(biāo)志
  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ù)點是否顯示的標(biāo)志
  48. unsigned char ucDigDot7=1;//數(shù)碼管7的小數(shù)點是否顯示的標(biāo)志
  49. unsigned char ucDigShowTemp=0; //臨時中間變量
  50. unsigned char ucDisplayDriveStep=1;//動態(tài)掃描數(shù)碼管的步驟變量
  51. unsigned int uiRedTimeCnt=0; //紅棋產(chǎn)生秒基準(zhǔn)的時間計時器
  52. unsigned int uiBlackTimeCnt=0;//黑棋產(chǎn)生秒基準(zhǔn)的時間計時器
  53. unsigned int uiRedTotal=1200; //紅棋的總時間
  54. unsigned int uiBlackTotal=1200;//黑棋的總時間
  55. unsigned char ucRedFlag=0;//紅棋是否開始計時的標(biāo)志
  56. unsigned char ucBlackFlag=0;//黑棋是否開始計時的標(biāo)志
  57. unsigned char ucDisplayUpdate=1; //更新顯示標(biāo)志
  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;//計時器處于停止?fàn)顟B(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;//按鍵自鎖標(biāo)志清零
  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ā),只有松開按鍵,此標(biāo)志位才會被清零
  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ā),只有松開按鍵,此標(biāo)志位才會被清零
  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ā),只有松開按鍵,此標(biāo)志位才會被清零
  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ā),只有松開按鍵,此標(biāo)志位才會被清零
  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;//清除中斷標(biāo)志
  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)閉