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 }

 

   

posted @ 2017-06-29 19:41  hugh.dong  阅读(4871)  评论(0编辑  收藏  举报