因為一些莫名其妙的原因重寫了三遍,燒壞了兩塊STC,十分心累 ...
————————————————————————————————————————————
開發板:暢學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 {'<', '<'