首页 > 代码库 > 51单片机使用中缀表示法实现计算器
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 = http://www.mamicode.com/‘1‘;WriteData(keyValue);break; 140 case 0xED:keyValue = http://www.mamicode.com/‘2‘;WriteData(keyValue);break; 141 case 0xEB:keyValue = http://www.mamicode.com/‘3‘;WriteData(keyValue);break; 142 case 0xDE:keyValue = http://www.mamicode.com/‘4‘;WriteData(keyValue);break; 143 case 0xDD:keyValue = http://www.mamicode.com/‘5‘;WriteData(keyValue);break; 144 case 0xDB:keyValue = http://www.mamicode.com/‘6‘;WriteData(keyValue);break; 145 case 0xBE:keyValue = http://www.mamicode.com/‘7‘;WriteData(keyValue);break; 146 case 0xBD:keyValue = http://www.mamicode.com/‘8‘;WriteData(keyValue);break; 147 case 0xBB:keyValue = http://www.mamicode.com/‘9‘;WriteData(keyValue);break; 148 case 0x7D:keyValue = http://www.mamicode.com/‘0‘;WriteData(keyValue);break; 149 case 0xE7:keyValue = http://www.mamicode.com/‘+‘;WriteData(keyValue);break; 150 case 0xD7:keyValue = http://www.mamicode.com/‘-‘;WriteData(keyValue);break; 151 case 0xB7:keyValue = http://www.mamicode.com/‘*‘;WriteData(keyValue);break; 152 case 0x77:keyValue = http://www.mamicode.com/‘/‘;WriteData(keyValue);break; 153 case 0x7E:keyValue = http://www.mamicode.com/‘.‘;WriteData(keyValue);break; 154 case 0x7B:keyValue = http://www.mamicode.com/‘#‘;WriteData(‘=‘);break; 155 } 156 } 157 else if(!leftBracket) 158 { 159 Delay(20); 160 if (!leftBracket) 161 { 162 while(!leftBracket); 163 keyValue = http://www.mamicode.com/‘(‘; 164 WriteData(keyValue); 165 } 166 } 167 else if(!rightBracket) 168 { 169 Delay(20); 170 if (!rightBracket) 171 { 172 while(!rightBracket); 173 keyValue = http://www.mamicode.com/‘)‘; 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 =http://www.mamicode.com/= ‘.‘) // 当为点运算时,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 }
51单片机使用中缀表示法实现计算器