51單片機使用中綴表示法實現計算器

来源:http://www.cnblogs.com/hughdong/archive/2017/06/29/7096080.html
-Advertisement-
Play Games

因為一些莫名其妙的原因重寫了三遍,燒壞了兩塊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         {'<', '<'

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 資料庫的創建和刪除 黑視窗啟動資料庫服務:net start mysql 關閉資料庫服務:net stop mysql 創建資料庫使用關鍵字create database格式: create database 資料庫名; create database 資料庫名 character set 字元集; ...
  • oracle查詢重覆數據 select * from 表 where 條件 and 判重欄位 not in (select 判重欄位 from 表 where 條件 group by 判重欄位 having count(*) > 1) 根據rowid刪除重覆數據,保留一條 delete from 表 ...
  • oracle數值函數 abs()、 ceil()、 oracle數值函數 abs()、 ceil()、 1、格式:abs(number) 即 abs(數值) 返回數值的絕對值。 例: abs(5) 返回 5 abs(-5) 返回 5 2、格式:ceil(number) 即 ceil(數值) 根據輸入 ...
  • 包括初始化root用戶密碼password的過程以及兩個常見問題的解決方法 1. 下載MySQL zip包 進入 "MySQL官網" 按需選擇zip包下載並解壓, 比如現在我電腦裡面下載的是mysql 5.7.17 winx64 http://dev.mysql.com/downloads/mysq ...
  • 資料庫引擎接收到一個新的查詢請求(Batch或SP),查詢優化器會生成執行計劃,並緩存到記憶體中;下次再次執行相同的查詢請求時,資料庫引擎從復用已經緩存的執行計劃,換句話,資料庫引擎為每一個查詢請求生成執行計劃,並把已經生成的執行計劃緩存起來,當接收到相同的查詢請求時,資料庫引擎復用已緩存的執行計劃。 ...
  • Linux系統出現了性能問題,一般我們可以通過top、iostat、free、vmstat等命令來查看初步定位問題。在一個以前看到系統監控工具,總在想那些監控工具的代理,如何收集系統性能信息,io性能,cpu使用,帶寬使用等信息,偶然發現,不同系統均提供有性能分析工具的,代理可通過這些命令獲取系統性 ...
  • 1、簡介 2、read 3、運算工具 4、if/then結構 5、while迴圈 6、for迴圈 一、簡介 1、什麼是shell shell是用戶與系統交互作用的界面。shell是一種命令解釋程式,同時也是一種高級程式設計語言 2、shell常見種類 Bourne Shell(/usr/bin/sh ...
  • 1、輸入輸出,重定向,管道 2、<(cmd);>(cmd) 3、>;<;>>;<<;>>>;<<< 4、文本處理_1:cat;head;tail;cut;wc;sort;uniq;tr;tac;rev 一、輸入輸出,重定向,管道 1、Linux 程式有三個標準的輸入輸出,分別是: 標準輸入,用數字0 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...