51单片机使用中缀表示法实现计算器

Posted Hugh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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);
以上是关于51单片机使用中缀表示法实现计算器的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 中为中缀表示法添加前缀表示法

栈实现综合计算器(中缀表达式)

Proteus仿真51单片机+LCD1602+外置存储器计算器

栈实现综合计算器(中缀表达式),前缀,中缀,后缀表达式,逆波兰计算器

如何在Postfix和Infix表示法中接受负值?

关于栈实现综合计算器的代码实现和讲解