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单片机使用中缀表示法实现计算器的主要内容,如果未能解决你的问题,请参考以下文章 Proteus仿真51单片机+LCD1602+外置存储器计算器