电子DIY、Arduino、51单片机、STM32单片机、FPGA……
电子百科、开发技术、职业经验、趣味知识、科技头条、设备拆机……
http://mp.weixin.qq.com/mp/homepage?__biz=MzU3OTczMzk5Mg==&hid=7&sn=ad5d5d0f15df84f4a92ebf72f88d4ee8&scene=18#wechat_redirect
使用元件:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
实现效果:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
实现原理:
中缀表示法实现计算器正常情况下用栈实现,但由于51单片机内存小,无法使用malloc函数,以及一些莫名其妙的原因导致无法给指针赋值,所以在此处使用数组来模拟栈中情况,以两个int类型变量指示组中数量(模拟栈顶指针)
中缀表示法实现原理见
http://www.cnblogs.com/hughdong/p/6837247.html
http://www.cnblogs.com/hughdong/p/7088915.html
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
实现代码:
/********************************
实验箱实现计算器
*********************************
器件连接:
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
#include
#include
#include
#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);
}