基于AT89C51单片机的多功能计算器设计(含文档、源码与proteus仿真,以及系统详细介绍)

本篇文章论述的是基于AT89C51单片机的多功能计算器设计的详情介绍,如果对您有帮助的话,还请关注一下哦,如果有资源方面的需要可以联系我。

目录

摘要 

元件清单

仿真图

原理图

代码

系统论文

资源下载


摘要 

当今社会,随着人们物质生活的不断提高,电子产品已经走进了家家户户,无论是生活或学习,还是娱乐和消遣几乎样样都离不开电子产品,大型复杂的计算能力是人脑所不能胜任的,而且人脑比较容易出错。计算器作为一种快速通用的计算工具方便了用户的使用。计算器可谓是我们最亲密的电子伙伴之一。本设计着重在于分析计算器设计开发过程中的环节和步骤,并从实践经验出发对计算器设计做了详细的分析和研究。

本设计是以STC89C52单片机为核心的计算器模拟系统设计,输入采用5×8矩阵键盘,可以进行加、减、乘、除等十几种数字运算,同时支持括号的嵌套使用级浮点数的运算,并在LCD1602上显示操作过程。

本次设计注重设计方法及流程,首先根据原理设计电路,利用keil编程,借助实验开发平台进行仿真实验,进而利用altium designer 制作PCB,最后到焊接元器件,直至调试成功。在设计的同时,特别注重keil软件和altium designer软件的使用方法和技巧以及常用的LCD显示器和矩阵键盘的设计和使用方法。

关键词】 计算器,STC89C52,矩阵键盘,1602液晶

元件清单


仿真图


原理图


代码


#include <REGX51.H>
#include<intrins.h>
#include<stdio.h>
#include<string.h>
#include<math.h>
sbit RS = P2^5; 
sbit RW = P2^6; 
sbit E  = P2^7; 

#define Data  P0//数据端口
//全局变量
float num1;//第一操作数num1     (初始为零)
float num2;//第二操作数num2     (初始为零)
char yun_flag='+';//运算符号 yun_flag    (默认为+ )
char key_last;//上次按键状态标志 key_last
char sqrt_flag;//开方键按下标志   sqrt_flag
unsigned long pos_flag=1;//小数位权pos_flag      (默认为1)
char neg_flag;//正负标志 neg_flag
char data c_num1[15]=" ";//c_num1 字符型第一操作数 (数组不定义大小与其他变量冲突)
char data c_num2[15]=" ";//c_num2 字符型第二操作数
char error;//运算法则错误;
char len;//小数点后位数
/*                    微秒延时函数                                */
/******************************************************************/
void DelayUs(unsigned char us)//delay us
{
 unsigned char uscnt;
 uscnt=us>>1;        /*12MHz频率*/
 while(--uscnt);
}
/******************************************************************/
/*                    毫秒函数声明                                */
/******************************************************************/
void DelayMs(unsigned char ms)
{
 while(--ms)
   {
     DelayUs(250);
     DelayUs(250);
	 DelayUs(250);
	 DelayUs(250);
   }
}
/******************************************************************/
/*                   写入命令函数                                 */
/******************************************************************/
void WriteCommand(unsigned char c)
{
 DelayMs(5);//操作前短暂延时,保证信号稳定
 E=0;
 RS=0;
 RW=0;
 _nop_();
 E=1;
 Data=c;
 E=0;
}
/******************************************************************/
/*                   写入数据函数                                 */
/******************************************************************/
void WriteData(unsigned char c)
{
 DelayMs(5);  //操作前短暂延时,保证信号稳定
 E=0;
 RS=1;
 RW=0;
 _nop_();
 E=1;
 Data=c;
 E=0;
 RS=0;
}
/******************************************************************/
/*                   写入字节函数                                 */
/******************************************************************/
void ShowChar(unsigned char pos,unsigned char c)
{
 unsigned char p;
 if (pos>=0x10)
    p=pos+0xb0; //是第二行则命令代码高4位为0xc
 else 
    p=pos+0x80; //是第二行则命令代码高4位为0x8
 WriteCommand (p);//写命令
 WriteData (c);   //写数据
}
/******************************************************************/
/*                   写入字符串函数                               */
/******************************************************************/
void ShowString (unsigned char line,char *ptr)
{
 unsigned char l,i;
 l=line<<4;
 for (i=0;*(ptr+i)!='\0';i++)
  ShowChar (l++,*(ptr+i));//循环显示16个字符
}
/******************************************************************/
/*                   初始化函数                                   */
/******************************************************************/
void InitLcd()
{
 DelayMs(15);
 WriteCommand(0x38); //display mode
 WriteCommand(0x38); //display mode
 WriteCommand(0x38); //display mode
 WriteCommand(0x06); //显示光标移动位置
 WriteCommand(0x0c); //显示开及光标设置
 WriteCommand(0x01); //显示清屏

}
/*************按键扫描****************************/
char scan()
{

  char h_data,l_data,i,key_num;
  P2=P2&0XE0;//P2低5位送0
  P1=P1|0X0F;//P1低4位送1
  while((P1|0xf0)==0xff)//判断P1低4位是否全为1
  {
   while((P1|0xf0)==0xff);
   DelayMs(10);//延时10ms
  }
   l_data=~(P1|0xf0);//记入列标志
   P2=P2|0X1F;//P2低五位送1
   P1=P1&0XF0;//P1低四位送0
   h_data=~(P2|0xe0);//记入行标志
   for(i=0;i<=4;i++)//计算行号(0~4)
   	 {
	   if(h_data==1)break;
	   h_data=h_data>>1;
	 }
 h_data=i;//行号
  for(i=1;i<=4;i++)//计算列号(1~4)
 	{
	  if(l_data==1)break;
	  l_data=l_data>>1;
	}
 l_data=i;//列号
   key_num=h_data*4+l_data;	
 
  P2=P2&0XE0;//P2低5位送0
  P1=P1|0X0F;//P1低4位送1
  while((P1|0xf0)!=0xff)//判断P1低4位是否全为1
  {
   while((P1|0xf0)!=0xff);
   DelayMs(10);//延时10ms
  }
  return key_num;
}
void float_to_char(float a,char* p)
{
  char i,flag,length;
  flag=0;
  sprintf(p,"%f",a);
  length=strlen (p);
  for(i=0;i<length;i++)
  {
    if(*(p+i)=='.')flag=1;
  }
  if(flag==1)
  for(i=length-1;i>=0;i--)
  {
    if(*(p+i)=='.'){*(p+i)='\0';break;}
    if(*(p+i)!='0'){*(p+i+1)='\0';break;}
  }
}
/**********************更新液晶*************************/
void refresh()//更新液晶
{
  char length,i,j;
  char dot;
  dot=0;
  	
  float_to_char(num2,c_num2);//num2转为字符型
  length=strlen(c_num2);
  for(i=0,j=0;i<length;i++)	
  {
    if(c_num2[i]=='.')
	dot=1;
	if(dot==1)
    j++;
  } 
  if(j<len)
  {
	  if(dot==1)
	  {	
	    for(i=length;i<(length+len-j);i++)
		 {
		   c_num2[i]='0';
	
		 }
		 c_num2[i]='\0';
	  }
	  else
		{
		  
		  c_num2[length]='.';
		  if(len-j>1)
		  {
		    for(i=length+1;i<(length+len-j);i++)
			 c_num2[i]='0';
		  }
		  c_num2[length+len-j]='\0';
		}  
  }

  if(neg_flag==1)//'+/-'按下首位加‘-’
   {
      length=strlen(c_num2);//计算c_num2长度	  
		    for(i=length-1;i>=0;i--)
		  {
		  	c_num2[i+1]=c_num2[i];
		  }
		  c_num2[length+1]='\0';
		  c_num2[0]='-';
   }
   
   if(sqrt_flag==1)
   	{
      length=strlen(c_num2);//计算c_num2长度
   	  for(i=length-1;i>=0;i--)
	  {
	  	c_num2[i+1]=c_num2[i];
	  }
	  c_num2[length+1]='\0';
	  c_num2[0]=0xe8;//字符根号
   }
   
   
   if(error==0)
   {
	   float_to_char(num1,c_num1);//num1转为字符型
	   WriteCommand(0x01); //显示清屏 
	   ShowString(0,c_num1);
	   ShowString(1,c_num2);  
	   ShowChar(15,yun_flag);
   }else
   { 
       WriteCommand(0x01); //显示清屏 
	   ShowString(0,"error!!!");
   }
}
//键值处理
void operation1(char keynum)//按下 ’+、-、*、/处理
{
  if(key_last==1)//上次按键为 数字、小数点、+/-、sqrt
   {
     if(neg_flag==1)num2=-num2;//'+/-'按下
	 if(sqrt_flag==1)//sqrt按下
	 {
	 if(num2>=0)
	 num2=sqrt(num2);
	 else
	 error=1;
	 }
	 if(yun_flag=='+')num1=num1+num2; //按下的是‘+’
	 if(yun_flag=='-')num1=num1-num2;//按下的是‘-’
	 if(yun_flag=='*')num1=num1*num2;//按下的是‘*’
	 if(yun_flag=='/')//按下的是‘/’
	 {
	   if(num2!=0)
	   num1=num1/num2;
	   else
	   error=1;
	 }
	 num2=0;//num2清零
	 sqrt_flag=0;//sqrt_flag清零
     neg_flag=0;//neg_flag清零
	 pos_flag=1;//pos_flag回1
   }
   if(keynum==4)yun_flag='+';//yun_flag更新
   if(keynum==8)yun_flag='-';
   if(keynum==12)yun_flag='*';
   if(keynum==16)yun_flag='/';
   len=0;
   key_last=0;//key_last更新   
   refresh();
}
//
void operation2(char keynum)//输入数字
{
  float Data1;
   
  if(keynum==1)Data1=7;//分析输入数字
  if(keynum==2)Data1=8;
  if(keynum==3)Data1=9;
  if(keynum==5)Data1=4;
  if(keynum==6)Data1=5;
  if(keynum==7)Data1=6;
  if(keynum==9)Data1=1;
  if(keynum==10)Data1=2;
  if(keynum==11)Data1=3;
  if(keynum==13)Data1=0; 
  if(pos_flag==1)//更新num2
  num2=num2*10+Data1;
  else
  {	    
    num2=num2+(Data1/pos_flag);
	pos_flag=pos_flag*10;
	len++;
  }
  key_last=1;//更新key_last	
  refresh();
}

void operation3()//输入小数点
{
  if(pos_flag==1)//首次出现小数点
  {
   pos_flag=pos_flag*10;//小数位权*10
   len++;
  }
  key_last=1;//更新key_last 
  refresh();//更新液晶
}
/
void operation4()//输入'='
{
     if(neg_flag==1)num2=-num2;//'+/-'按下
	 if(sqrt_flag==1)//sqrt按下
	 {
	 if(num2>=0)
	 num2=sqrt(num2);
	 else
	 error=1;
	 }
	 if(yun_flag=='+')num1=num1+num2; //按下的是‘+’
	 if(yun_flag=='-')num1=num1-num2;//按下的是‘-’
	 if(yun_flag=='*')num1=num1*num2;//按下的是‘*’
	 if(yun_flag=='/')//按下的是‘/’
	 {
	   if(num2!=0)
	   num1=num1/num2;
	   else
	   error=1;
	 }
	 num2=0;//num2清零
	 sqrt_flag=0;//sqrt_flag清零
     neg_flag=0;//neg_flag清零
	 pos_flag=1;//pos_flag回1
     yun_flag='+';//yun_flag更新
	 len=0;
   key_last=0;//key_last更新   
   refresh();
}

void operation5()//输入clear all
{

   num1=0;// num1清零
   num2=0;//num2清零
   sqrt_flag=0;//清sqrt_flag
   neg_flag=0;// 清neg_flag
   pos_flag=1;// Pos_flag=1
   yun_flag='+';// yun_flag(为'+')
   error=0;//清error
   len=0;
   key_last=0;//更新key_flag
   refresh();//更新液晶
}
///
void operation6()//输入'C'
{
 num2=0;//num2清零
 sqrt_flag=0;//清sqrt_flag
 neg_flag=0;//清neg_flag
 pos_flag=1;//pos_flag=1
 len=0;
 key_last=0;//key_last
 refresh();//更新液晶 
}

void operation7()//输入'+/-'
{
  if(neg_flag==0)//neg_flag反转
  neg_flag=1;
  else neg_flag=0;
  key_last=1;//key_last
  refresh();// 更新液晶
}
//键值分析
void key(char keynum)
{
  switch(keynum)
  {
    case 4 :
	case 8 :
	case 12:
	case 16://+、-、*、/
	    	{
			 if(error==0)
	         operation1(keynum);
        	 break;}
			
	case 1  : //数字7
	case 2  : //数字8
	case 3  : //数字9
	case 5  : //数字4
	case 6  : //数字5
	case 7  : //数字6
	case 9  : //数字1
	case 10 : //数字2
	case 11 : //数字3
	case 13 : //数字0
	         {
			 if(error==0)
			 operation2(keynum);
			 break;}
			 
	case 14 ://小数点		  
			 {
			   if(error==0)
			   operation3();
			   break;}
			 
	case 15 :// '='	  
			 {
			   if(error==0)
			   operation4();
			   break;}
			 
	case 17 :// clear all  
			 {
			   operation5();
			   break;}

	case 18 :// 'C'  
			 {
			   if(error==0)
			   operation6();
			   break;}
	case 19 :// '+/-'  
			 {
			   if(error==0)
			   operation7();
			   break;}
	case 20 ://sqrt
			 {
			   if(error==0)
			   operation8();
			   break;}		   		   
			   			   		 
  }	  
}
main()
{
 
 InitLcd();         //初始化LCD
DelayMs(15);       //延时保证信号稳定
refresh();
 
        //延时保证信号稳定
while(1)
{
 key(scan());
}
}

系统论文


1  系统方案设计

1.1 设计目的及要求

1.1.1 设计目的

通过本次课题设计,应用《单片机应用基础》、《数据结构》等所学相关知识及查阅资料,完成实用计算器的设计,以达到理论与实践更好的结合、进一步提高综合运用所学知识和设计的能力的目的。

通过本次设计的训练,可以使我在基本思路和基本方法上对基于MCS-51单片机的嵌入式系统设计有一个比较感性的认识,并具备一定程度的设计能力。

1.1.2 设计要求

在本次课程设计中,主要完成如下方面的设计要求:

1、掌握MCS-51系列某种产品(例如8051)的最小电路及外围扩展电路的设计方法;

2、计算器能实现加、减、乘、除、平方、开方、N次方、开N次方、正弦函数、        余弦函数、正切函数、反正弦、反余弦、反正切、对数运算、阶乘(N<=34)、排列、    组合、累加等十九种功能。

3、支持浮点数运算;

4、较为友好的界面显示,对输入实时显示,对计算结果输出显示;

5、能够具备比较完善的报错系统

1.2 方案论证及选择

基于设计要求,笨设计考虑了两种设计方案,他们均可以实现计算器的功能,但基于设计目的及微控制器的广泛运用,比较两种方案的优劣,最终选择基于51单片机的计算器设计。

1.2.1 方案一 采用FPGA控制

FPGA是一种高密度的可编程逻辑器件,自从Xilinx公司1985年推出第一片FPGA以来,FPGA的集成密度和性能提高很快,其集成密度最高达500万门/片以上,系统性能可达200MHz。由于FPGA器件集成度高,方便易用,开发和上市周期短,在数字设计和电子生产中得到迅速普及和应用,并一度在高密度的可编程逻辑器件领域中独占鳌头。

但是而基于 SRAM编程的FPGA,其编程信息需存放在外部存储器上 ,需外部存储器芯片 ,且使用方法复杂 ,保密性差,而其对于一个简单的计算器而言,实用FPGA有点大材小用,成本太高。

1.2.2 方案二 采用STC89C52

单片机是单片微型机的简称,故又称为微控制器MCU(Micro Control Unit)。通常由单块集成电路芯片组成,内部包含有计算机的基本功能部件:中央处理器CPU,存储器和I/O接口电路等。因此,单片机只要和适当的软件及外部设备相结合,便可成为一个单片机控制系统。单片机广泛用于智能产品,智能仪表,测控技术,智能接口等,具有操作简单,实用方便,价格便宜等优点,而其中AT89S52以MCS-51为内核,是单片机中最典型的代表,应用于各种控制领域。

1.2.3 方案比较及选择

通过以上两种方案论证和比较,从设计的实用性,方便性和成本出发,选择了以STC89C52单片机作为中央处理单元进行计算器的设计,这样设计能够实现对六位浮点数的加减和三位浮点数的乘除运算。

3系统测试

测试主要测试其运算是否正确,及检错能力。

3.1 整数运算

在此以整数运算为例,介绍计算器的使用方法即流程。首先打开电源,看到LCD打开显示,说明运行正常,接着,输入表达式:12*(56+23)*2,其结果本身应为1896。

输入结束后,点“=”按键,即可在第二行显示出运算结果,由图可见运算完全正确。在使用时,可以通过声音开关按钮控制按键音的打开和关闭,在LCD上也有显示,如果再第二行第一个位置没有显示,则没有打开声音,可以通过按钮打开。若有显示,则声音已经打开,可以通过按钮关闭声音。如图3.1所示,此时已经打开声音。

图3.1  整数运算

3.2 浮点数运算

图3.2 浮点数运算

由图可以看出,可以进行浮点数运算,还可以从第二行第一个字符,蜂鸣器处于关闭状态。

3.3 输入出错的情况

输入一个错误的表达式,如图3.3所示。

图3.3 输入错误的情况下

再按“=”号,将会出现出错画面。如图3.4所示。

图3.4 输入错误的显示

由以上测试可知,整个设计运行正常,能够正确的进行运算和出错提示。由此可得,整个设计是成功的。


资源下载


如果有需要这个系统的源码、仿真、论文等资源的可以私信我。感谢你的阅读~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值