单片机实现简易计算器

涉及元器件

  • STC89C52RC单片机
  • 矩阵键盘
  • LCD1602液晶显示屏

使用软件

  • Keil uVision5
  • stc-isp-v6.93

整体介绍

实现功能:使用矩阵键盘输入操作数和运算符,可以在LCD1602液晶显示屏上实时显示,并且按下矩阵键盘的S16,相当于等于号,就可以得出计算结果。

具体操作方法:

  1. 矩阵键盘S1-S9分别对应数字1-9,S10代表数字0,S11-S14对应运算符加减乘除,S15的作用是清屏,S16的作用是显示计算结果,相当于等号。
  2. 使用者只需要输入一串表达式,LCD1602会实时显示在第一行上,但是由于LCD1602只有16*2的尺寸,所以输入的表达式不能过长,输入完表达式之后按下S16就会显示计算结果在第二行上。
  3. 输入的操作数控制在三位整数以内,运算结果不能超过unsigned int类型的表示范围,不支持负数运算,不支持括号运算。

具体实现步骤

一种数据结构——栈

栈是一种先入后出的数据结构,如下图所示:
在这里插入图片描述
可以看到,不管是入栈还是出栈,操作的都是栈顶,这样就很轻松的完成了先入后出的操作,因为先入的元素沉在了最底下,变成了栈底元素。本次的程序需要用到此数据结构

核心思路分析

如何让输入的中缀表达式能够进行运算,我们此处需要定义两个栈,一个是操作数栈,一个是运算符栈,同时要定义操作符的优先级

  1. 从左到右扫描输入的表达式,当遇到操作数时直接入栈
  2. 遇到运算符时,查看运算符栈是否为空
  3. 如果运算符栈不为空,比较运算符栈顶的运算符和当前扫描到的运算符的优先级,如果运算符栈顶的运算符优先级低,那么当前运算符直接入栈
  4. 如果运算符栈顶的运算符优先级高,运算符栈顶元素出栈,同时在操作数栈中取两个操作数,让这两个操作数和出栈的运算符进行运算,得到的结果再入操作数栈,最后将扫描到的运算符入运算符栈
    此处注意,先出栈的操作数的右操作数,后出栈的操作数是左操作数
  5. 当表达式扫描完毕,也就是按下矩阵键盘上的S16,就顺序的从操作数栈和运算符栈中取出相应的操作数和运算符,进行最后的运算

面临问题

  1. 如何按下矩阵按键实时显示在LCD1602屏幕上面?
  2. 由于是边输入边进行计算,而不是现成的完整表达式,应该选择在什么时机进栈?
  3. 如何判断输入一个操作数是否完成?此处可输入三位的操作数,可以输入002也可以输入200,如何保证读取到的结果是正确的?
  4. 最后按下S16计算结果的时候,运算符栈中真的只有一个元素吗?
  5. 要定义什么栈的基本操作

代码实现

LCD1602模块

LCD1602主要有以下几个函数,可以在屏幕上显示字符、字符串、无符号数、有符号数、十六进制数、二进制数
使用方法:导入头文件,先调用LCD_Init();初始化函数进行初始化,然后就可以任意调用其中的函数进行显示你想显示的内容

LCD1602.h头文件定义如下:

#ifndef __LCD1602_H__
#define __LCD1602_H__

//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
#endif

LCD1602.c如下:

#include <REGX52.H>

//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
	unsigned char i, j;

	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
}

/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;
	LCD_RW=0;
	LCD_DataPort=Command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1;
	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
	if(Line==1)
	{
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}

/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()
{
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
		LCD_WriteData(String[i]);
	}
}

/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}

/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line,Column);
	if(Number>=0)
	{
		LCD_WriteData('+');
		Number1=Number;
	}
	else
	{
		LCD_WriteData('-');
		Number1=-Number;
	}
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i,SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		{
			LCD_WriteData(SingleNumber+'0');
		}
		else
		{
			LCD_WriteData(SingleNumber-10+'A');
		}
	}
}

/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
	}
}

蜂鸣器模块Buzzer

蜂鸣器模块主要是为了发出按键提示音

Buzzer.h

#ifndef __BUZZER_H__
#define __BUZZER_H__

void Buzzer_Time(unsigned int xms);

#endif

Buzzer.c

#include <REGX52.H>
#include <INTRINS.H>
#include "Delay.h"

//蜂鸣器端口
sbit Buzzer=P2^5;

/**
 * @brief 蜂鸣器私有延迟500us函数
 * @param 无
 * @retval 无
 */ 
void Buzzer_Delay500us(void)	//@11.0592MHz
{
	unsigned char data i;

	_nop_();
	i = 227;
	while (--i);
}

/**
 * @brief 蜂鸣器持续发声时间
 * @param 时间 单位ms
 * @retval 无
 */ 
void Buzzer_Time(unsigned int ms)
{
	unsigned int i;
	for(i=0;i<ms*2;i++) 
	{
		Buzzer=!Buzzer;
		Buzzer_Delay500us();
	}
}

Delay延时函数模块

其主要作用是延迟一定时间

Delay.h

#ifndef __DELAY_H__
#define __DELAY_H__

void Delay(unsigned int xms);

#endif

Delay.c

void Delay(unsigned int xms)	//@12.000MHz
{
	unsigned char data i, j;
	
	while(xms--)
	{
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
	}
}

矩阵键盘模块Matrix

主要是为了扫描矩阵键盘,读取矩阵键盘的按键码

Matrix.h

#ifndef __MATRIX_H__
#define __MATRIX_H__

unsigned char MatrixKey();

#endif

Matrix.c

#include <REGX52.H>
#include "Delay.h"

/**
 * @brief 矩阵键盘读取按键键码
 * @param 无
 * @retval KeyNumber 按下按键的键码值
					 如果按键按下不放,程序会停留在子函数,松手的一瞬间返回按键键码 没有按键按下时返回0
 */
unsigned char MatrixKey()
{
	unsigned char KeyNumber = 0;
	
	P1=0xFF;   //全部置高
	//第一列
	P1_3=0;   //P1_3置0 检测第1列
	if(P1_7 == 0) {Delay(20);while(P1_7 == 0);Delay(20);KeyNumber=1;}
	if(P1_6 == 0) {Delay(20);while(P1_6 == 0);Delay(20);KeyNumber=5;}
	if(P1_5 == 0) {Delay(20);while(P1_5 == 0);Delay(20);KeyNumber=9;}
	if(P1_4 == 0) {Delay(20);while(P1_4 == 0);Delay(20);KeyNumber=13;}
	
	P1=0xFF;   //全部置高
	//第二列
	P1_2=0;   //P1_2置0 检测第2列
	if(P1_7 == 0) {Delay(20);while(P1_7 == 0);Delay(20);KeyNumber=2;}
	if(P1_6 == 0) {Delay(20);while(P1_6 == 0);Delay(20);KeyNumber=6;}
	if(P1_5 == 0) {Delay(20);while(P1_5 == 0);Delay(20);KeyNumber=10;}
	if(P1_4 == 0) {Delay(20);while(P1_4 == 0);Delay(20);KeyNumber=14;}
	
	P1=0xFF;   //全部置高
	//第三列
	P1_1=0;   //P1_1置0 检测第3列
	if(P1_7 == 0) {Delay(20);while(P1_7 == 0);Delay(20);KeyNumber=3;}
	if(P1_6 == 0) {Delay(20);while(P1_6 == 0);Delay(20);KeyNumber=7;}
	if(P1_5 == 0) {Delay(20);while(P1_5 == 0);Delay(20);KeyNumber=11;}
	if(P1_4 == 0) {Delay(20);while(P1_4 == 0);Delay(20);KeyNumber=15;}
	
	P1=0xFF;   //全部置高
	//第四列
	P1_0=0;   //P1_0置0 检测第4列
	if(P1_7 == 0) {Delay(20);while(P1_7 == 0);Delay(20);KeyNumber=4;}
	if(P1_6 == 0) {Delay(20);while(P1_6 == 0);Delay(20);KeyNumber=8;}
	if(P1_5 == 0) {Delay(20);while(P1_5 == 0);Delay(20);KeyNumber=12;}
	if(P1_4 == 0) {Delay(20);while(P1_4 == 0);Delay(20);KeyNumber=16;}
	
	return KeyNumber;
}

主函数模块

需要导入的头文件
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "Matrix.h"
#include "Buzzer.h"
定义宏,替换加减乘除的序号
#define ADD 1
#define SUB 2
#define MUL 3
#define DIV 4
定义的变量
  • 定义两个全局栈,分别是NumArray[]和Operation[],表示操作数栈和运算符栈。
  • 定义变量NumLen和OperationLen,表示两个栈的元素个数。
  • 定义变量NumLenShow和OperationLenShow,表示当前在LCD1602上显示的操作数个数和运算符个数,方便定位LCD1602光标进行显示
  • 定义变量KeyNum,用于暂存每次按下的键码值
  • 定义变量Temp,用于存放和显示每个操作数
  • 定义变量TempOperation,用于存放和显示输入的运算符
  • 定义变量flag,表明一次运算是否完成,也就是是否按了等号(S16)
  • 定义数组OperationPriority,用于存放各个运算符的优先级,OperationPriority[0]不使用
bit flag;   //表明一次运算完成,也就是按了等号
unsigned char KeyNum;   //每次按下的键码值
unsigned int NumArray[10]
unsigned char Operation[5], OperationLen, NumLen, OperationLenShow, NumLenShow;
unsigned char OperationPriority[5] = {0,1,1,2,2};
函数声明

操作数栈的操作:入栈、出栈、获取栈顶元素

  • void NumArrayPush(unsigned int Num);
  • unsigned int NumArrayPop();
  • unsigned int NumArrayGetTop();

运算符栈的操作:入栈、出栈、获取栈顶元素

  • void OperationPush(unsigned char OperationNum);
  • unsigned char OperationPop();
  • unsigned char OperationGetTop();

清空操作:清空栈和清空LCD屏幕

  • void ClearStack();
  • void ClearLCD();

运算操作:输入两个无符号整数和对应的运算符进行运算

  • unsigned int Operate(unsigned int Num1, unsigned int Num2, unsigned char Operation);
//函数声明
void OperationPush(unsigned char OperationNum);
unsigned char OperationPop();
unsigned char OperationGetTop();
void NumArrayPush(unsigned int Num);
unsigned int NumArrayPop();
unsigned int NumArrayGetTop();
unsigned int Operate(unsigned int Num1, unsigned int Num2, unsigned char Operation);
void ClearStack();
void ClearLCD();
主函数
  1. 定义a, b, res用于存放一次运算的两个操作数和一个运算结果,之后进行LCD初始化
  2. 在循环体中进行按键扫描,扫描按键按下,如果有按键按下,蜂鸣器发出提示音。获取按下按键键码值,检测标志位,如果上一次已经计算完成过一次,需要先进行清屏,标志位改为0。
  3. 再判断按键属于什么范围,如果是操作数范围S1-S10(S1-S9表示数字1-9,S10表示0,使用%10的方式就可以快速完成映射),用Temp暂存一个操作数,如果Temp不超过三位数即合法,否则清屏显示Overflow。每次输入一个数字,Temp*10+KeyNum,并且实时在屏幕上显示Temp,显示起始位置使用1+NumLenShow*3+OperationLenShow来计算
  4. 如果按下按键属于运算符,意味着之前的操作数已经完整,将NumLenShow++,并将Temp存入操作数栈中,Temp清0。并将矩阵按键键码与运算符的序号通过TempOperation=KeyNum-10;进行映射,存放到TempOperation中,并显示在LCD1602上,OperationLenShow++;。判断当前运算符栈是否为空,根据刚刚的思路进行
  5. 如果按下的是S15(清空键),将Temp=0,清空两个栈和LCD1602屏幕
  6. 如果按下的是S16(等于键),将操作数和运算符栈中剩下的元素进行运算,最终在LCD第二行显示运算结果
void main()
{
	unsigned int a, b, res;
	LCD_Init();
	while(1)
	{
		KeyNum = MatrixKey();   //按键数字
		if(KeyNum) 
		{
			Buzzer_Time(100);   //提示音
			
			if(flag)
			{
				//如果计算完成一次,先进行清屏
				flag = 0;
				ClearStack();
				ClearLCD();
			}
			
			if(KeyNum>=1&&KeyNum<=10)
			{
				//如果输入是数字
				if(Temp*10+KeyNum>999)
				{
					ClearStack();
					ClearLCD();
					LCD_ShowString(1,1,"Overflow");
					//现在清空Temp
					Temp=0;
				}
				else
				{
					KeyNum%=10;
					Temp*=10;
					Temp+=KeyNum;
					LCD_ShowNum(1,1+NumLenShow*3+OperationLenShow,Temp,3);
				}
			}
			else if(KeyNum>=11&&KeyNum<=14)
			{
				if(Temp>999)
				{
					ClearStack();
					ClearLCD();
					LCD_ShowString(1,1,"Overflow");
					//现在清空Temp
					Temp=0;
				}
				else
				{
					//现在是运算符,操作数入栈
					NumLenShow++;
					NumArrayPush(Temp);
					//现在清空Temp
					Temp=0;
					//加减乘除 1,2,3,4
					TempOperation=KeyNum-10;
					switch(TempOperation)
					{
						case ADD:
							LCD_ShowChar(1,1+NumLenShow*3+OperationLenShow,'+');
							break;
						case SUB:
							LCD_ShowChar(1,1+NumLenShow*3+OperationLenShow,'-');
							break;
						case MUL:
							LCD_ShowChar(1,1+NumLenShow*3+OperationLenShow,'*');
							break;
						case DIV:
							LCD_ShowChar(1,1+NumLenShow*3+OperationLenShow,'/');
							break;
					}
					//显示出一个运算符,运算符数++
					OperationLenShow++;
					if(OperationLen==0)
					{
						//如果当前运算符栈中为空,直接入栈
						OperationPush(TempOperation);
					}
					else if(OperationLen!=0&&OperationPriority[TempOperation]<=OperationPriority[OperationGetTop()]) 
					{
						//如果运算符栈非空并且当前运算符优先级没有之前的高,取出一个运算符和两个运算数进行运算
						//运算后的数放入数栈,当前运算符放入运算符栈
						b=NumArrayPop();
						a=NumArrayPop();
						res = Operate(a,b,OperationPop());
						NumArrayPush(res);
						OperationPush(TempOperation);
					}
					else if(OperationLen!=0&&OperationPriority[TempOperation]>OperationPriority[OperationGetTop()]) 
					{
						//栈非空并且当前运算符优先级更高,直接把运算符放入栈中
						OperationPush(TempOperation);
					}
				}
			}
			else if(KeyNum==15)
			{
				//清空键
				Temp=0;
				ClearLCD();
				ClearStack();
			}
			else
			{
				//确认键
				//LCD_ShowNum(2,10,Temp,3);
				NumArrayPush(Temp);
				Temp=0;
				//这里先出来的是右操作数,搞半天..
				b=NumArrayPop();
				a=NumArrayPop();
				res = Operate(a,b,OperationPop());
				NumArrayPush(res);
				LCD_ShowChar(2,2,'=');
				LCD_ShowNum(2,3,NumArrayGetTop(),6);
				flag=1;
				while(OperationLen!=0)
				{
					b=NumArrayPop();
					a=NumArrayPop();
					res = Operate(a,b,OperationPop());
					NumArrayPush(res);
					LCD_ShowChar(2,2,'=');
					LCD_ShowNum(2,3,NumArrayGetTop(),6);
				}
			}
		}
	}
}
			
主函数模块整体代码
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "Matrix.h"
#include "Buzzer.h"

#define ADD 1
#define SUB 2
#define MUL 3
#define DIV 4

bit flag;   //表明一次运算完成,也就是按了等号
unsigned char KeyNum;   //每次按下的键码值
unsigned int NumArray[10], Temp, TempOperation;   
unsigned char Operation[5], OperationLen, NumLen, OperationLenShow, NumLenShow;
unsigned char OperationPriority[5] = {0,1,1,2,2};

//函数声明
void OperationPush(unsigned char OperationNum);
unsigned char OperationPop();
unsigned char OperationGetTop();
void NumArrayPush(unsigned int Num);
unsigned int NumArrayPop();
unsigned int NumArrayGetTop();
unsigned int Operate(unsigned int Num1, unsigned int Num2, unsigned char Operation);
void ClearStack();
void ClearLCD();

/**
 * 小小计算器,使用矩阵键盘,并且能发出提示音
 * S1-S10分别表示 1-9,0
 * S11-S14分别表示+ - * /
 * S15表示清屏
 * S16表示等于 显示运算结果
 * 但是目前有许多限制,只能三位整数运算,最大不能超过unsigned int类型的表示范围,不能有负数,结果也不行
 * 屏幕不够大,无法实现滑动效果
 */
void main()
{
	unsigned int a, b, res;
	LCD_Init();
	while(1)
	{
		KeyNum = MatrixKey();   //按键数字
		if(KeyNum) 
		{
			Buzzer_Time(100);   //提示音
			
			if(flag)
			{
				//如果计算完成一次,先进行清屏
				flag = 0;
				ClearStack();
				ClearLCD();
			}
			
			if(KeyNum>=1&&KeyNum<=10)
			{
				//如果输入是数字
				if(Temp*10+KeyNum>999)
				{
					ClearStack();
					ClearLCD();
					LCD_ShowString(1,1,"Overflow");
					//现在清空Temp
					Temp=0;
				}
				else
				{
					KeyNum%=10;
					Temp*=10;
					Temp+=KeyNum;
					LCD_ShowNum(1,1+NumLenShow*3+OperationLenShow,Temp,3);
				}
			}
			else if(KeyNum>=11&&KeyNum<=14)
			{
				if(Temp>999)
				{
					ClearStack();
					ClearLCD();
					LCD_ShowString(1,1,"Overflow");
					//现在清空Temp
					Temp=0;
				}
				else
				{
					//现在是运算符,操作数入栈
					NumLenShow++;
					NumArrayPush(Temp);
					//现在清空Temp
					Temp=0;
					//加减乘除 1,2,3,4
					TempOperation=KeyNum-10;
					switch(TempOperation)
					{
						case ADD:
							LCD_ShowChar(1,1+NumLenShow*3+OperationLenShow,'+');
							break;
						case SUB:
							LCD_ShowChar(1,1+NumLenShow*3+OperationLenShow,'-');
							break;
						case MUL:
							LCD_ShowChar(1,1+NumLenShow*3+OperationLenShow,'*');
							break;
						case DIV:
							LCD_ShowChar(1,1+NumLenShow*3+OperationLenShow,'/');
							break;
					}
					//显示出一个运算符,运算符数++
					OperationLenShow++;
					if(OperationLen==0)
					{
						//如果当前运算符栈中为空,直接入栈
						OperationPush(TempOperation);
					}
					else if(OperationLen!=0&&OperationPriority[TempOperation]<=OperationPriority[OperationGetTop()]) 
					{
						//如果运算符栈非空并且当前运算符优先级没有之前的高,取出一个运算符和两个运算数进行运算
						//运算后的数放入数栈,当前运算符放入运算符栈
						b=NumArrayPop();
						a=NumArrayPop();
						res = Operate(a,b,OperationPop());
						NumArrayPush(res);
						OperationPush(TempOperation);
					}
					else if(OperationLen!=0&&OperationPriority[TempOperation]>OperationPriority[OperationGetTop()]) 
					{
						//栈非空并且当前运算符优先级更高,直接把运算符放入栈中
						OperationPush(TempOperation);
					}
				}
			}
			else if(KeyNum==15)
			{
				//清空键
				Temp=0;
				ClearLCD();
				ClearStack();
			}
			else
			{
				//确认键
				//LCD_ShowNum(2,10,Temp,3);
				NumArrayPush(Temp);
				Temp=0;
				//这里先出来的是右操作数,搞半天..
				b=NumArrayPop();
				a=NumArrayPop();
				res = Operate(a,b,OperationPop());
				NumArrayPush(res);
				LCD_ShowChar(2,2,'=');
				LCD_ShowNum(2,3,NumArrayGetTop(),6);
				flag=1;
				while(OperationLen!=0)
				{
					b=NumArrayPop();
					a=NumArrayPop();
					res = Operate(a,b,OperationPop());
					NumArrayPush(res);
					LCD_ShowChar(2,2,'=');
					LCD_ShowNum(2,3,NumArrayGetTop(),6);
				}
			}
		}
	}
}

//进行运算
unsigned int Operate(unsigned int Num1, unsigned int Num2, unsigned char Operation)
{
	unsigned int res;
	switch(Operation)
	{
		case ADD:
			res = Num1 + Num2;
			break;
		case SUB:
			res = Num1 - Num2;
			break;
		case MUL:
			res = Num1 * Num2;
			break;
		case DIV:
			res = Num1 / Num2;
			break;
	}
	
	return res;
}

//操作数进栈
void NumArrayPush(unsigned int Num)
{
	NumArray[NumLen]=Num;
	NumLen++;
}

//操作数出栈
unsigned int NumArrayPop()
{
	NumLen--;
	return NumArray[NumLen];
}

//得到操作数栈顶元素
unsigned int NumArrayGetTop()
{
	return NumArray[NumLen-1];
}

//运算符进栈
void OperationPush(unsigned char OperationNum)
{
	Operation[OperationLen]=OperationNum;
	OperationLen++;
}

//运算符出栈
unsigned char OperationPop()
{
	OperationLen--;
	return Operation[OperationLen];
}

//得到运算符栈顶元素
unsigned char OperationGetTop()
{
	return Operation[OperationLen-1];
}

//清空两个栈
void ClearStack()
{
	NumLen=0;
	OperationLen=0;
}

//清空屏幕
void ClearLCD()
{
	NumLenShow=0;
	OperationLenShow=0;
	LCD_ShowString(1,1,"                ");
	LCD_ShowString(2,1,"                ");
}

结果展示

在这里插入图片描述
在这里插入图片描述

  • 60
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值