新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 第37節:數碼管作為儀表盤顯示跑馬燈的方向,速度和狀態

        第37節:數碼管作為儀表盤顯示跑馬燈的方向,速度和狀態

        作者: 時間:2016-11-22 來源:網絡 收藏
        開場白:
        我在第24節中講過按鍵控制跑馬燈的方向,速度和運行狀態的項目程序,只可惜那個程序不能直觀地顯示運行中的三種狀態,這節我決定在24節的基礎上,增加一個數碼管顯示作為類似汽車儀表盤的界面,實時顯示跑馬燈的方向,速度,和運行狀態。
        這一節要教會大家一個知識點:繼續加深理解運動,按鍵與數碼管三者之間的關聯程序框架。

        具體內容,請看源代碼講解。

        (1)硬件平臺:
        基于朱兆祺51單片機學習板。用S1鍵作為控制跑馬燈的方向按鍵,S5鍵作為控制跑馬燈方向的加速度按鍵,S9鍵作為控制跑馬燈方向的減速度按鍵,S13鍵作為控制跑馬燈方向的啟動或者暫停按鍵。記得把輸出線P0.4一直輸出低電平,模擬獨立按鍵的觸發地GND。

        (2)實現功能:
        跑馬燈運行:第1個至第8個LED燈一直不亮。在第9個至第16個LED燈,依次逐個亮燈并且每次只能亮一個燈。每按一次獨立按鍵S13鍵,原來運行的跑馬燈會暫停,原來暫停的跑馬燈會運行。用S1來改變方向。用S5和S9來改變速度,每按一次按鍵的遞增或者遞減以10為單位。
        數碼管顯示:本程序只有1個窗口,這個窗口分成3個局部顯示。8,7,6位數碼管顯示運行狀態,啟動時顯示“on”,停止時顯示“oFF”。5位數碼管顯示數碼管方向,正向顯示“n”,反向顯示“U”。4,3,2,1位數碼管顯示速度。數值越大速度越慢,最慢的速度是550,最快的速度是50。

        (3)源代碼講解如下:
        1. #include "REG52.H"
        2. #define const_voice_short40 //蜂鳴器短叫的持續時間
        3. #define const_key_time120 //按鍵去抖動延時的時間
        4. #define const_key_time220 //按鍵去抖動延時的時間
        5. #define const_key_time320 //按鍵去抖動延時的時間
        6. #define const_key_time420 //按鍵去抖動延時的時間
        7. void initial_myself();
        8. void initial_peripheral();
        9. void delay_short(unsigned int uiDelayShort);
        10. void delay_long(unsigned int uiDelaylong);
        11. //驅動數碼管的74HC595
        12. void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01);
        13. void display_drive(); //顯示數碼管字模的驅動函數
        14. void display_service(); //顯示的窗口菜單服務程序
        15. //驅動LED的74HC595
        16. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01);
        17. void led_flicker_09_16(); //第9個至第16個LED的跑馬燈程序,逐個亮并且每次只能亮一個.
        18. void led_update();//LED更新函數
        19. void T0_time();//定時中斷函數
        20. void key_service(); //按鍵服務的應用程序
        21. void key_scan();//按鍵掃描函數 放在定時中斷里
        22. sbit beep_dr=P2^7; //蜂鳴器的驅動IO口
        23. sbit key_sr1=P0^0; //對應朱兆祺學習板的S1鍵
        24. sbit key_sr2=P0^1; //對應朱兆祺學習板的S5鍵
        25. sbit key_sr3=P0^2; //對應朱兆祺學習板的S9鍵
        26. sbit key_sr4=P0^3; //對應朱兆祺學習板的S13鍵
        27. sbit key_gnd_dr=P0^4; //模擬獨立按鍵的地GND,因此必須一直輸出低電平
        28. sbit led_dr=P3^5;
        29. sbit dig_hc595_sh_dr=P2^0; //數碼管的74HC595程序
        30. sbit dig_hc595_st_dr=P2^1;
        31. sbit dig_hc595_ds_dr=P2^2;
        32. sbit hc595_sh_dr=P2^3; //LED燈的74HC595程序
        33. sbit hc595_st_dr=P2^4;
        34. sbit hc595_ds_dr=P2^5;
        35. unsigned char ucKeySec=0; //被觸發的按鍵編號
        36. unsigned intuiKeyTimeCnt1=0; //按鍵去抖動延時計數器
        37. unsigned char ucKeyLock1=0; //按鍵觸發后自鎖的變量標志
        38. unsigned intuiKeyTimeCnt2=0; //按鍵去抖動延時計數器
        39. unsigned char ucKeyLock2=0; //按鍵觸發后自鎖的變量標志
        40. unsigned intuiKeyTimeCnt3=0; //按鍵去抖動延時計數器
        41. unsigned char ucKeyLock3=0; //按鍵觸發后自鎖的變量標志
        42. unsigned intuiKeyTimeCnt4=0; //按鍵去抖動延時計數器
        43. unsigned char ucKeyLock4=0; //按鍵觸發后自鎖的變量標志
        44. unsigned intuiVoiceCnt=0;//蜂鳴器鳴叫的持續時間計數器
        45. unsigned char ucLed_dr1=0; //代表16個燈的亮滅狀態,0代表滅,1代表亮
        46. unsigned char ucLed_dr2=0;
        47. unsigned char ucLed_dr3=0;
        48. unsigned char ucLed_dr4=0;
        49. unsigned char ucLed_dr5=0;
        50. unsigned char ucLed_dr6=0;
        51. unsigned char ucLed_dr7=0;
        52. unsigned char ucLed_dr8=0;
        53. unsigned char ucLed_dr9=0;
        54. unsigned char ucLed_dr10=0;
        55. unsigned char ucLed_dr11=0;
        56. unsigned char ucLed_dr12=0;
        57. unsigned char ucLed_dr13=0;
        58. unsigned char ucLed_dr14=0;
        59. unsigned char ucLed_dr15=0;
        60. unsigned char ucLed_dr16=0;
        61. unsigned char ucLed_update=0;//刷新變量。每次更改LED燈的狀態都要更新一次。
        62. unsigned char ucLedStep_09_16=0; //第9個至第16個LED跑馬燈的步驟變量
        63. unsigned intuiTimeCnt_09_16=0; //第9個至第16個LED跑馬燈的統計定時中斷次數的延時計數器
        64. unsigned char ucLedStatus16_09=0; //代表底層74HC595輸出狀態的中間變量
        65. unsigned char ucLedStatus08_01=0; //代表底層74HC595輸出狀態的中間變量
        66. unsigned char ucLedDirFlag=0; //方向變量,把按鍵與跑馬燈關聯起來的核心變量,0代表正方向,1代表反方向
        67. unsigned intuiSetTimeLevel_09_16=300;//速度變量,此數值越大速度越慢,此數值越小速度越快。
        68. unsigned char ucLedStartFlag=1; //啟動和暫停的變量,0代表暫停,1代表啟動
        69. unsigned char ucDigShow8;//第8位數碼管要顯示的內容
        70. unsigned char ucDigShow7;//第7位數碼管要顯示的內容
        71. unsigned char ucDigShow6;//第6位數碼管要顯示的內容
        72. unsigned char ucDigShow5;//第5位數碼管要顯示的內容
        73. unsigned char ucDigShow4;//第4位數碼管要顯示的內容
        74. unsigned char ucDigShow3;//第3位數碼管要顯示的內容
        75. unsigned char ucDigShow2;//第2位數碼管要顯示的內容
        76. unsigned char ucDigShow1;//第1位數碼管要顯示的內容
        77. unsigned char ucDigDot8;//數碼管8的小數點是否顯示的標志
        78. unsigned char ucDigDot7;//數碼管7的小數點是否顯示的標志
        79. unsigned char ucDigDot6;//數碼管6的小數點是否顯示的標志
        80. unsigned char ucDigDot5;//數碼管5的小數點是否顯示的標志
        81. unsigned char ucDigDot4;//數碼管4的小數點是否顯示的標志
        82. unsigned char ucDigDot3;//數碼管3的小數點是否顯示的標志
        83. unsigned char ucDigDot2;//數碼管2的小數點是否顯示的標志
        84. unsigned char ucDigDot1;//數碼管1的小數點是否顯示的標志
        85. unsigned char ucDigShowTemp=0; //臨時中間變量
        86. unsigned char ucDisplayDriveStep=1;//動態掃描數碼管的步驟變量
        87. unsigned char ucWd1Part1Update=1;//窗口1的局部1更新顯示變量
        88. unsigned char ucWd1Part2Update=1;//窗口1的局部2更新顯示變量
        89. unsigned char ucWd1Part3Update=1;//窗口1的局部3更新顯示變量
        90. //根據原理圖得出的共陰數碼管字模表
        91. code unsigned char dig_table[]=
        92. {
        93. 0x3f,//0 序號0
        94. 0x06,//1 序號1
        95. 0x5b,//2 序號2
        96. 0x4f,//3 序號3
        97. 0x66,//4 序號4
        98. 0x6d,//5 序號5
        99. 0x7d,//6 序號6
        100. 0x07,//7 序號7
        101. 0x7f,//8 序號8
        102. 0x6f,//9 序號9
        103. 0x00,//無 序號10
        104. 0x40,//- 序號11
        105. 0x73,//P 序號12
        106. 0x5c,//o 序號13
        107. 0x71,//F 序號14
        108. 0x3e,//U 序號15
        109. 0x37,//n 序號16
        110. };
        111. void main()
        112. {
        113. initial_myself();
        114. delay_long(100);
        115. initial_peripheral();
        116. while(1)
        117. {
        118. key_service(); //按鍵服務的應用程序
        119. display_service(); //顯示的窗口菜單服務程序
        120. led_flicker_09_16(); //第9個至第16個LED的跑馬燈程序,逐個亮并且每次只能亮一個.
        121. led_update();//LED更新函數
        122. }
        123. }
        124. /* 注釋一:
        125. * 由于本程序只有1個窗口,而這個窗口又分成3個局部,因此可以省略去窗口變量uWd,
        126. * 只用三個局部變量ucWdxPartyUpdate就可以了。
        127. */
        128. void display_service() //顯示的窗口菜單服務程序
        129. {
        130. if(ucWd1Part1Update==1) //更新顯示當前系統是處于運行還是暫停的狀態
        131. {
        132. ucWd1Part1Update=0; //及時把更新變量清零,防止一直進來更新
        133. if(ucLedStartFlag==1)//啟動,顯示on
        134. {
        135. ucDigShow8=13;//顯示o
        136. ucDigShow7=16;//顯示n
        137. ucDigShow6=10;//顯示空
        138. }
        139. else//暫停,顯示oFF
        140. {
        141. ucDigShow8=13;//顯示o
        142. ucDigShow7=14;//顯示F
        143. ucDigShow6=14;//顯示F
        144. }
        145. }
        146. if(ucWd1Part2Update==1) //更新顯示當前系統是處于正方向還是反方向
        147. {
        148. ucWd1Part2Update=0; //及時把更新變量清零,防止一直進來更新
        149. if(ucLedDirFlag==0)//正方向,向上,顯示n
        150. {
        151. ucDigShow5=16;//顯示n
        152. }
        153. else//反方向,向下,顯示U
        154. {
        155. ucDigShow5=15;//顯示U
        156. }
        157. }
        158. if(ucWd1Part3Update==1) //更新顯示當前系統的速度,此數值越大速度越慢,此數值越小速度越快。
        159. {
        160. ucWd1Part3Update=0; //及時把更新變量清零,防止一直進來更新
        161. ucDigShow4=10;//顯示空這一位不用,作為空格
        162. if(uiSetTimeLevel_09_16>=100)
        163. {
        164. ucDigShow3=uiSetTimeLevel_09_16/100; //顯示速度的百位
        165. }
        166. else
        167. {
        168. ucDigShow3=10; //顯示空
        169. }
        170. if(uiSetTimeLevel_09_16>=10)
        171. {
        172. ucDigShow2=uiSetTimeLevel_09_16%100/10;//顯示速度的十位
        173. }
        174. else
        175. {
        176. ucDigShow2=10; //顯示空
        177. }
        178. ucDigShow1=uiSetTimeLevel_09_16%10; //顯示速度的個位
        179. }
        180. }
        181. void key_scan()//按鍵掃描函數 放在定時中斷里
        182. {
        183. if(key_sr1==1)//IO是高電平,說明按鍵沒有被按下,這時要及時清零一些標志位
        184. {
        185. ucKeyLock1=0; //按鍵自鎖標志清零
        186. uiKeyTimeCnt1=0;//按鍵去抖動延時計數器清零,此行非常巧妙,是我實戰中摸索出來的。
        187. }
        188. else if(ucKeyLock1==0)//有按鍵按下,且是第一次被按下
        189. {
        190. uiKeyTimeCnt1++; //累加定時中斷次數
        191. if(uiKeyTimeCnt1>const_key_time1)
        192. {
        193. uiKeyTimeCnt1=0;
        194. ucKeyLock1=1;//自鎖按鍵置位,避免一直觸發
        195. ucKeySec=1; //觸發1號鍵
        196. }
        197. }
        198. if(key_sr2==1)//IO是高電平,說明按鍵沒有被按下,這時要及時清零一些標志位
        199. {
        200. ucKeyLock2=0; //按鍵自鎖標志清零
        201. uiKeyTimeCnt2=0;//按鍵去抖動延時計數器清零,此行非常巧妙,是我實戰中摸索出來的。
        202. }
        203. else if(ucKeyLock2==0)//有按鍵按下,且是第一次被按下
        204. {
        205. uiKeyTimeCnt2++; //累加定時中斷次數
        206. if(uiKeyTimeCnt2>const_key_time2)
        207. {
        208. uiKeyTimeCnt2=0;
        209. ucKeyLock2=1;//自鎖按鍵置位,避免一直觸發
        210. ucKeySec=2; //觸發2號鍵
        211. }
        212. }
        213. if(key_sr3==1)//IO是高電平,說明按鍵沒有被按下,這時要及時清零一些標志位
        214. {
        215. ucKeyLock3=0; //按鍵自鎖標志清零
        216. uiKeyTimeCnt3=0;//按鍵去抖動延時計數器清零,此行非常巧妙,是我實戰中摸索出來的。
        217. }
        218. else if(ucKeyLock3==0)//有按鍵按下,且是第一次被按下
        219. {
        220. uiKeyTimeCnt3++; //累加定時中斷次數
        221. if(uiKeyTimeCnt3>const_key_time3)
        222. {
        223. uiKeyTimeCnt3=0;
        224. ucKeyLock3=1;//自鎖按鍵置位,避免一直觸發
        225. ucKeySec=3; //觸發3號鍵
        226. }
        227. }
        228. if(key_sr4==1)//IO是高電平,說明按鍵沒有被按下,這時要及時清零一些標志位
        229. {
        230. ucKeyLock4=0; //按鍵自鎖標志清零
        231. uiKeyTimeCnt4=0;//按鍵去抖動延時計數器清零,此行非常巧妙,是我實戰中摸索出來的。
        232. }
        233. else if(ucKeyLock4==0)//有按鍵按下,且是第一次被按下
        234. {
        235. uiKeyTimeCnt4++; //累加定時中斷次數
        236. if(uiKeyTimeCnt4>const_key_time4)
        237. {
        238. uiKeyTimeCnt4=0;
        239. ucKeyLock4=1;//自鎖按鍵置位,避免一直觸發
        240. ucKeySec=4; //觸發4號鍵
        241. }
        242. }
        243. }
        244. void key_service() //按鍵服務的應用程序
        245. {
        246. switch(ucKeySec) //按鍵服務狀態切換
        247. {
        248. case 1:// 改變跑馬燈方向的按鍵 對應朱兆祺學習板的S1鍵
        249. if(ucLedDirFlag==0) //通過中間變量改變跑馬燈的方向
        250. {
        251. ucLedDirFlag=1;
        252. }
        253. else
        254. {
        255. ucLedDirFlag=0;
        256. }
        257. ucWd1Part2Update=1; //及時更新顯示方向
        258. uiVoiceCnt=const_voice_short; //按鍵聲音觸發,滴一聲就停。
        259. ucKeySec=0;//響應按鍵服務處理程序后,按鍵編號清零,避免一致觸發
        260. break;
        261. case 2:// 加速按鍵 對應朱兆祺學習板的S5鍵 uiSetTimeLevel_09_16越小速度越快
        262. uiSetTimeLevel_09_16=uiSetTimeLevel_09_16-10;
        263. if(uiSetTimeLevel_09_16<50)//最快限定在50
        264. {
        265. uiSetTimeLevel_09_16=50;
        266. }
        267. ucWd1Part3Update=1; //及時更新顯示速度
        268. uiVoiceCnt=const_voice_short; //按鍵聲音觸發,滴一聲就停。
        269. ucKeySec=0;//響應按鍵服務處理程序后,按鍵編號清零,避免一致觸發
        270. break;
        271. case 3:// 減速按鍵 對應朱兆祺學習板的S9鍵uiSetTimeLevel_09_16越大速度越慢
        272. uiSetTimeLevel_09_16=uiSetTimeLevel_09_16+10;
        273. if(uiSetTimeLevel_09_16>550)//最慢限定在550
        274. {
        275. uiSetTimeLevel_09_16=550;
        276. }
        277. ucWd1Part3Update=1; //及時更新顯示速度
        278. uiVoiceCnt=const_voice_short; //按鍵聲音觸發,滴一聲就停。
        279. ucKeySec=0;//響應按鍵服務處理程序后,按鍵編號清零,避免一致觸發
        280. break;
        281. case 4:// 啟動和暫停按鍵 對應朱兆祺學習板的S13鍵ucLedStartFlag為0時代表暫停,為1時代表啟動
        282. if(ucLedStartFlag==1)//啟動和暫停兩種狀態循環切換
        283. {
        284. ucLedStartFlag=0;
        285. }
        286. else //啟動和暫停兩種狀態循環切換
        287. {
        288. ucLedStartFlag=1;
        289. }
        290. ucWd1Part1Update=1; //及時更新顯示系統的運行狀態,是運行還是暫停.
        291. uiVoiceCnt=const_voice_short; //按鍵聲音觸發,滴一聲就停。
        292. ucKeySec=0;//響應按鍵服務處理程序后,按鍵編號清零,避免一致觸發
        293. break;
        294. }
        295. }
        296. void led_update()//LED更新函數
        297. {
        298. if(ucLed_update==1)
        299. {
        300. ucLed_update=0; //及時清零,讓它產生只更新一次的效果,避免一直更新。
        301. if(ucLed_dr1==1)
        302. {
        303. ucLedStatus08_01=ucLedStatus08_01|0x01;
        304. }
        305. else
        306. {
        307. ucLedStatus08_01=ucLedStatus08_01&0xfe;
        308. }
        309. if(ucLed_dr2==1)
        310. {
        311. ucLedStatus08_01=ucLedStatus08_01|0x02;
        312. }
        313. else
        314. {
        315. ucLedStatus08_01=ucLedStatus08_01&0xfd;
        316. }
        317. if(ucLed_dr3==1)
        318. {
        319. ucLedStatus08_01=ucLedStatus08_01|0x04;
        320. }
        321. else
        322. {
        323. ucLedStatus08_01=ucLedStatus08_01&0xfb;
        324. }
        325. if(ucLed_dr4==1)
        326. {
        327. ucLedStatus08_01=ucLedStatus08_01|0x08;
        328. }
        329. else
        330. {
        331. ucLedStatus08_01=ucLedStatus08_01&0xf7;
        332. }
        333. if(ucLed_dr5==1)
        334. {
        335. ucLedStatus08_01=ucLedStatus08_01|0x10;
        336. }
        337. else
        338. {
        339. ucLedStatus08_01=ucLedStatus08_01&0xef;
        340. }
        341. if(ucLed_dr6==1)
        342. {
        343. ucLedStatus08_01=ucLedStatus08_01|0x20;
        344. }
        345. else
        346. {
        347. ucLedStatus08_01=ucLedStatus08_01&0xdf;
        348. }
        349. if(ucLed_dr7==1)
        350. {
        351. ucLedStatus08_01=ucLedStatus08_01|0x40;
        352. }
        353. else
        354. {
        355. ucLedStatus08_01=ucLedStatus08_01&0xbf;
        356. }
        357. if(ucLed_dr8==1)
        358. {
        359. ucLedStatus08_01=ucLedStatus08_01|0x80;
        360. }
        361. else
        362. {
        363. ucLedStatus08_01=ucLedStatus08_01&0x7f;
        364. }
        365. if(ucLed_dr9==1)
        366. {
        367. ucLedStatus16_09=ucLedStatus16_09|0x01;
        368. }
        369. else
        370. {
        371. ucLedStatus16_09=ucLedStatus16_09&0xfe;
        372. }
        373. if(ucLed_dr10==1)
        374. {
        375. ucLedStatus16_09=ucLedStatus16_09|0x02;
        376. }
        377. else
        378. {
        379. ucLedStatus16_09=ucLedStatus16_09&0xfd;
        380. }
        381. if(ucLed_dr11==1)
        382. {
        383. ucLedStatus16_09=ucLedStatus16_09|0x04;
        384. }
        385. else
        386. {
        387. ucLedStatus16_09=ucLedStatus16_09&0xfb;
        388. }
        389. if(ucLed_dr12==1)
        390. {
        391. ucLedStatus16_09=ucLedStatus16_09|0x08;
        392. }
        393. else
        394. {
        395. ucLedStatus16_09=ucLedStatus16_09&0xf7;
        396. }
        397. if(ucLed_dr13==1)
        398. {
        399. ucLedStatus16_09=ucLedStatus16_09|0x10;
        400. }
        401. else
        402. {
        403. ucLedStatus16_09=ucLedStatus16_09&0xef;
        404. }
        405. if(ucLed_dr14==1)
        406. {
        407. ucLedStatus16_09=ucLedStatus16_09|0x20;
        408. }
        409. else
        410. {
        411. ucLedStatus16_09=ucLedStatus16_09&0xdf;
        412. }
        413. if(ucLed_dr15==1)
        414. {
        415. ucLedStatus16_09=ucLedStatus16_09|0x40;
        416. }
        417. else
        418. {
        419. ucLedStatus16_09=ucLedStatus16_09&0xbf;
        420. }
        421. if(ucLed_dr16==1)
        422. {
        423. ucLedStatus16_09=ucLedStatus16_09|0x80;
        424. }
        425. else
        426. {
        427. ucLedStatus16_09=ucLedStatus16_09&0x7f;
        428. }
        429. hc595_drive(ucLedStatus16_09,ucLedStatus08_01);//74HC595底層驅動函數
        430. }
        431. }
        432. void display_drive()
        433. {
        434. //以下程序,如果加一些數組和移位的元素,還可以壓縮容量。但是鴻哥追求的不是容量,而是清晰的講解思路
        435. switch(ucDisplayDriveStep)
        436. {
        437. case 1://顯示第1位
        438. ucDigShowTemp=dig_table[ucDigShow1];
        439. if(ucDigDot1==1)
        440. {
        441. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數點
        442. }
        443. dig_hc595_drive(ucDigShowTemp,0xfe);
        444. break;
        445. case 2://顯示第2位
        446. ucDigShowTemp=dig_table[ucDigShow2];
        447. if(ucDigDot2==1)
        448. {
        449. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數點
        450. }
        451. dig_hc595_drive(ucDigShowTemp,0xfd);
        452. break;
        453. case 3://顯示第3位
        454. ucDigShowTemp=dig_table[ucDigShow3];
        455. if(ucDigDot3==1)
        456. {
        457. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數點
        458. }
        459. dig_hc595_drive(ucDigShowTemp,0xfb);
        460. break;
        461. case 4://顯示第4位
        462. ucDigShowTemp=dig_table[ucDigShow4];
        463. if(ucDigDot4==1)
        464. {
        465. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數點
        466. }
        467. dig_hc595_drive(ucDigShowTemp,0xf7);
        468. break;
        469. case 5://顯示第5位
        470. ucDigShowTemp=dig_table[ucDigShow5];
        471. if(ucDigDot5==1)
        472. {
        473. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數點
        474. }
        475. dig_hc595_drive(ucDigShowTemp,0xef);
        476. break;
        477. case 6://顯示第6位
        478. ucDigShowTemp=dig_table[ucDigShow6];
        479. if(ucDigDot6==1)
        480. {
        481. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數點
        482. }
        483. dig_hc595_drive(ucDigShowTemp,0xdf);
        484. break;
        485. case 7://顯示第7位
        486. ucDigShowTemp=dig_table[ucDigShow7];
        487. if(ucDigDot7==1)
        488. {
        489. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數點
        490. }
        491. dig_hc595_drive(ucDigShowTemp,0xbf);
        492. break;
        493. case 8://顯示第8位
        494. ucDigShowTemp=dig_table[ucDigShow8];
        495. if(ucDigDot8==1)
        496. {
        497. ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數點
        498. }
        499. dig_hc595_drive(ucDigShowTemp,0x7f);
        500. break;
        501. }
        502. ucDisplayDriveStep++;
        503. if(ucDisplayDriveStep>8)//掃描完8個數碼管后,重新從第一個開始掃描
        504. {
        505. ucDisplayDriveStep=1;
        506. }
        507. }
        508. //數碼管的74HC595驅動函數
        509. void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01)
        510. {
        511. unsigned char i;
        512. unsigned char ucTempData;
        513. dig_hc595_sh_dr=0;
        514. dig_hc595_st_dr=0;
        515. ucTempData=ucDigStatusTemp16_09;//先送高8位
        516. for(i=0;i<8;i++)
        517. {
        518. if(ucTempData>=0x80)dig_hc595_ds_dr=1;
        519. else dig_hc595_ds_dr=0;
        520. dig_hc595_sh_dr=0; //SH引腳的上升沿把數據送入寄存器
        521. delay_short(1);
        522. dig_hc595_sh_dr=1;
        523. delay_short(1);
        524. ucTempData=ucTempData<<1;
        525. }
        526. ucTempData=ucDigStatusTemp08_01;//再先送低8位
        527. for(i=0;i<8;i++)
        528. {
        529. if(ucTempData>=0x80)dig_hc595_ds_dr=1;
        530. else dig_hc595_ds_dr=0;
        531. dig_hc595_sh_dr=0; //SH引腳的上升沿把數據送入寄存器
        532. delay_short(1);
        533. dig_hc595_sh_dr=1;
        534. delay_short(1);
        535. ucTempData=ucTempData<<1;
        536. }
        537. dig_hc595_st_dr=0;//ST引腳把兩個寄存器的數據更新輸出到74HC595的輸出引腳上并且鎖存起來
        538. delay_short(1);
        539. dig_hc595_st_dr=1;
        540. delay_short(1);
        541. dig_hc595_sh_dr=0; //拉低,抗干擾就增強
        542. dig_hc595_st_dr=0;
        543. dig_hc595_ds_dr=0;
        544. }
        545. //LED燈的74HC595驅動函數
        546. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01)
        547. {
        548. unsigned char i;
        549. unsigned char ucTempData;
        550. hc595_sh_dr=0;
        551. hc595_st_dr=0;
        552. ucTempData=ucLedStatusTemp16_09;//先送高8位
        553. for(i=0;i<8;i++)
        554. {
        555. if(ucTempData>=0x80)hc595_ds_dr=1;
        556. else hc595_ds_dr=0;
        557. hc595_sh_dr=0; //SH引腳的上升沿把數據送入寄存器
        558. delay_short(1);
        559. hc595_sh_dr=1;
        560. delay_short(1);
        561. ucTempData=ucTempData<<1;
        562. }
        563. ucTempData=ucLedStatusTemp08_01;//再先送低8位
        564. for(i=0;i<8;i++)
        565. {
        566. if(ucTempData>=0x80)hc595_ds_dr=1;
        567. else hc595_ds_dr=0;
        568. hc595_sh_dr=0; //SH引腳的上升沿把數據送入寄存器
        569. delay_short(1);
        570. hc595_sh_dr=1;
        571. delay_short(1);
        572. ucTempData=ucTempData<<1;
        573. }
        574. hc595_st_dr=0;//ST引腳把兩個寄存器的數據更新輸出到74HC595的輸出引腳上并且鎖存起來
        575. delay_short(1);
        576. hc595_st_dr=1;
        577. delay_short(1);
        578. hc595_sh_dr=0; //拉低,抗干擾就增強
        579. hc595_st_dr=0;
        580. hc595_ds_dr=0;
        581. }
        582. void led_flicker_09_16() //第9個至第16個LED的跑馬燈程序,逐個亮并且每次只能亮一個.
        583. {
        584. if(ucLedStartFlag==1)//此變量為1時代表啟動
        585. {
        586. switch(ucLedStep_09_16)
        587. {
        588. case 0:
        589. if(uiTimeCnt_09_16>=uiSetTimeLevel_09_16) //時間到
        590. {
        591. uiTimeCnt_09_16=0; //時間計數器清零
        592. if(ucLedDirFlag==0)//正方向
        593. {
        594. ucLed_dr16=0;//第16個滅
        595. ucLed_dr9=1;//第9個亮
        596. ucLed_update=1;//更新顯示
        597. ucLedStep_09_16=1; //切換到下一個步驟
        598. }
        599. else//反方向
        600. {
        601. ucLed_dr15=1;//第15個亮
        602. ucLed_dr16=0;//第16個滅
        603. ucLed_update=1;//更新顯示
        604. ucLedStep_09_16=7; //返回上一個步驟
        605. }
        606. }
        607. break;
        608. case 1:
        609. if(uiTimeCnt_09_16>=uiSetTimeLevel_09_16) //時間到
        610. {
        611. uiTimeCnt_09_16=0; //時間計數器清零
        612. if(ucLedDirFlag==0)//正方向
        613. {
        614. ucLed_dr9=0;//第9個滅
        615. ucLed_dr10=1;//第10個亮
        616. ucLed_update=1;//更新顯示
        617. ucLedStep_09_16=2; //切換到下一個步驟
        618. }
        619. else//反方向
        620. {
        621. ucLed_dr16=1;//第16個亮
        622. ucLed_dr9=0;//第9個滅
        623. ucLed_update=1;//更新顯示
        624. ucLedStep_09_16=0; //返回上一個步驟
        625. }
        626. }
        627. break;
        628. case 2:
        629. if(uiTimeCnt_09_16>=uiSetTimeLevel_09_16) //時間到
        630. {
        631. uiTimeCnt_09_16=0; //時間計數器清零
        632. if(ucLedDirFlag==0)//正方向
        633. {
        634. ucLed_dr10=0;//第10個滅
        635. ucLed_dr11=1;//第11個亮
        636. ucLed_update=1;//更新顯示
        637. ucLedStep_09_16=3; //切換到下一個步驟
        638. }
        639. else//反方向
        640. {
        641. ucLed_dr9=1;//第9個亮
        642. ucLed_dr10=0;//第10個滅
        643. ucLed_update=1;//更新顯示
        644. ucLedStep_09_16=1; //返回上一個步驟
        645. }
        646. }
        647. break;
        648. case 3:
        649. if(uiTimeCnt_09_16>=uiSetTimeLevel_09_16) //時間到
        650. {
        651. uiTimeCnt_09_16=0; //時間計數器清零
        652. if(ucLedDirFlag==0)//正方向
        653. {
        654. ucLed_dr11=0;//第11個滅
        655. ucLed_dr12=1;//第12個亮
        656. ucLed_update=1;//更新顯示
        657. ucLedStep_09_16=4; //切換到下一個步驟
        658. }
        659. else//反方向
        660. {
        661. ucLed_dr10=1;//第10個亮
        662. ucLed_dr11=0;//第11個滅
        663. ucLed_update=1;//更新顯示
        664. ucLedStep_09_16=2; //返回上一個步驟
        665. }
        666. }
        667. break;
        668. case 4:
        669. if(uiTimeCnt_09_16>=uiSetTimeLevel_09_16) //時間到
        670. {
        671. uiTimeCnt_09_16=0; //時間計數器清零
        672. if(ucLedDirFlag==0)//正方向
        673. {
        674. ucLed_dr12=0;//第12個滅
        675. ucLed_dr13=1;//第13個亮
        676. ucLed_update=1;//更新顯示
        677. ucLedStep_09_16=5; //切換到下一個步驟
        678. }
        679. else//反方向
        680. {
        681. ucLed_dr11=1;//第11個亮
        682. ucLed_dr12=0;//第12個滅
        683. ucLed_update=1;//更新顯示
        684. ucLedStep_09_16=3; //返回上一個步驟
        685. }
        686. }
        687. break;
        688. case 5:
        689. if(uiTimeCnt_09_16>=uiSetTimeLevel_09_16) //時間到
        690. {
        691. uiTimeCnt_09_16=0; //時間計數器清零
        692. if(ucLedDirFlag==0)//正方向
        693. {
        694. ucLed_dr13=0;//第13個滅
        695. ucLed_dr14=1;//第14個亮
        696. ucLed_update=1;//更新顯示
        697. ucLedStep_09_16=6; //切換到下一個步驟
        698. }
        699. else//反方向
        700. {
        701. ucLed_dr12=1;//第12個亮
        702. ucLed_dr13=0;//第13個滅
        703. ucLed_update=1;//更新顯示
        704. ucLedStep_09_16=4; //返回上一個步驟
        705. }
        706. }
        707. break;
        708. case 6:
        709. if(uiTimeCnt_09_16>=uiSetTimeLevel_09_16) //時間到
        710. {
        711. uiTimeCnt_09_16=0; //時間計數器清零
        712. if(ucLedDirFlag==0)//正方向
        713. {
        714. ucLed_dr14=0;//第14個滅
        715. ucLed_dr15=1;//第15個亮
        716. ucLed_update=1;//更新顯示
        717. ucLedStep_09_16=7; //切換到下一個步驟
        718. }
        719. else//反方向
        720. {
        721. ucLed_dr13=1;//第13個亮
        722. ucLed_dr14=0;//第14個滅
        723. ucLed_update=1;//更新顯示
        724. ucLedStep_09_16=5; //返回上一個步驟
        725. }
        726. }
        727. break;
        728. case 7:
        729. if(uiTimeCnt_09_16>=uiSetTimeLevel_09_16) //時間到
        730. {
        731. uiTimeCnt_09_16=0; //時間計數器清零
        732. if(ucLedDirFlag==0)//正方向
        733. {
        734. ucLed_dr15=0;//第15個滅
        735. ucLed_dr16=1;//第16個亮
        736. ucLed_update=1;//更新顯示
        737. ucLedStep_09_16=0; //返回到開始處,重新開始新的一次循環
        738. }
        739. else//反方向
        740. {
        741. ucLed_dr14=1;//第14個亮
        742. ucLed_dr15=0;//第15個滅
        743. ucLed_update=1;//更新顯示
        744. ucLedStep_09_16=6; //返回上一個步驟
        745. }
        746. }
        747. break;
        748. }
        749. }
        750. }
        751. void T0_time() interrupt 1
        752. {
        753. TF0=0;//清除中斷標志
        754. TR0=0; //關中斷
        755. if(uiTimeCnt_09_16<0xffff)//設定這個條件,防止uiTimeCnt超范圍。
        756. {
        757. if(ucLedStartFlag==1)//此變量為1時代表啟動
        758. {
        759. uiTimeCnt_09_16++;//累加定時中斷的次數,
        760. }
        761. }
        762. key_scan(); //按鍵掃描函數
        763. if(uiVoiceCnt!=0)
        764. {
        765. uiVoiceCnt--; //每次進入定時中斷都自減1,直到等于零為止。才停止鳴叫
        766. beep_dr=0;//蜂鳴器是PNP三極管控制,低電平就開始鳴叫。
        767. // beep_dr=1;//蜂鳴器是PNP三極管控制,低電平就開始鳴叫。
        768. }
        769. else
        770. {
        771. ; //此處多加一個空指令,想維持跟if括號語句的數量對稱,都是兩條指令。不加也可以。
        772. beep_dr=1;//蜂鳴器是PNP三極管控制,高電平就停止鳴叫。
        773. // beep_dr=0;//蜂鳴器是PNP三極管控制,高電平就停止鳴叫。
        774. }
        775. display_drive();//數碼管字模的驅動函數
        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. ; //一個分號相當于執行一條空語句
        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++)//內嵌循環的空指令數量
        795. {
        796. ; //一個分號相當于執行一條空語句
        797. }
        798. }
        799. }
        800. void initial_myself()//第一區 初始化單片機
        801. {
        802. /* 注釋二:
        803. * 矩陣鍵盤也可以做獨立按鍵,前提是把某一根公共輸出線輸出低電平,
        804. * 模擬獨立按鍵的觸發地,本程序中,把key_gnd_dr輸出低電平。
        805. * 朱兆祺51學習板的S1就是本程序中用到的一個獨立按鍵。
        806. */
        807. key_gnd_dr=0; //模擬獨立按鍵的地GND,因此必須一直輸出低電平
        808. led_dr=0;//關閉獨立LED燈
        809. beep_dr=1; //用PNP三極管控制蜂鳴器,輸出高電平時不叫。
        810. TMOD=0x01;//設置定時器0為工作方式1
        811. TH0=0xfe; //重裝初始值(65535-500)=65035=0xfe0b
        812. TL0=0x0b;
        813. }
        814. void initial_peripheral() //第二區 初始化外圍
        815. {
        816. ucDigDot8=0; //小數點全部不顯示
        817. ucDigDot7=0;
        818. ucDigDot6=0;
        819. ucDigDot5=0;
        820. ucDigDot4=0;
        821. ucDigDot3=0;
        822. ucDigDot2=0;
        823. ucDigDot1=0;
        824. EA=1; //開總中斷
        825. ET0=1; //允許定時中斷
        826. TR0=1; //啟動定時中斷
        827. }


        總結陳詞:
        前面花了大量的章節在講數碼管顯示,按鍵,運動的關聯程序框架,從下一節開始,我將會用八節內容來講我常用的串口程序框架,內容非常精彩和震撼,思路非常簡單而又實用。欲知詳情,請聽下回分解-----判斷數據尾來接收一串數據的串口通用程序框架。


        評論


        技術專區

        關閉
        主站蜘蛛池模板: 利川市| 古蔺县| 靖西县| 新绛县| 勃利县| 蒙阴县| 双鸭山市| 阿克| 大新县| 顺平县| 清原| 衡山县| 乌鲁木齐市| 望城县| 安多县| 黑河市| 奈曼旗| 健康| 双鸭山市| 渭源县| 平远县| 许昌市| 福州市| 商都县| 万荣县| 博客| 田阳县| 开化县| 赞皇县| 宾阳县| 电白县| 沙河市| 会同县| 九龙城区| 乐陵市| 绿春县| 玉田县| 安达市| 广饶县| 湘潭县| 扶绥县|