基于51单片机的智能计算器Protues仿真设计

目录

一、设计背景

二、实现功能

三、硬件设计

3.1 总体硬件设计

​3.2 键盘电路的设计

3.3 显示电路的设计

 四、仿真演示

 五、源程序

一、设计背景

       随着社会的发展,科学的进步,人们的生活水平在逐步的提高,尤其是微电子技术的发展,犹如雨后春笋般的变化。电子产品的更新速度快就不足惊奇了。计算器在人们的日常中是比较的常见的电子产品之一。如何使计算器技术更加的成熟,充分利用已有的软件和硬件条件,设计出更出色的计算器,使其更好的为各个行业服务,成了如今电子领域重要的研究课题。

二、实现功能

     本设计是以AT89C51单片机为核心的计算器模拟系统设计,输入采用4×4矩阵键盘,可以进行加、减、乘、除4位带符号数字运算,最大运算是可达9999*9999,可以运算负数,并在LCD1602上显示操作过程。

三、硬件设计

3.1 总体硬件设计

为了更好的实现系统得功能,硬件电路的设计应该遵循以下原则:

1、优化硬件电路

      采用软件设计与硬件设计相结合的方法;尽管采用软件来实现硬件系统的功能时,也许响应时间会比单纯使用硬件时长,而且还要占用微处理器(MCU)的时间;但是,用软件实现硬件的功能可以简化硬件结构,提高电路的可靠性。所以,在设计本系统得时候,在满足可靠性和实时性的前提下,尽可能的通过软件来实现硬件功能。

2、可靠性及抗干扰设计

      根据可靠性设计理论,系统所用芯片数量越少,系统的平均无故障时间越长。而且,所用芯片数量越少,地址和数据总线在电路板上受干扰的可能性也就越小。因此,系统的设计思想是在满足功能的情况下力争使用较少数量的芯片。

3、灵活的功能扩展

     功能扩展是否灵活是衡量一个系统优劣的重要指标。一次设计往往不能完全考虑到系统的各个方面,系统需要不断完善以及进行功能升级。进行功能扩展时,应该在原有设计的基础上,通过修改软件程序和少量硬件完成。对于本系统而言,就是要求在系统硬件不变的情况下,能够通过修改软件程序,完成功能的升级和扩展。

     根据第提出的系统设计方案,结合以上三条原则,确定了系统硬件的设计。计算器主要由以下一些功能模块构成:非编码键盘模块、LCD液晶显示屏模块等。

下图为总体硬件结构。

3.2 键盘电路的设计

       键盘可分为两类:编码键盘和非编码键盘。编码键盘是较多按键(20个以上)和专用驱动芯片的组合,当按下某个按键时,它能够处理按键抖动、连击等问题,直接输出按键的编码,无需系统软件干预。通用计算机使用的标准键盘就是编码键盘。在智能仪器中,使用并行接口芯片8279或串行接口芯片HD7279均可以组成编码键盘,同时还可以兼顾数码管的显示驱动,其相关的接口电路和接口软件均可在芯片资料中得到。当系统功能比较复杂,按键数量很多时,采用编码键盘可以简化软件设计。从成本角度出发,本设计选用的是非编码键盘。如下图所示:

3.3 显示电路的设计

       当系统需要显示少量数据时,采用LCD液晶显示屏进行显示是一种经济实用的方法。P0口作为液晶显示的数据端口,P3.5-P3.7口作为其控制端口,控制LCD液晶显示屏显示输出数据。如下图所示:

 四、仿真演示

初始界面

 加运算

减运算

乘运算

除运算

 

五、源程序

#include<reg51.h>
#define uint unsigned int
#define uchar unsigned char
//--------LCD1602-------------------
//P00-07==== D0-7
sbit rs=P2^7;        //指令or数据
sbit wela=P2^6;      //读or写
sbit lcden=P2^5;	 //使能信号
//--------LCD1602-------------------
//--------KEY-----------------------
//P1口
//--------KEY-----------------------
uchar code table[]= "                ";

long  int data_a,data_b; 	//第一个数和第二个数
long  int data_c;			//计算结果

uchar dispaly[10];         //显示缓冲

//************************************************************************/
// 描述: 延时t us函数
//************************************************************************/
void LCD_Delay_us(unsigned int t)
{
	while(t--);           //t=0,退出
}
//************************************************************************/
// 描述: 延时t ms函数
//************************************************************************/
void LCD_Delay_ms(unsigned int t)
{
	unsigned int i,j;
	for(i=0;i<t;i++)       		//执行t次循环
	for(j=0;j<113;j++)     		//执行113次循环
	;
}
//************************************************************************/
// 描述: 1602液晶写指令
//************************************************************************/
void write_com(uchar com)    	//1602液晶写指令
{
	rs=0;                       //写指令
	lcden=0;                    //使能1602 
	P0=com;                     //写入指令com
	LCD_Delay_ms(1);            //延时1ms
	lcden=1;                    //使能1602
	LCD_Delay_ms(2);            //延时2ms  
	lcden=0;	                //使能1602
}
//************************************************************************/
// 描述:1602液晶写数据 
//************************************************************************/
void write_date(uchar date) //1602液晶写数据
{
	rs=1;                        //写数据
	lcden=0;                     //使能1602 
	P0=date;                     //写入数据date
	LCD_Delay_ms(1);             //延时1ms
	lcden=1;                     //使能1602
	LCD_Delay_ms(2);             //延时2ms
	lcden=0;	                 //使能1602
}
//************************************************************************/
// 描述:指定x,y写入字符函数
//************************************************************************/
 void W_lcd(unsigned char x,unsigned char y,unsigned char Data) 
 {     
	 if (y == 0){write_com(0x80 + x);}   //第一行  
	 else{write_com(0xc0 + x);}          //第二行
	 write_date( Data);                  //写入数据
 }
 //指定x,y写入字符串函数
 void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s) 
 {     
 if (y == 0){write_com(0x80 + x);} 		//第一行
 else{write_com(0xC0 + x);}        		//第二行
 while (*s)                        		//
 	{write_date( *s); s++;}      		//写入数据
 }
//************************************************************************/
// 描述:初始化液晶,及画面初始化 
//************************************************************************/
void init_lcd(void)            //初始化液晶,及画面初始化
{
	wela=0;                      //写液晶
	lcden=0;                     //使能1602
	write_com(0x38);             //8 位总线,双行显示,5X7 的点阵字符
	LCD_Delay_us(100);           //延时100us
	write_com(0x0c);             //开显示,无光标,光标不闪烁
	write_com(0x06);             //光标右移动
	write_com(0x01);             //清屏
	write_com(0x80);             //DDRAM 地址归0
}
//************************************************************************/
// 描述: 反转法键盘扫描 
//************************************************************************/
short keycheckdown()				/* 反转法键盘扫描 */
{

	short temp1,temp2,temp,a=0xff;
	P1=0xf0;						/* 输入行值(或列值) */
	LCD_Delay_ms(20);				/* 延时 */
	temp1=P1;						/* 读列值(或行值) */
	P1=0xff;
	LCD_Delay_ms(20);				/* 延时 */
	P1=0x0f;						/* 输入列值(或行值) */
	LCD_Delay_ms(20);				/* 延时 */	
	temp2=P1;						/* 读行值(或列值) */
	P1=0xff;
	temp=(temp1&0xf0)|(temp2&0xf);	/* 将两次读入数据组合 */
	switch(temp)					/* 通过读入数据组合判断按键位置 */
	{


		case 0x77 :a=0x0a;break;//  按键+   
		case 0x7b :a=0x0e; break;// 按键=	
		case 0x7d :a=0;	   break;// 按键0
		case 0x7e :a=0x0f; break;// 按键CE

		case 0xe7 :a=0x0d;break;// 	按键/
		case 0xeb :a=0x9;break; //  按键9
		case 0xed :a=0x8;break; //  按键8 
		case 0xee :a=0x7;break; // 	按键7

		case 0xd7 :a=0x0c;break;//  按键*
		case 0xdb :a=0x6;break; // 	按键6
		case 0xdd :a=0x5;break; // 	按键5
		case 0xde :a=0x4;break; // 	按键4

		case 0xb7 :a=0x0b; break;// 按键-
		case 0xbb :a=3;break;	//  按键3
		case 0xbd :a=2;break;	//  按键2
		case 0xbe :a=1;break;	//  按键1

		default :a=0xff;
	}
	return a;						/* 返回按键值 */
}
void display_a() //显示数据a
{
	dispaly[3]=data_a%10000/1000;    //千
	dispaly[2]=data_a%1000/100;      //百
	dispaly[1]=data_a%100/10;        //十
	dispaly[0]=data_a%10;            //个 

	write_com(0x80+0);               //显示数据a
	if(data_a>999){	write_date('0'+dispaly[3]);}      //显示千位
	if(data_a>99){	write_date('0'+dispaly[2]);}		 //显示百位
	if(data_a>9){	write_date('0'+dispaly[1]);}     //显示十位
	      	        write_date('0'+dispaly[0]);      //显示个位
}

void display_b() //显示数据b
{
	write_com(0x80+7); //第一行
	dispaly[3]=data_b%10000/1000;    //千
	dispaly[2]=data_b%1000/100;      //百
	dispaly[1]=data_b%100/10;        //十
	dispaly[0]=data_b%10;            //个 

if(data_b>999){	write_date('0'+dispaly[3]); }     //显示千位   
if(data_b>99) {	write_date('0'+dispaly[2]); }    //显示百位  
if(data_b>9)  {	write_date('0'+dispaly[1]); }     //显示十位
  			    write_date('0'+dispaly[0]);      //显示个位
}

//计算结果
void display_c(x)
{

	if(data_c<100000000&&data_c>-1)//溢出时显示错误
	{	

		dispaly[8]=data_c%1000000000/100000000;    	//万万
		dispaly[7]=data_c%100000000/10000000;    	//千万
		dispaly[6]=data_c%10000000/1000000;    		//百万
		dispaly[5]=data_c%1000000/100000;    		//十万
		dispaly[4]=data_c%100000/10000;    			//万
		dispaly[3]=data_c%10000/1000;    			//千
		dispaly[2]=data_c%1000/100;      			//百
		dispaly[1]=data_c%100/10;        			//十
		dispaly[0]=data_c%10;            			//个 
		write_com(0x80+6+0x40); //第一行
		if(x==4)
		{    
			if(data_c>99999999)	{	write_date('0'+dispaly[8]);}    //显示万万
			if(data_c>9999999)	{	write_date('0'+dispaly[7]);}   //千万
			if(data_c>999999)	{	write_date('0'+dispaly[6]);}    //百万
			if(data_c>99999)	{	write_date('0'+dispaly[5]);}    //十万
			if(data_b!=0)		{
									write_date('0'+dispaly[4]);    //万
									write_date('.');
									write_date('0'+dispaly[3]);    //千
									write_date('0'+dispaly[2]);    //百
									write_date('0'+dispaly[1]);    //十
									write_date('0'+dispaly[0]);    //个 
								}
		}
	else{
		if(data_c>99999999)	{	write_date('0'+dispaly[8]);}    //显示万万
		if(data_c>9999999)	{	write_date('0'+dispaly[7]);}    //千万
		if(data_c>999999)	{	write_date('0'+dispaly[6]);}    //百万
		if(data_c>99999)	{	write_date('0'+dispaly[5]);}    //十万
		if(data_c>9999)		{	write_date('0'+dispaly[4]);}    //万
		if(data_c>999)		{	write_date('0'+dispaly[3]);}    //千
		if(data_c>99)		{	write_date('0'+dispaly[2]);}    //百
		if(data_c>9)		{	write_date('0'+dispaly[1]);}    //十
								write_date('0'+dispaly[0]);    //个 
		}
	}
//	else  //溢出时显示错误
//	{
//		write_com(0x80+11+0x40); //第一行
//		write_date('E');         //显示 E 
//		write_date('r');         //显示R
//		write_date('r');		 //显示R
//		write_date('o');		 //显示O
//		write_date('r');		 //显示E
//	}
}

void eql(uchar x)//加减乘除运算
{
	switch(x)		/*功能键选择*/
			{   
				case 1:data_c=data_a+data_b;break; 		  //加  /* + S=1 */ /* 数值转换函数 */									
				case 2:if(data_a>=data_b){data_c=data_a-data_b;} /* - S=2 *///减
                       else{data_c=data_b-data_a;W_lcd(5,1,'-');} //负数符号
					   break;  	 
				case 3:data_c=(data_a*data_b);break;		  /* * S=3 *///乘
				case 4:if(data_b==0){LCD_Write_String(0,1,"Error !         ");}else{data_c=(data_a*10000)/data_b;}break;		  /* / S=4 *///除//溢出时显示错误
				case 0:break;
			}	  

}

void main()
{
	uchar   key=0xff;               //键值初始化
	uchar   n=0;		 			//第1个数可以按1-4次
	uchar   m=5; 					//第2个数可以按1-4次
	uchar   x=0; 
	data_a=0;                       //前一个数
	data_b=0;                       //后一个数
	data_c=0;                       //结果 
	init_lcd();  					//1602液晶初始化
	display_a();
    while(1)
	  {
	  	key=keycheckdown();			/*动态扫描键盘,返回按键对应值,赋给j        key=0到f */
		if(0xff!=key)				/*若返回值有效,进入内部处理程序*/
		{ 
		  if(key<10)
		  {
		  	if(key==0&&n==0) ;
			else
			{
				if(n<4){data_a=data_a*10+key;m=5;display_a();}n++;  //首先输入第一个数	
			}
	        if(key==0&&m==0) ;
			else
			{
				if(m<4){data_b=data_b*10+key;n=5;display_b();}m++;  //必须按了+-*/才能输入第二个数	
			}
		  }
          else
          {	switch(key)		/*功能键选择*/
					{
						case 0xa:n=5;m=0;x=1;W_lcd(5,0,'+');break; //加  /* + S=1 */ /* 数值转换函数 */									
						case 0xb:n=5;m=0;x=2;W_lcd(5,0,'-');break;		  /* - S=2 *///减
						case 0xc:n=5;m=0;x=3;W_lcd(5,0,'*');break;		  /* * S=3 *///乘
						case 0xd:n=5;m=0;x=4;W_lcd(5,0,'/');break;		  /* / S=4 *///除
						case 0xe:n=5;m=5;eql(x);W_lcd(12,0,'=');display_c(x);break; 	  /* = */
						case 0xf:n=0;x=0;m=5; data_a=0;data_b=0;data_c=0;LCD_Write_String(0,0,table);LCD_Write_String(0,1,table);W_lcd(0,0,'0');break; /*     C*/
					}	  		  
		  }
			do{P1=0xf0;}while(P1!=0xf0);		/*等待按键松开*/
	  	}//(0xff!=key)	  
	  }//while
}//main

  • 22
    点赞
  • 162
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 15
    评论
摘要 近些年以单片机为核心的技术发展很快,现在它被广泛的应用于与我们生活相关的各 个领域中,如电子、通信、科技、工业等,其中电子产品的更新速度更为迅猛。计算器 是日常生活中比较常见的电子产品之一,怎样才能使计算器技术更加的成熟、简单,充 分利用已有的硬件和软件条件,设计出更简易的计算器。 本设计是以AT89C51单片机为核心的简易计算器设计,输入采用4*4矩阵键盘,可以进 行加、减、乘、除带符号数字运算(八位整数),并在液晶显示屏LCD1602上静态显示操 作的过程及结果。软件用C语言编程、Keil uVision2和pretues仿真。 关键词:单片机计算器;液晶显示屏;矩阵键盘 Abstract In recent years, the microcontroller as the core technology is developing very fast, now it is widely used in various fields related with our life, such as electronics, communications, science and technology, industry and so on, and the update speed of electronic product is more rapid. The calculator is the one of common electronic products in our daily life, how to make the computer technology more mature and simple and to make full use of the existing hardware and software conditions to design a simple calculator. The design is based on the AT89C51single-chip microcomputer as the core of a simple calculator design, using 4*4matrix keyboard input, you can add, subtract, multiplication, except the symbol digit operation ( eight integers ), and static display operation process and result in the LCD1602 screen LCD. The Software programming use C language, Keil uVision2 and pretues simulation. Key words: single chip microcomputer; calculator; LCD screen; keyboard matrix 目录 引言 1 第一章 设计原理及要求 2 1.1 设计方案的确定 2 1.2 系统的设计方案 2 1.3 系统的设计要求 2 第二章 硬件模块设计 4 2.1 单片机AT89C51 4 2.1.1 AT89C51芯片的特点 5 2.1.2 管脚说明 5 2.1.3 振荡器特性 7 2.1.4 芯片擦除 7 2.2 键盘控制模块 7 2.2.1 矩阵键盘的工作原理 8 2.2.2 键盘电路主要器件介绍 8 2.3 LCD显示模块 10 2.3.1 显示电路 11 2.3.2 LCD1602主要技术参数 11 2.3.3 引脚功能说明 11 2.4 运算模块(单片机控制) 12 第三章 软件设计 14 3.1 功能介绍 14 3.2系统流程 14 3.3 程序 16 第四章 系统调试 17 4.1软件介绍 17 4.1.1 Keil uVision2仿真软件简介 17 4.1.2 protues简介 17 4.2 软件调试 18 4.2.1 软件分析及常见故障 19 4.2.2 仿真结果演示 20 4.3 硬件调试 21 结束语 23 参考文献 24 附录 25 致谢 36 引言 计算工具最早诞生于中国,中国古代最早采用的一种计算工具叫筹策,也被叫做算筹 。这种算筹多用竹子制成,也有用木头,兽骨充当材料的,约二百七十枚一束,放在布 袋里可随身携带。另外直到今天仍在使用的珠算盘,是中国古代计算工具领域中的另一 项发明,明代时的珠算盘已经与现代的珠算盘几乎相同。 17世纪初,西方国家的计算工具有了较大的发展,英国数学家纳皮尔发明的"纳皮尔 算筹",英国牧师奥却德发明了圆柱型对数计算尺,这种计算尺不仅能做加、
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薄情书生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值