/********************************
實驗箱實現計算器
*********************************
器件連接:
89C51 P0.0 - LCD D0
89C51 P0.1 - LCD D1
89C51 P0.2 - LCD D2
89C51 P0.3 - LCD D3
89C51 P0.4 - LCD D4
89C51 P0.5 - LCD D5
89C51 P0.6 - LCD D6
89C51 P0.7 - LCD D7
89C51 P2.0 - LCD RS
89C51 P2.1 - LCD RW
89C51 P2.2 - LCD EN
89C51 P3.0 - k1
89C51 P3.1 - k2
89C51 P3.2 - k3
89C51 P1.0 - BUTTON L1
89C51 P1.1 - BUTTON L2
89C51 P1.2 - BUTTON L3
89C51 P1.3 - BUTTON L4
89C51 P1.4 - BUTTON H1
89C51 P1.5 - BUTTON H2
89C51 P1.6 - BUTTON H3
89C51 P1.7 - BUTTON H4
*********************************
按鍵對應數值
1 2 3 +
4 5 6 -
7 8 9 *
. 0 # /
獨立按鍵
k1: (
k2: )
k3: C
********************************/
#include <reg52.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define OK 1
#define ERROR 0
typedef unsigned char uchar;
typedef unsigned int uint;
typedef char Status;
sbit rs = P2 ^ 0; // LCD-RS
sbit rw = P2 ^ 1; // LCD-RW
sbit en = P2 ^ 2; // LCD-EN
sbit leftBracket = P3 ^ 0; // 右括號
sbit rightBracket = P3 ^ 1; // 左括號
sbit reset = P3 ^ 2; // 重置算式按鍵
/*******************************/
void Delay(uint z); // 延時函數
void UART_Init(); // 串口初始化
void UART_Send_Byte(uchar ucData); // 串口發送單字節
void UART_Send_Str(uchar *string); // 串口發送字符串
void UART_Send_Enter(); // 串口發送回車
void Init_LCD(); // 初始化LCD1602
void WriteData(uchar dat); // LCD寫字節
void WriteCom(uchar com); // LCD寫指令
void ClearScreen(); // LCD清屏
int InputJudge(char keyValue); // 判斷按鍵是操作符還是操作數
char PriorityJudge(char optr1, char optr2); // 操作數比較
float Calc(char optr, float num1, float num2); // 四則運算
void LCD_Float(float f); // 測試函數,LCD第二行顯示float
void LCD_Int(int dat); // 測試函數,LCD第二行顯示int
void LCD_Char(char c); // 測試函數,根據指針顯示char
/*******************************/
void main()
{
/* 定義運算變量 */
char arrayChar[20]; // 操作數存放數組
float arrayFloat[20]; // 操作數存放數組
int topChar; // 操作符數量
int topFloat; // 操作數數量
char tempChar; // 讀取數組頂部存放的操作符
float tempFloat; // 讀取數組頂部存放的操作數
char optr; // 四則運算操作符
float num1, num2; // 四則運算操作數
int i; // i作為臨時循環使用
int tenPower; // 參與小數點運算時被除數
/* 定義硬件操作變量 */
unsigned char temp; // 按鍵檢索時存放臨時值
unsigned char key; // 按鍵值 16進制
unsigned char keyValue; // 按鍵值 char類型
unsigned int ipos; // LCD顯示指針計數
unsigned int flag; // flag標記,操作數為1 操作符為0 點運算為2
re: // 按下C鍵復位,重新輸入計算式子
/* 初始化變量 */
for (i = 0; i < 20; ++i)
{
arrayChar[i] = '0';
arrayFloat[20] = 0;
}
topChar = 0;
topFloat = 0;
tenPower = 1;
ipos = 0;
flag = 0;
/* 壓入# */
arrayChar[topChar] = '#';
topChar++;
/* 初始化硬件 */
UART_Init();
Init_LCD();
Delay(100);
while(1)
{
P1 = 0xf0;
leftBracket = 1;
rightBracket = 1;
reset = 1;
/* 按鍵檢測 */
if (P1 != 0xf0 || !leftBracket || !rightBracket || !reset)
{
Delay(20);
if (P1 != 0xf0)
{
temp = P1;
P1 = 0x0f;
key = temp | P1;
while(P1 != 0x0f);
ipos++;
if (ipos == 16)
{
ClearScreen();
ipos = 0;
}
/* 按鍵賦值 */
switch(key)
{
case 0xEE:keyValue = '1';WriteData(keyValue);break;
case 0xED:keyValue = '2';WriteData(keyValue);break;
case 0xEB:keyValue = '3';WriteData(keyValue);break;
case 0xDE:keyValue = '4';WriteData(keyValue);break;
case 0xDD:keyValue = '5';WriteData(keyValue);break;
case 0xDB:keyValue = '6';WriteData(keyValue);break;
case 0xBE:keyValue = '7';WriteData(keyValue);break;
case 0xBD:keyValue = '8';WriteData(keyValue);break;
case 0xBB:keyValue = '9';WriteData(keyValue);break;
case 0x7D:keyValue = '0';WriteData(keyValue);break;
case 0xE7:keyValue = '+';WriteData(keyValue);break;
case 0xD7:keyValue = '-';WriteData(keyValue);break;
case 0xB7:keyValue = '*';WriteData(keyValue);break;
case 0x77:keyValue = '/';WriteData(keyValue);break;
case 0x7E:keyValue = '.';WriteData(keyValue);break;
case 0x7B:keyValue = '#';WriteData('=');break;
}
}
else if(!leftBracket)
{
Delay(20);
if (!leftBracket)
{
while(!leftBracket);
keyValue = '(';
WriteData(keyValue);
}
}
else if(!rightBracket)
{
Delay(20);
if (!rightBracket)
{
while(!rightBracket);
keyValue = ')';
WriteData(keyValue);
}
}
else if(!reset) // 當按下復位C鍵時,清屏并回到初始狀態
{
Delay(20);
if (!reset)
{
while(!reset);
ClearScreen();
goto re;
}
}
/* 運算過程 */
if (keyValue == '.') // 當為點運算時,flag標識為2,后續輸入的數字進行小數運算
{
flag = 2;
tenPower = 1;
continue;
}
if (InputJudge(keyValue)) //判斷輸入是否為數字
{
if (flag == 0) // <上次是操作符,本次是操作數> 壓棧
{
arrayFloat[topFloat] = (float)(keyValue - '0');
topFloat++;
flag = 1;
continue;
}
else if(flag == 1) // <輸入10位以上數字> 彈棧值*10+本次值
{
topFloat--;
tempFloat = arrayFloat[topFloat];
arrayFloat[topFloat] = (float)(tempFloat * 10 + (keyValue - '0'));
topFloat++;
flag = 1;
continue;
}
else if (flag == 2) // <輸入小數> 彈棧值+本次值/(10的n次方)
{
topFloat--;
tempFloat = arrayFloat[topFloat];
tenPower = tenPower * 10;
tempFloat = tempFloat + ((float)(keyValue - '0') / tenPower);
arrayFloat[topFloat] = tempFloat;
topFloat++;
flag = 2;
continue;
}
}
/****************************************************
當按鍵值為符號時,進行計算或壓入運算符組
優先級為 > 時,重復對比并計算
****************************************************/
else
{
reCalc:
tempChar = arrayChar[topChar - 1];
switch(PriorityJudge(tempChar, keyValue)) // 判斷本次輸入符號與操作符數組頂部元素優先級
{
/****************************************************
本次輸入壓入操作符組頂部,完畢后重新獲取按鍵
****************************************************/
case '<':
arrayChar[topChar] = keyValue;
topChar++;
flag = 0;
continue;
/****************************************************
()或#閉合時,彈出頂部元素
()閉合后重新獲取按鍵
#彈出說明公式計算完畢,LCD顯示結果并進入死循環
計算結束后,按下復位鍵代碼回到Line 90,程序重置
****************************************************/
case '=':
topChar--;
tempChar = arrayChar[topChar];
if (tempChar == '#')
{
LCD_Float(arrayFloat[topFloat - 1]);
/*
LCD_Int(topFloat);
UART_Send_Enter();
UART_Send_Str("End");
*/
while(1)
{
if(!reset)
{
Delay(20);
if (!reset)
{
while(!reset);
ClearScreen();
goto re; // line 90
}
}
}
}
flag = 0;
continue;
/****************************************************
彈出兩個操作數和一個操作符進行四則運算
運算結束后將結果操作數壓入
程序回到 reCalc處 Line231,繼續彈出操作符對比
****************************************************/
case '>':
topChar--;
optr = arrayChar[topChar];
topFloat--;
num2 = arrayFloat[topFloat];
topFloat--;
num1 = arrayFloat[topFloat];
arrayFloat[topFloat] = Calc(optr, num1, num2);
topFloat++;
flag = 0;
goto reCalc;
}
}
}
/*
char串口打印測試
UART_Send_Enter();
UART_Send_Str("optr:");
UART_Send_Byte(optr);
int串口打印測試
UART_Send_Enter();
UART_Send_Byte(topFloat + '0');
*/
}
}
void UART_Init()
{
SCON = 0x50;
TMOD = 0x20;
PCON = 0x00;
TH1 = 0xFD;
TL1 = 0xFD;
TR1 = 1;
ES = 1;
EA = 1;
ET1 = 0;
}
void UART_Send_Byte(uchar ucData)
{
SBUF = ucData;
while(!TI);
TI = 0;
}
void UART_Send_Str(uchar *string)
{
while(*string)
UART_Send_Byte(*string++);
}
void UART_Send_Enter()
{
UART_Send_Byte(0x0d);
UART_Send_Byte(0x0a);
}
void Init_LCD()
{
en = 0;
WriteCom(0x38);
WriteCom(0x0e);
WriteCom(0x06);
WriteCom(0x01);
WriteCom(0x80 + 0x1);
}
void WriteData(uchar dat)
{
rs = 1;
rw = 0;
P0 = dat;
Delay(5);
en = 1;
Delay(5);
en = 0;
}
void WriteCom(uchar com)
{
rs = 0;
rw = 0;
P0 = com;
Delay(5);
en = 1;
Delay(5);
en = 0;
}
void ClearScreen()
{
WriteCom(0x01);
}
void Delay(uint z)
{
uint x, y;
for(x = z; x > 0; x--)
for(y = 110; y > 0; y--);
}
int InputJudge(char keyValue)
{
switch(keyValue)
{
case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':return OK;break;
case '+':case '-':case '*':case '/':case '(':case ')':case '#':return ERROR;break;
default:break;
}
}
char PriorityJudge(char optr1, char optr2)
{
int i, j;
char priorityTable[7][7] =
{
// + - * / ( ) #
{'>', '>', '<', '<', '<', '>', '>'}, // +
{'>', '>', '<', '<', '<', '>', '>'}, // -
{'>', '>', '>', '>', '<', '>', '>'}, // *
{'>', '>', '>', '>', '<', '>', '>'}, // /
{'<', '<', '<', '<', '<', '=', '0'}, // (
{'>', '>', '>', '>', '0', '>', '>'}, // )
{'<', '<', '<', '<', '<', '0', '='} // #
};
switch(optr1)
{
case '+':i = 0;break;
case '-':i = 1;break;
case '*':i = 2;break;
case '/':i = 3;break;
case '(':i = 4;break;
case ')':i = 5;break;
case '#':i = 6;break;
}
switch(optr2)
{
case '+':j = 0;break;
case '-':j = 1;break;
case '*':j = 2;break;
case '/':j = 3;break;
case '(':j = 4;break;
case ')':j = 5;break;
case '#':j = 6;break;
}
return priorityTable[i][j];
}
float Calc(char optr, float num1, float num2)
{
switch(optr)
{
case '+':return (num1 + num2);break;
case '-':return (num1 - num2);break;
case '*':return (num1 * num2);break;
case '/':return (num1 / num2);break;
}
}
void LCD_Float(float f)
{
char str[7];
int i, length;
for (i = 0; i < 7; ++i)
str[i] = '0';
length = sprintf(str, "%g", f);
WriteCom(0x80 + 0x40);
Delay(20);
for (i = 0; i < length; ++i)
{
WriteData(str[i]);
Delay(20);
}
}
void LCD_Int(int dat)
{
char str[7];
int i, length;
for (i = 0; i < 7; ++i)
str[i] = '0';
length = sprintf(str, "%d", dat);
WriteCom(0x80 + 0x48);
Delay(20);
for (i = 0; i < length; ++i)
{
WriteData(str[i]);
Delay(20);
}
}
void LCD_Char(char c)
{
WriteData(c);
Delay(20);
} |