基于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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/375.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】基础知识总结

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了数据结构复习用的&#xff0c;由于牛客刷题发现数据结构方面和王道数据结构的题目非常像&#xff0c;甚至很多都是王道中的&#xff0c;所以将基础知识进行了整理&#xff0c;后续会将牛客刷题的错题一…

大数据技术之Sqoop——SQL to Hadoop

一、简介sqoop &#xff08;sql to hadoop&#xff09;是一款开源的工具,主要用于在 Hadoop&#xff08;Hive&#xff09;与传统的数据库&#xff08;mysql、postgresql...&#xff09;间进行数据的传递&#xff0c;可以将一个关系型数据库&#xff08;例如 : MSQL,Oracle,Post…

Unity脚本练习

在C# 中 class 是创建类的标志&#xff0c;要创建类的话得现有class上面这个的逻辑是 类的访问权限&#xff0c; 关键字&#xff0c;类名以及类继承的父类在Unity中创建一个脚本或者添加一个组件&#xff0c;就相当于在Unity命名空间中创建了一个可以访问的类。这些类能够直接在…

2023秋招前端面试必会的面试题

浏览器存储 我们经常需要对业务中的一些数据进行存储&#xff0c;通常可以分为 短暂性存储 和 持久性储存。 短暂性的时候&#xff0c;我们只需要将数据存在内存中&#xff0c;只在运行时可用持久性存储&#xff0c;可以分为 浏览器端 与 服务器端 浏览器: cookie: 通常用于存储…

springboot健身房管理系统

springboot健身房管理系统 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xf…

Vue 3.0 单文件组件 【Vue3 从零开始】

#介绍 在很多 Vue 项目中&#xff0c;我们使用 app.component 来定义全局组件&#xff0c;紧接着用 app.mount(#app) 在每个页面内指定一个容器元素。 这种方式在很多中小规模的项目中运作的很好&#xff0c;在这些项目里 JavaScript 只被用来加强特定的视图。但当在更复杂的…

HTTP 3.0来了,UDP取代TCP成为基础协议,TCP究竟输在哪里?

TCP 是 Internet 上使用和部署最广泛的协议之一&#xff0c;多年来一直被视为网络基石&#xff0c;随着HTTP/3正式被标准化&#xff0c;QUIC协议成功“上位”&#xff0c;UDP“取代”TCP成为基础协议&#xff0c;TCP究竟“输”在哪里&#xff1f; HTTP/3 采用了谷歌多年探索的基…

< CSS小技巧:那些不常用,却很惊艳的CSS属性 >

文章目录&#x1f449; 前言&#x1f449; 一. background-clip: text - 限制背景显示&#xff08;裁剪&#xff09;&#x1f449; 二. user-select - 控制用户能否选中文本&#x1f449; 三. :focus-within 伪类&#x1f449; 四. gap - 网格 / 弹性布局间隔设置&#x1f449;…

【C++笔试强训】第三十一天

&#x1f387;C笔试强训 博客主页&#xff1a;一起去看日落吗分享博主的C刷题日常&#xff0c;大家一起学习博主的能力有限&#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话&#xff1a;夜色难免微凉&#xff0c;前方必有曙光 &#x1f31e;。 选择题 &#x…

Golang每日一练(leetDay0005)

目录 13. 罗马数字转整数 Roman to Integer ★ 14. 最长公共前缀 Longest Common Prefix ★ 15. 三数之和 3Sum ★★★ &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 13. 罗马数字转…

我从功能测试到python接口自动化测试涨到22k,谁知道我经历了什么......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 常见的接口&#xf…

C++高并发内存池的设计和实现

一、整体设计 1、需求分析 池化技术是计算机中的一种设计模式&#xff0c;内存池是常见的池化技术之一&#xff0c;它能够有效的提高内存的申请和释放效率以及内存碎片等问题&#xff0c;但是传统的内存池也存在一定的缺陷&#xff0c;高并发内存池相对于普通的内存池它有自己…

卷王都在偷偷准备金三银四了...

年终奖没发&#xff1b; 简历石沉大海&#xff1b; 发消息只读不回 打开某招聘&#xff0c;看了看岗位&#xff0c;这个厂还不错&#xff0c;可是要求好高&#xff0c;我啥都不会。 “哎&#xff0c;算了&#xff0c;我简历还没更新呢&#xff0c;我躺到6月份拿到年终奖再跑…

3-1 SpringCloud快速开发入门: Ribbon 是什么

接上一章节Eureka 服务注册中心自我保护机制&#xff0c;这里讲讲Ribbon 是什么 Ribbon 是什么 通常说的负载均衡是指将一个请求均匀地分摊到不同的节点单元上执行&#xff0c;负载均和分为硬件负载均衡和软件负载均衡&#xff1a; **硬件负载均衡&#xff1a;**比如 F5、深信…

记第一次面试的过程(C++)

说实话三月份上旬过得很充实&#xff0c;而且感觉蛮值&#xff0c;但还有不足的地方&#xff0c;今晚特地看完资料分析来复盘复盘。 时间还要回到3.2中午13.35&#xff08;别问我为什么那么准确&#xff0c;刚刚掏手机看的&#xff09;&#xff0c;我正在吃着饭看着王者荣耀的直…

STL sort 分析

前言 STL 中提供了很多算法&#xff0c;sort 是我们经常使用的&#xff0c;那它究竟是如何实现的呢&#xff1f; STL 的 sort 算法&#xff0c;数据量大时采用快速排序&#xff0c;分段递归。一旦分段的数据量小于某个门槛&#xff0c;为避免快速排序的递归调用带来过大的额外…

三天吃透计算机网络面试八股文

本文已经收录到Github仓库&#xff0c;该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点&#xff0c;欢迎star~ Github地址&#xff1a;https://github.com/…

Linux常用命令

个人简介&#xff1a;云计算网络运维专业人员&#xff0c;了解运维知识&#xff0c;掌握TCP/IP协议&#xff0c;每天分享网络运维知识与技能。座右铭&#xff1a;海不辞水&#xff0c;故能成其大&#xff1b;山不辞石&#xff0c;故能成其高。个人主页&#xff1a;小李会科技的…

C++STL 容器案例 员工分组 实现步骤与代码分析与展示 实现步骤的注意事项

STL容器 员工分组案例 文章目录STL容器 员工分组案例1 案例描述2 实现步骤3 案例代码与分析1 案例描述 公司今天招聘了10个员工&#xff08;ABCDEFGHIJ&#xff09;&#xff0c;10名员工进入公司之后&#xff0c;需要指派员工在哪个部门工作员工信息有: 姓名 工资组成&#xf…

CANoe中使用CAPL刷写流程详解(Trace图解)(CAN总线)

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…