新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 第36節(jié):帶數(shù)碼管顯示的加法簡(jiǎn)易計(jì)算器

第36節(jié):帶數(shù)碼管顯示的加法簡(jiǎn)易計(jì)算器

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

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

(1)硬件平臺(tái):
基于朱兆祺51單片機(jī)學(xué)習(xí)板。數(shù)字1鍵對(duì)應(yīng)S1鍵,數(shù)字2鍵對(duì)應(yīng)S2鍵,數(shù)字3鍵對(duì)應(yīng)S3鍵…. 數(shù)字9鍵對(duì)應(yīng)S9鍵, 數(shù)字0鍵對(duì)應(yīng)S10鍵。加號(hào)鍵對(duì)應(yīng)S13,等于號(hào)鍵對(duì)應(yīng)S14,清除復(fù)位按鍵對(duì)應(yīng)S16。其它按鍵不用。

(2)實(shí)現(xiàn)功能:
常用的加法計(jì)算器功能。有連加功能。
本程序有2個(gè)窗口。
第1個(gè)窗口:原始數(shù)據(jù)和運(yùn)算結(jié)果窗口。比如加法運(yùn)算中的被加數(shù)
第2個(gè)窗口:第二個(gè)參與運(yùn)行的數(shù)據(jù)窗口。比如加法運(yùn)算中的加數(shù)

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


總結(jié)陳詞:
這節(jié)講了加法簡(jiǎn)易計(jì)算器的程序項(xiàng)目。為了讓讀者理解運(yùn)動(dòng),按鍵,顯示是如何有規(guī)律關(guān)聯(lián)起來(lái)的,下節(jié)會(huì)繼續(xù)講一個(gè)相關(guān)的小項(xiàng)目程序。欲知詳情,請(qǐng)聽(tīng)下回分解-----數(shù)碼管作為儀表盤(pán)顯示跑馬燈的方向,速度和運(yùn)行狀態(tài)。


評(píng)論


技術(shù)專(zhuān)區(qū)

關(guān)閉