51单片机实现简易计算器

这篇博客介绍了使用STC89C52单片机设计的一款简易计算器,具备加减乘除功能,支持整数输入及正负数运算。用户可以通过独立和矩阵键盘进行操作,结果显示在数码管上,错误输入时有删除键辅助,还能保存和读取计算结果。此外,计算器还包括LED灯循环点亮和蜂鸣器提示等功能。
摘要由CSDN通过智能技术生成

简介:
使用的单片机型号为"STC89C52",使用的模块为独立键盘和矩阵键盘,LED,蜂鸣器,数码管这些较基础的模块。
具体功能:
可以实现两个数字的加减乘除运算(两个数字为整数,位数可调,区分正负),结果保留整数,区分正负。在输入错误时有删除键,可以一位一位的删除(比如输入34,按下删除键后就变为3)。数码管显示时,需要用到的点亮,不需要用到的没有被点亮(个人认为这样比较舒服~)。
计算器的按键分布:
7 8 9 +
4 5 6 -
1 2 3 *
D 0 = ÷
F T W R
(D为删除键,F为关机键,T为开机键,W为存储键,R为读取键)
另外自己加的小功能:
在得到结果后,还设置有结果的保存键和读取键,按下后可以储存结果和读取结果。另外设置有不掉电的伪开机和伪关机键,按下后可以实现显示的关闭和打开。每按下一次键盘后LED灯都会循环点亮,并且蜂鸣器会发出短暂的声音。
完整的代码如下:

#include <reg52.h>
#include <intrins.h>

typedef unsigned int uint;
typedef unsigned char uchar;

sbit DU=P2^6;
sbit WE=P2^7;
sbit Beep=P2^3;

uchar code SMGduan[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};//数码管0-9
uchar code LED[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//数码管位选

int num;
int n1=0,n2=0;//数据传递的中间变量
uchar flag;//运算符号标志位
uchar F,T;//输入负数的标志位
uchar i=0;//LED灯移位标志位
uchar j=0;//计算器开关标志位
uchar A=0;//储存结果数组变量
uchar C=0;//读取结果数组变量
int tabel5[20]={0};//计算器计算结果储存数组

//数码管动态显示
void delay(uint z)
{
	uint x,y;
	for(x=z;x>0;x--)
		for(y=114;y>0;y--);
}

void display(int i)
{
	if(i>=0)
	{
		if(i<10)
		{
			P0=0XFF;
			WE=1;
			P0=0XFE;
			WE=0;
			DU=1;
			P0=SMGduan[i];
			DU=0;
			delay(8);
		}
		if(i>=10&&i<99)
		{
			P0=0XFF;
			WE=1;
			P0=0XFE;
			WE=0;
			DU=1;
			P0=SMGduan[i/10];
			DU=0;
			delay(8);
			P0=0XFF;
			WE=1;
			P0=0XFd;
			WE=0;
			DU=1;
			P0=SMGduan[i%10];
			DU=0;
			delay(8);
		}
		if(i>=100&&i<999)
		{
			P0=0XFF;
			WE=1;
			P0=0XFE;
			WE=0;
			DU=1;
			P0=SMGduan[i/100];
			DU=0;
			delay(8);
			P0=0XFF;
			WE=1;
			P0=0XFd;
			WE=0;
			DU=1;
			P0=SMGduan[i%100/10];
			DU=0;
			delay(8);
			P0=0XFF;
			WE=1;
			P0=0XFb;
			WE=0;
			DU=1;
			P0=SMGduan[i%10];
			DU=0;
			delay(8);
		}
	}
	else
	{
		i=-i;
		if(i<9)
		{
			P0=0XFF;
			WE=1;
			P0=0XFE;
			WE=0;
			DU=1;
			P0=0x40;
			DU=0;
			delay(8);
			P0=0XFF;
			WE=1;
			P0=0XFd;
			WE=0;
			DU=1;
			P0=SMGduan[i];
			DU=0;
			delay(8);
		}
		if(i>=10&&i<99)
		{
			P0=0XFF;
			WE=1;
			P0=0XFe;
			WE=0;
			DU=1;
			P0=0x40;
			DU=0;
			delay(8);
			P0=0XFF;
			WE=1;
			P0=0XFd;
			WE=0;
			DU=1;
			P0=SMGduan[i/10];
			DU=0;
			delay(8);
			P0=0XFF;
			WE=1;
			P0=0XFb;
			WE=0;
			DU=1;
			P0=SMGduan[i%10];
			DU=0;
			delay(8);
		}
		if(i>=100&&i<999)
		{
			P0=0XFF;
			WE=1;
			P0=0XFe;
			WE=0;
			DU=1;
			P0=0x40;
			DU=0;
			delay(8);
			P0=0XFF;
			WE=1;
			P0=0XFd;
			WE=0;
			DU=1;
			P0=SMGduan[i/100];
			DU=0;
			delay(8);
			P0=0XFF;
			WE=1;
			P0=0XFb;
			WE=0;
			DU=1;
			P0=SMGduan[i%100/10];
			DU=0;
			delay(8);
			P0=0XFF;
			WE=1;
			P0=0XF7;
			WE=0;
			DU=1;
			P0=SMGduan[i%10];
			DU=0;
			delay(8);
		}
	}
}
//也可以用中断来实现

//矩阵键盘的扫描
void keyscan()
{
	uchar temp;
	P3=0XFF;
	P3=0XFE;
	temp=P3&0XF0;
	if(temp!=0xf0)
	{
		delay(20);
		P3=0XFE;
		temp=P3&0xf0;
		if(temp!=0xf0)
		{
			temp=P3;
			switch(temp)
			{
				case 0xee: 	Beep=0;
							delay(20);
							Beep=1;
							if(T==0)
							{
								n1=10*n1+7;num=n1;F=1;i++;break;
							}
							if(T==1)
							{
								n1=10*n1-7;num=n1;F=1;i++;break;
							}	
				case 0xde: 	Beep=0;
							delay(20);
							Beep=1;
							if(T==0)
							{
								n1=10*n1+8;num=n1;F=1;i++;break;
							}
							if(T==1)
							{
								n1=10*n1-8;num=n1;F=1;i++;break;
							}
				case 0xbe: 	Beep=0;
							delay(20);
							Beep=1;
							if(T==0)
							{
								n1=10*n1+9;num=n1;F=1;i++;break;
							}
							if(T==1)
							{
								n1=10*n1-9;num=n1;F=1;i++;break;
							}
				case 0x7e: 	Beep=0;
							delay(20);
							Beep=1;
							n2=n1;
							n1=0;
							flag=1;
							WE=1;
							P0=0XFF;
							WE=0;
							T=0;
							F=0;
							i++;
							break;
			}//+
			while(temp!=0xf0)
			{
				temp=P3;
				temp=temp&0xf0;
			}
			P3=0XFF;
		}
	}
	P3=0XFF;
	P3=0XFD;
	temp=P3&0xf0;
	if(temp!=0xf0)
	{
		delay(20);
		P3=0XFD;
		temp=P3&0xf0;
		if(temp!=0xf0)
		{
			temp=P3;
			switch(temp)
			{
				case 0xed:	Beep=0;
							delay(20);
							Beep=1;
							if(T==0)
							{
								n1=10*n1+4;num=n1;F=1;i++;break;
							}
							if(T==1)
							{
								n1=10*n1-4;num=n1;F=1;i++;break;
							}
				case 0xdd: 	Beep=0;
							delay(10);
							Beep=1;
							if(T==0)
							{
								n1=10*n1+5;num=n1;F=1;i++;break;
							}
							if(T==1)
							{
								n1=10*n1-5;num=n1;F=1;i++;break;
							}
				case 0xbd: 	Beep=0;
							delay(20);
							Beep=1;
							if(T==0)
							{
								n1=10*n1+6;num=n1;F=1;i++;break;
							}
							if(T==1)
							{
								n1=10*n1-6;num=n1;F=1;i++;break;
							}
				case 0x7d: 	Beep=0;
							delay(20);
							Beep=1;
				 		   if(F==1)
						   {
								n2=n1;
								n1=0;
								flag=2;
								WE=1;
								P0=0XFF;
								WE=0;
								T=0;
								F=0;
								i++;
								break;
							}//-
							if(F==0)
							{
								T=1;
								break;
							}//负号					
			}
			while(temp!=0xf0)
			{
				temp=P3;
				temp=temp&0xf0;
			}
			P3=0XFF;
		}
	}
	P3=0XFF;
	P3=0XFB;
	temp=P3&0xf0;
	if(temp!=0xf0)
	{
		delay(20);
		P3=0XFB;
		temp=P3&0XF0;
		if(temp!=0xf0)
		{
			temp=P3;
			switch(temp)
			{
				case 0xeb: 	Beep=0;
							delay(20);
							Beep=1;
							if(T==0)
							{
								n1=10*n1+1;num=n1;F=1;i++;break;
							}
							if(T==1)
							{
								n1=10*n1-1;num=n1;F=1;i++;break;
							}
				case 0xdb: 	Beep=0;
							delay(20);
							Beep=1;
							if(T==0)
							{
								n1=10*n1+2;num=n1;F=1;i++;break;
							}
							if(T==1)
							{
								n1=10*n1-2;num=n1;F=1;i++;break;
							}
				case 0xbb: 	Beep=0;
							delay(20);
							Beep=1;
							if(T==0)
							{
								n1=10*n1+3;num=n1;F=1;i++;break;
							}
							if(T==1)
							{
								n1=10*n1-3;num=n1;F=1;i++;break;
							}
				case 0x7b: 	Beep=0;
							delay(20);
							Beep=1;
							n2=n1;
							n1=0;
							flag=3;
							WE=1;
							P0=0XFF;
							WE=0;
							T=0;
							F=0;
							i++;
							break;
			}//  X
			while(temp!=0xf0)
			{
				temp=P3;
				temp=temp&0xf0;
			}
			P3=0XFF;
		}
	}
	P3=0XFF;
	P3=0XF7;
	temp=P3&0xf0;
	if(temp!=0xf0)
	{
		delay(20);
		P3=0XF7;
		temp=P3&0xf7;
		if(temp!=0xf0)
		{
			temp=P3;
			switch(temp)
			{
				case 0xe7: 	Beep=0;
							delay(20);
							Beep=1;
							i++;
							n1=n1/10;
							num=n1;
							break;
				case 0xd7: 	Beep=0;
							delay(20);
							Beep=1;
							if(T==0)
							{
								n1=10*n1;num=n1;F=1;i++;break;
							}
							if(T==1)					
							{
								n1=10*n1;num=n1;F=1;i++;break;
							}
				case 0xb7: 	Beep=0;
							delay(20);
							Beep=1;
							if(flag==1) num=n2+n1;	
						   	if(flag==2) num=n2-n1;
						   	if(flag==3) num=n2*n1;
						   	if(flag==4) num=n2/n1;
						  	n1=0;
						   	WE=1;
						   	P0=0XFF;
						  	WE=0;
						   	F=0;//一次计算完成后重置标志位
						   	i++;
						   	break;//=
				case 0x77: 	Beep=0;
							delay(20);
							Beep=1;
							n2=n1;
							n1=0;
							flag=4;
							WE=1;
							P0=0XFF;
							WE=0;
							T=0;
							F=0;
							i++;
							break;//÷
			}
			while(temp!=0xf0)
			{
				temp=P3;
				temp=temp&0xf0;
			}
			P3=0XFF;
		}
	}
	P3=0XFF;
	if(P3==0XFB)
	{
		delay(20);
		if(P3==0XFB)
		{
			tabel5[A]=num;
			C=A;//将数组变量赋给读取数组的变量
			A++;
			n1=0;
			num=0;
			if(A>9)
			{
				for(A=9;A>-1;A--)
				{
					tabel5[A]=0;
				}
				A=0;
			}//存满后自动清零
			while(P3==0XFB);
		}
	}
	if(P3==0XF7)
	{
		delay(20);
		if(P3==0XF7)
		{
			num=tabel5[C];
			C--;
			while(P3==0XF7);
		}
	}				
}
void keyscan1()//部分独立键盘判断
{
	if(P3==0XFE)
	{
		delay(10);
		if(P3==0XFE)
		{
			j=1;
			WE=1;
			P0=0xFF;
			WE=0;
			num=0;
			n1=0;
			Beep=0;
			delay(20);
			Beep=1;
			P1=0XFF;
			while(P3==0XFE);
		}
	}
	P3=0XFF;
	if(P3==0XFD)
	{
		delay(20);
		if(P3==0XFD)
		{
			j=0;
			Beep=0;
			delay(20);
			Beep=1;
			while(P3==0XFD);
		}
	}
}
void main()
{
	while(1)
	{
		if(j==1)
		{
			keyscan1();
		}
		if(j==0)
		{	
			keyscan();
			display(num);
			P1=LED[i];
			if(i>7)
			{
				i=0;
			}
			keyscan1();
		}
	}
}

已经通过编译测试,代码可以正常使用。个人认为写的还比较好理解,毕竟我学单片机也没多久(=。=)。
代码可能看起来比较冗余,欢迎各位大神提出意见,我看到后会努力精简的!
第一次尝试在CSDN平台发布自己写的代码,希望读到本文的各位多多鼓励哈~相信我们很快会再次见面的!

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值