新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 第36節:帶數碼管顯示的加法簡易計算器

        第36節:帶數碼管顯示的加法簡易計算器

        作者: 時間:2016-11-22 來源:網絡 收藏
        開場白:
        這一節要做一個簡單的計算器。這個計算器不帶小數點,只能進行不超過8位數據的加法運算,它麻雀雖小但是五臟俱全,它能清晰地勾勒出商業計算器的程序框架和思路。讀者只要看懂本節程序框架的規律,以后自己想做一個復雜一點的計算器應該是沒問題的。復雜的計算器在算法上要用數組進行特殊處理,不能簡單地直接用C語言的+,-,*,/運算符,這方面的內容我會在以后的章節中跟大家分享。
        這一節要教會大家兩個知識點:
        第一個:數字按鍵的輸入和十進制數值的移位方法。
        第二個:繼續加深理解按鍵與數碼管的關聯程序框架。

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

        (1)硬件平臺:
        基于朱兆祺51單片機學習板。數字1鍵對應S1鍵,數字2鍵對應S2鍵,數字3鍵對應S3鍵…. 數字9鍵對應S9鍵, 數字0鍵對應S10鍵。加號鍵對應S13,等于號鍵對應S14,清除復位按鍵對應S16。其它按鍵不用。

        (2)實現功能:
        常用的加法計算器功能。有連加功能。
        本程序有2個窗口。
        第1個窗口:原始數據和運算結果窗口。比如加法運算中的被加數
        第2個窗口:第二個參與運行的數據窗口。比如加法運算中的加數

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


        總結陳詞:
        這節講了加法簡易計算器的程序項目。為了讓讀者理解運動,按鍵,顯示是如何有規律關聯起來的,下節會繼續講一個相關的小項目程序。欲知詳情,請聽下回分解-----數碼管作為儀表盤顯示跑馬燈的方向,速度和運行狀態。


        評論


        技術專區

        關閉
        主站蜘蛛池模板: 德阳市| 德清县| 和龙市| 大石桥市| 射阳县| 额敏县| 苍南县| 岑巩县| 略阳县| 赞皇县| 神农架林区| 前郭尔| 达拉特旗| 普格县| 涿鹿县| 当涂县| 肇庆市| 万安县| 广饶县| 石家庄市| 扎鲁特旗| 三河市| 开江县| 郑州市| 香港| 本溪| 阳朔县| 珲春市| 边坝县| 吉安市| 玉龙| 安庆市| 华蓥市| 麦盖提县| 招远市| 忻城县| 镇巴县| 阿克| 永春县| 中牟县| 龙游县|