51單片機 | 實現計算器(中綴表示法)


————————————————————————————————————————————

開發板:暢學51單片機學習板

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

使用元件:

  • STC51單片機芯片
  • 51單片機核心板
  • LCD1602
  • 矩陣鍵盤
  • 11.0592MHz晶振

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

實現效果:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

實現原理:

中綴表示法實現計算器正常情況下用棧實現,但由於51單片機內存小,無法使用malloc函數,以及一些莫名其妙的原因導致無法給指針賦值,所以在此處使用數組來模擬棧中情況,以兩個int類型變量指示組中數量(模擬棧頂指針)

中綴表示法實現原理見

http://www.cnblogs.com/hughdong/p/6837247.html

http://www.cnblogs.com/hughdong/p/7088915.html

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

實現代碼:

  1 /********************************
  2 實驗箱實現計算器
  3 *********************************
  4 器件連接:
  5 89C51 P0.0 - LCD D0
  6 89C51 P0.1 - LCD D1
  7 89C51 P0.2 - LCD D2
  8 89C51 P0.3 - LCD D3
  9 89C51 P0.4 - LCD D4
 10 89C51 P0.5 - LCD D5
 11 89C51 P0.6 - LCD D6
 12 89C51 P0.7 - LCD D7
 13 89C51 P2.0 - LCD RS
 14 89C51 P2.1 - LCD RW
 15 89C51 P2.2 - LCD EN
 16 89C51 P3.0 - k1
 17 89C51 P3.1 - k2
 18 89C51 P3.2 - k3
 19 89C51 P1.0 - BUTTON L1
 20 89C51 P1.1 - BUTTON L2
 21 89C51 P1.2 - BUTTON L3
 22 89C51 P1.3 - BUTTON L4
 23 89C51 P1.4 - BUTTON H1
 24 89C51 P1.5 - BUTTON H2
 25 89C51 P1.6 - BUTTON H3
 26 89C51 P1.7 - BUTTON H4
 27 *********************************
 28 按鍵對應數值
 29 1 2 3 +
 30 4 5 6 -
 31 7 8 9 *
 32 . 0 # /
 33 獨立按鍵
 34 k1: (
 35 k2: )
 36 k3: C
 37 ********************************/
 38 #include <reg52.h>
 39 #include <stdio.h>
 40 #include <stdlib.h>
 41 #include <math.h>
 42 #define OK 1
 43 #define ERROR 0
 44 typedef unsigned char uchar;
 45 typedef unsigned int uint;
 46 typedef char Status;
 47 sbit rs = P2 ^ 0; // LCD-RS
 48 sbit rw = P2 ^ 1; // LCD-RW
 49 sbit en = P2 ^ 2; // LCD-EN
 50 sbit leftBracket = P3 ^ 0; // 右括號
 51 sbit rightBracket = P3 ^ 1; // 左括號
 52 sbit reset = P3 ^ 2; // 重置算式按鍵
 53 /*******************************/
 54 void Delay(uint z); // 延時函數
 55 void UART_Init(); // 串口初始化
 56 void UART_Send_Byte(uchar ucData); // 串口發送單字節
 57 void UART_Send_Str(uchar *string); // 串口發送字符串
 58 void UART_Send_Enter(); // 串口發送回車
 59 void Init_LCD(); // 初始化LCD1602
 60 void WriteData(uchar dat); // LCD寫字節
 61 void WriteCom(uchar com); // LCD寫指令
 62 void ClearScreen(); // LCD清屏
 63 int InputJudge(char keyValue); // 判斷按鍵是操作符還是操作數
 64 char PriorityJudge(char optr1, char optr2); // 操作數比較
 65 float Calc(char optr, float num1, float num2); // 四則運算
 66 void LCD_Float(float f); // 測試函數,LCD第二行顯示float
 67 void LCD_Int(int dat); // 測試函數,LCD第二行顯示int
 68 void LCD_Char(char c); // 測試函數,根據指針顯示char
 69 /*******************************/
 70 void main()
 71 {
 72     /* 定義運算變量 */
 73     char arrayChar[20]; // 操作數存放數組
 74     float arrayFloat[20]; // 操作數存放數組
 75     int topChar; // 操作符數量
 76     int topFloat; // 操作數數量
 77     char tempChar; // 讀取數組頂部存放的操作符
 78     float tempFloat; // 讀取數組頂部存放的操作數
 79     char optr; // 四則運算操作符
 80     float num1, num2; // 四則運算操作數
 81     int i; // i作為臨時循環使用
 82     int tenPower; // 參與小數點運算時被除數
 83     /* 定義硬件操作變量 */
 84     unsigned char temp; // 按鍵檢索時存放臨時值
 85     unsigned char key; // 按鍵值 16進制
 86     unsigned char keyValue; // 按鍵值 char類型
 87     unsigned int ipos; // LCD顯示指針計數
 88     unsigned int flag; // flag標記,操作數為1 操作符為0 點運算為2
 89 
 90 re: // 按下C鍵復位,重新輸入計算式子
 91 
 92     /* 初始化變量 */
 93     for (i = 0; i < 20; ++i)
 94     {
 95         arrayChar[i] = '0';
 96         arrayFloat[20] = 0;
 97     }
 98     topChar = 0;
 99     topFloat = 0;
100     tenPower = 1;
101     ipos = 0;
102     flag = 0;
103 
104     /* 壓入# */
105     arrayChar[topChar] = '#';
106     topChar++;
107 
108     /* 初始化硬件 */
109     UART_Init();
110     Init_LCD();
111     Delay(100);
112     while(1)
113     {
114         P1 = 0xf0;
115         leftBracket = 1;
116         rightBracket = 1;
117         reset = 1;
118 
119         /* 按鍵檢測 */
120         if (P1 != 0xf0 || !leftBracket || !rightBracket || !reset)
121         {
122             Delay(20);
123             if (P1 != 0xf0)
124             {
125                 temp = P1;
126                 P1 = 0x0f;
127                 key = temp | P1;
128                 while(P1 != 0x0f);
129                 ipos++;
130                 if (ipos == 16)
131                 {
132                     ClearScreen();
133                     ipos = 0;
134                 }
135 
136                 /* 按鍵賦值 */
137                 switch(key)
138                 {
139                 case 0xEE:keyValue = '1';WriteData(keyValue);break;
140                 case 0xED:keyValue = '2';WriteData(keyValue);break;
141                 case 0xEB:keyValue = '3';WriteData(keyValue);break;
142                 case 0xDE:keyValue = '4';WriteData(keyValue);break;
143                 case 0xDD:keyValue = '5';WriteData(keyValue);break;
144                 case 0xDB:keyValue = '6';WriteData(keyValue);break;
145                 case 0xBE:keyValue = '7';WriteData(keyValue);break;
146                 case 0xBD:keyValue = '8';WriteData(keyValue);break;
147                 case 0xBB:keyValue = '9';WriteData(keyValue);break;
148                 case 0x7D:keyValue = '0';WriteData(keyValue);break;
149                 case 0xE7:keyValue = '+';WriteData(keyValue);break;
150                 case 0xD7:keyValue = '-';WriteData(keyValue);break;
151                 case 0xB7:keyValue = '*';WriteData(keyValue);break;
152                 case 0x77:keyValue = '/';WriteData(keyValue);break;
153                 case 0x7E:keyValue = '.';WriteData(keyValue);break;
154                 case 0x7B:keyValue = '#';WriteData('=');break;
155                 }
156             }
157             else if(!leftBracket)
158             {
159                 Delay(20);
160                 if (!leftBracket)
161                 {
162                     while(!leftBracket);
163                     keyValue = '(';
164                     WriteData(keyValue);
165                 }
166             }
167             else if(!rightBracket)
168             {
169                 Delay(20);
170                 if (!rightBracket)
171                 {
172                     while(!rightBracket);
173                     keyValue = ')';
174                     WriteData(keyValue);
175                 }
176             }
177             else if(!reset) // 當按下復位C鍵時,清屏並回到初始狀態
178             {
179                 Delay(20);
180                 if (!reset)
181                 {
182                     while(!reset);
183                     ClearScreen();
184                     goto re;
185                 }
186             }
187 
188             /* 運算過程 */
189             if (keyValue == '.') // 當為點運算時,flag標識為2,后續輸入的數字進行小數運算
190             {
191                 flag = 2;
192                 tenPower = 1;
193                 continue;
194             }
195             if (InputJudge(keyValue)) //判斷輸入是否為數字
196             {
197                 if (flag == 0) // <上次是操作符,本次是操作數> 壓棧
198                 {
199                     arrayFloat[topFloat] = (float)(keyValue - '0');
200                     topFloat++;
201                     flag = 1;
202                     continue;
203                 }
204                 else if(flag == 1) // <輸入10位以上數字> 彈棧值*10+本次值
205                 {
206                     topFloat--;
207                     tempFloat = arrayFloat[topFloat];
208                     arrayFloat[topFloat] = (float)(tempFloat * 10 + (keyValue - '0'));
209                     topFloat++;
210                     flag = 1;
211                     continue;
212                 }
213                 else if (flag == 2) // <輸入小數> 彈棧值+本次值/(10的n次方)
214                 {
215                     topFloat--;
216                     tempFloat = arrayFloat[topFloat];
217                     tenPower = tenPower * 10;
218                     tempFloat = tempFloat + ((float)(keyValue - '0') / tenPower);
219                     arrayFloat[topFloat] = tempFloat;
220                     topFloat++;
221                     flag = 2;
222                     continue;
223                 }
224             }
225             /****************************************************
226             當按鍵值為符號時,進行計算或壓入運算符組
227             優先級為 > 時,重復對比並計算
228             ****************************************************/
229             else
230             {
231 reCalc:
232                 tempChar = arrayChar[topChar - 1];
233                 switch(PriorityJudge(tempChar, keyValue)) // 判斷本次輸入符號與操作符數組頂部元素優先級
234                 {
235                 /****************************************************
236                 本次輸入壓入操作符組頂部,完畢后重新獲取按鍵
237                 ****************************************************/
238                 case '<':
239                     arrayChar[topChar] = keyValue;
240                     topChar++;
241                     flag = 0;
242                     continue;
243                 /****************************************************
244                 ()或#閉合時,彈出頂部元素
245                 ()閉合后重新獲取按鍵
246                 #彈出說明公式計算完畢,LCD顯示結果並進入死循環
247                 計算結束后,按下復位鍵代碼回到Line 90,程序重置
248                 ****************************************************/
249                 case '=':
250                     topChar--;
251                     tempChar = arrayChar[topChar];
252                     if (tempChar == '#')
253                     {
254                         LCD_Float(arrayFloat[topFloat - 1]);
255                         /*
256                         LCD_Int(topFloat);
257                         UART_Send_Enter();
258                         UART_Send_Str("End");
259                         */
260                         while(1)
261                         {
262                             if(!reset)
263                             {
264                                 Delay(20);
265                                 if (!reset)
266                                 {
267                                     while(!reset);
268                                     ClearScreen();
269                                     goto re; // line 90
270                                 }
271                             }
272                         }
273                     }
274                     flag = 0;
275                     continue;
276                 /****************************************************
277                 彈出兩個操作數和一個操作符進行四則運算
278                 運算結束后將結果操作數壓入
279                 程序回到 reCalc處 Line231,繼續彈出操作符對比
280                 ****************************************************/
281                 case '>':
282                     topChar--;
283                     optr = arrayChar[topChar];
284                     topFloat--;
285                     num2 = arrayFloat[topFloat];
286                     topFloat--;
287                     num1 = arrayFloat[topFloat];
288                     arrayFloat[topFloat] = Calc(optr, num1, num2);
289                     topFloat++;
290                     flag = 0;
291                     goto reCalc;
292                 }
293             }
294         }
295         /*
296         char串口打印測試 
297         UART_Send_Enter();
298         UART_Send_Str("optr:");
299         UART_Send_Byte(optr);
300         int串口打印測試 
301         UART_Send_Enter();
302         UART_Send_Byte(topFloat + '0');
303         */
304     }
305 }
306 void UART_Init()
307 {
308     SCON = 0x50;
309     TMOD = 0x20;
310     PCON = 0x00;
311     TH1 = 0xFD;
312     TL1 = 0xFD;
313     TR1 = 1;
314     ES = 1;
315     EA = 1;
316     ET1 = 0;
317 }
318 void UART_Send_Byte(uchar ucData)
319 {
320     SBUF = ucData;
321     while(!TI);
322     TI = 0;
323 }
324 void UART_Send_Str(uchar *string)
325 {
326     while(*string)
327         UART_Send_Byte(*string++);
328 }
329 void UART_Send_Enter()
330 {
331     UART_Send_Byte(0x0d);
332     UART_Send_Byte(0x0a);
333 }
334 void Init_LCD()
335 {
336     en = 0;
337     WriteCom(0x38);
338     WriteCom(0x0e);
339     WriteCom(0x06);
340     WriteCom(0x01);
341     WriteCom(0x80 + 0x1);
342 }
343 void WriteData(uchar dat)
344 {
345     rs = 1;
346     rw = 0;
347     P0 = dat;
348     Delay(5);
349     en = 1;
350     Delay(5);
351     en = 0;
352 }
353 void WriteCom(uchar com)
354 {
355     rs = 0;
356     rw = 0;
357     P0 = com;
358     Delay(5);
359     en = 1;
360     Delay(5);
361     en = 0;
362 }
363 void ClearScreen()
364 {
365     WriteCom(0x01);
366 }
367 void Delay(uint z)
368 {
369     uint x, y;
370     for(x = z; x > 0; x--)
371         for(y = 110; y > 0; y--);
372 }
373 int InputJudge(char keyValue)
374 {
375     switch(keyValue)
376     {
377     case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':return OK;break;
378     case '+':case '-':case '*':case '/':case '(':case ')':case '#':return ERROR;break;
379     default:break;
380     }
381 }
382 char PriorityJudge(char optr1, char optr2)
383 {
384     int i, j;
385     char priorityTable[7][7] =
386     {
387         // +   -    *    /    (    )    #
388         {'>', '>', '<', '<', '<', '>', '>'}, // +
389         {'>', '>', '<', '<', '<', '>', '>'}, // -
390         {'>', '>', '>', '>', '<', '>', '>'}, // *
391         {'>', '>', '>', '>', '<', '>', '>'}, // /
392         {'<', '<', '<', '<', '<', '=', '0'}, // (
393         {'>', '>', '>', '>', '0', '>', '>'}, // )
394         {'<', '<', '<', '<', '<', '0', '='}  // #
395     };
396     switch(optr1)
397     {
398     case '+':i = 0;break;
399     case '-':i = 1;break;
400     case '*':i = 2;break;
401     case '/':i = 3;break;
402     case '(':i = 4;break;
403     case ')':i = 5;break;
404     case '#':i = 6;break;
405     }
406     switch(optr2)
407     {
408     case '+':j = 0;break;
409     case '-':j = 1;break;
410     case '*':j = 2;break;
411     case '/':j = 3;break;
412     case '(':j = 4;break;
413     case ')':j = 5;break;
414     case '#':j = 6;break;
415     }
416     return priorityTable[i][j];
417 }
418 float Calc(char optr, float num1, float num2)
419 {
420     switch(optr)
421     {
422     case '+':return (num1 + num2);break;
423     case '-':return (num1 - num2);break;
424     case '*':return (num1 * num2);break;
425     case '/':return (num1 / num2);break;
426     }
427 }
428 void LCD_Float(float f)
429 {
430     char str[7];
431     int i, length;
432     for (i = 0; i < 7; ++i)
433         str[i] = '0';
434     length = sprintf(str, "%g", f);
435     WriteCom(0x80 + 0x40);
436     Delay(20);
437     for (i = 0; i < length; ++i)
438     {
439         WriteData(str[i]);
440         Delay(20);
441     }
442 }
443 void LCD_Int(int dat)
444 {
445     char str[7];
446     int i, length;
447     for (i = 0; i < 7; ++i)
448         str[i] = '0';
449     length = sprintf(str, "%d", dat);
450     WriteCom(0x80 + 0x48);
451     Delay(20);
452     for (i = 0; i < length; ++i)
453     {
454         WriteData(str[i]);
455         Delay(20);
456     }
457 }
458 void LCD_Char(char c)
459 {
460     WriteData(c);
461     Delay(20);
462 }

 

   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM