基于51单片机的简易计算器课程设计(完整代码+完整设计报告)

本文详细介绍了作者使用AT89C52单片机进行的计算器项目,包括整数、小数、负数四则运算、错误检测、按键输入及清除功能。代码中包含了完整的功能实现和按键扫描逻辑,适合初学者参考。
摘要由CSDN通过智能技术生成

一、简介

这学期进行了单片机的课程学习,由于有课程设计要做,但本人C语言编程基础很差,借鉴几篇博客的代码和原理,拼凑成了这份报告,参考文献会引用于末尾,虽然水平不高,但报告较完整,还是分享给大家,希望有所帮助。代码冗余,希望理解,功能也有一些缺陷,我写在了报告总结上。

使用的芯片是AT89C52,可以进行连续的四则运算,使结果在LCD屏显示,主要实现以下六个功能:

(1) 可以进行连续的整数、小数、负数之间的四则运算;

(2) 除数为0时报错;

(3) 可以删除输错的数字或符号;

(4) 按下按键时伴随提示音,且有控制开关;

(5) 可以清零操作;

(6) 小数保留两位且要求四舍五入。

按键设计如下:

二、代码

这里我直接放完整代码,在开头进行了引脚定义。报告文件中和代码后面都做了解释,这里就不多说了。

#include "reg52.h" 
typedef unsigned int u16;
typedef unsigned char u8; 

#define KEY_PORT P1 //矩阵按键


sbit rw=P2^5;            
sbit rs=P2^6;            
sbit e=P2^7; 

sbit KEY1=P3^1;
sbit KEY2=P3^0;
sbit KEY3=P3^2;
sbit KEY4=P3^3;


code u8 ERROR[]="     ERROR!";//除数为0时,显示 
code u8 wel[]="    Welcome!";
u8 negative1,negative2,fuhao,jjcc,jjcc,key_value,decimal1,decimal2,j1,x,symbol0,beep=200,be=0,be2,key=1;
//第一负号标志、第二负号标志、有无运算符标志、运算符标志、按键值、第一小数标志、第二小数标志、错误显示循环变量、欢迎显示循环变量、连续计算标志、蜂鸣器循环次数、蜂鸣器开关标志、独立按键松开标志
float number1,number2,result,resulted; //第一组合数、第二组合数、结果、连续计算上次结果
u16 dec1,dec2,mul1,mul2;//第一小数、第二小数、第一小数位数还原标记、第二小数位数还原标记
long num1,num2;//第一整数、第二整数

void write_comm(u16 c);//写命令
void write_data(u16 dat);//写数据
void lcdinit(void);//lcd、变量初始化
void resultShow(float value);//结果显示
void getFuhao(key_value);//获取运算符
void getNum(key_value);//获取数字
void calculate(void);//计算
void delect(void);//删除
void numShow(u16 zhengshu);//整数显示
void getNeg(key_value);//负号、减号判断
void buzzer(beep);//蜂鸣器


//延时
void delay(u16 ten_us)
{
	while(ten_us--);
}

void buzzer(beep)
{	
	while(beep--)//循环 200 次
	{
		rw=!rw;//产生一定频率的脉冲信号
		delay(100);
	}
	rw=0;//关闭蜂鸣器
}

//按键
void key_scan(void)
{	
	key_value=0;
	KEY_PORT=0xf7;//给第一列赋值 0,其余全为 1
	if(KEY_PORT!=0xf7)//判断第一列按键是否按下
	{
		delay(1000);//消抖
		switch(KEY_PORT)//保存第一列按键按下后的键值
		{
			case 0x77: key_value=1;buzzer(beep);getNum(key_value);break;
			case 0xb7: key_value=4;buzzer(beep);getNum(key_value);break;
			case 0xd7: key_value=7;buzzer(beep);getNum(key_value);break;
			case 0xe7: 
				buzzer(beep);
				key_value=10;//"."
				if(fuhao==0) 
				{
					decimal1 = 1;
					write_data('.');
				}
				else if(fuhao==1) 
				{
					decimal2 = 1;
					write_data('.');
				}
				break;
		}	
	}
	while(KEY_PORT!=0xf7);//等待按键松开
	KEY_PORT=0xfb;//给第二列赋值 0,其余全为 1

	if(KEY_PORT!=0xfb)//判断第二列按键是否按下
	{
		delay(1000);//消抖
		switch(KEY_PORT)//保存第二列按键按下后的键值
		{
			case 0x7b: key_value=2;buzzer(beep);getNum(key_value);break;
			case 0xbb: key_value=5;buzzer(beep);getNum(key_value);break;
			case 0xdb: key_value=8;buzzer(beep);getNum(key_value);break;
			case 0xeb: key_value=0;buzzer(beep);getNum(key_value);break;
		}
	}
	while(KEY_PORT!=0xfb);//等待按键松开
	KEY_PORT=0xfd;//给第三列赋值 0,其余全为 1
	if(KEY_PORT!=0xfd)//判断第三列按键是否按下
	{
		delay(1000);//消抖
		switch(KEY_PORT)//保存第三列按键按下后的键值
		{
			case 0x7d: key_value=3;buzzer(beep);getNum(key_value);break;
			case 0xbd: key_value=6;buzzer(beep);getNum(key_value);break;
			case 0xdd: key_value=9;buzzer(beep);getNum(key_value);break;
			case 0xed: 
				buzzer(beep);
				key_value=11;//"="
				write_data('=');
				calculate();
				if(symbol0==0)//显示错误时影响光标
				{
					resulted = result;
					write_comm(0xC0);
					resultShow(result);
				}
				else
					symbol0=0;
				break;
		}	
	}
	while(KEY_PORT!=0xfd);//等待按键松开
	KEY_PORT=0xfe;//给第四列赋值 0,其余全为 1
	if(KEY_PORT!=0xfe)//判断第四列按键是否按下
	{
		delay(1000);//消抖
		switch(KEY_PORT)//保存第四列按键按下后的键值
		{
			case 0x7e: key_value=12;buzzer(beep);getFuhao(key_value);break;//"+"
			case 0xbe: key_value=13;buzzer(beep);getNeg(key_value);break;//"-"
			case 0xde: key_value=14;buzzer(beep);getFuhao(key_value);break;//"*"
			case 0xee: key_value=15;buzzer(beep);getFuhao(key_value);break;//"/"
		}
	}
	while(KEY_PORT!=0xfe);//等待按键松开
	if(key==1 && (KEY1==0||KEY2==0||KEY3==0||KEY4==0))//任意按键按下
	{	
		delay(1000);//消抖
		key=0;
		if(KEY1==0)
		{	buzzer(beep);
			write_comm(0x01);
			lcdinit();//AC
			resulted=0;
		}
		else if(KEY2==0)
		{	buzzer(beep);
			delect();
		}
		else if(KEY3==0)
		{	buzzer(beep);
			write_comm(0x01);
			lcdinit();
			resultShow(resulted);//连续计算
		}
		else if(KEY4==0)
		{
			buzzer(beep);
			be=be+1;
			be2=be%2;
			if(be2==0)
			{
				beep=200;
			}
			else if(be2==1)
			{
				beep=0;
			}					
			
		}
	}
	else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1) //无按键按下
	{
		key=1;
	}
}

void getNeg(key_value)
{	
	if(key_value == 13) 
	{
		if(resulted==0)
		{	
			if(fuhao == 0)//第一个负号
			{
				if(num1 == 0 && dec1 == 0)
				{
					write_data('-');
					negative1 = 1;
				}
				else
				{
					write_data('-');
					jjcc=1;
					fuhao=1;
				}	
			}
			else if(fuhao == 1)//第二个负号
			{
				if(num2 == 0 && dec2 == 0)
				{
					negative2 = 1;
					write_data('-');
				}
			}
		}
		else if(resulted!=0)
		{
			if(fuhao == 0)
			{
				write_data('-');
				jjcc=1;
				fuhao=1;
			}
			else if(fuhao == 1)
			{
				if(num2 == 0 && dec2 == 0)
				{
				negative2 = 1;
				write_data('-');
				}
			}
		}
	}
}




//计算
void calculate()
{	
		if(resulted!=0)
		{	
			number1 = resulted;
			number2 = (float)num2 + (float)dec2/(float)mul2;
		}
		else
		{	
			number1 = (float)num1+ (float)dec1/(float)mul1;
			number2 = (float)num2 + (float)dec2/(float)mul2;//类型转换
		}
		if(negative1==1) number1 = -number1;//给负号
		if(negative2==1) number2 = -number2;
		switch(jjcc)
		{
			case 0:	result = number1 + number2;break;
			case 1: result = number1 - number2;break;
			case 2: result = number1 * number2;break;
			case 3:
				if(number2==0) 
				{	symbol0=1;
					write_comm(0x01);
					for(j1=0;j1<11;j1++)
					{
						write_data(ERROR[j1]);//显示语句:ERROR!	
					}
					delay(50000);
					lcdinit();
				}
				else
				{
					result = number1 / number2;
				}break;
		}
}
	


//获取整数、小数
void getNum(key_value)
{
	if(resulted!=0)//上次运算的结果
	{
		if(fuhao==1)
		{	
			if(decimal2==0)//输入不是小数
			{
				write_data(key_value + 0x30);
				num2 = key_value + num2*10;//第二个整数
			}
			else if(decimal2==1)
			{
				write_data(key_value + 0x30);
				dec2 = key_value + dec2*10;//第二个小数
				mul2=10*mul2;
			}
		}
	}
	else
	{
		if(fuhao==0 )
		{	
			if(decimal1==0)//输入不是小数
			{
				write_data(key_value + 0x30);
				num1 = key_value + num1*10;//第一个整数
			}
			else if(decimal1==1)
			{
				write_data(key_value + 0x30);
				dec1 = key_value + dec1*10;//第一个小数
				mul1=10*mul1;
			}
    }
		else if(fuhao==1)
		{	
			if(decimal2==0)//输入不是小数
			{
				write_data(key_value + 0x30);
				num2 = key_value + num2*10;//第二个整数
			}
			else if(decimal2==1)
			{
				write_data(key_value + 0x30);
				dec2 = key_value + dec2*10;//第二个小数
				mul2=10*mul2;
			}
		}
	}
}

//获取加减乘除符号值
void getFuhao(key_value)
{
	if(fuhao==0 && ( key_value==12||key_value==13||key_value==14||key_value==15))
	{
		if(key_value==12) 
		{
			jjcc = 0;
			write_data('+');
			fuhao = 1;
		}
		else if(key_value==14)
		{
			jjcc = 2;
			write_data('*');
			fuhao = 1;
		}
		else if(key_value==15)
		{
			jjcc = 3;
			write_data('/');
			fuhao = 1;
		}
		
	}
}	

//删除
void delect()
{
	write_comm(0x04);
	write_data(0x20);
	write_comm(0x06);
	write_data(0x20);
	write_comm(0x04);
	write_data(0x20);
	write_comm(0x06);
	if(fuhao==1)
	{	
		if(num2==0 && dec2==0)//删符号
		{	
			if(negative2==1)
			{
				negative2=0;//删第二个负号
			}
			else
			{
				fuhao=0;//删运算符号
				jjcc=4;
			}
		}
		else if(decimal2 == 0)//删第二个整数
			num2=num2/10;
		else if(decimal2 == 1)
		{
			if(dec2 == 0) decimal2 = 0;//删小数点
			else 
			{
				dec2=dec2/10;//删第二个小数
				mul2=mul2/10;
			}
		}
	}
	else if(fuhao==0)
	{	
		if(negative1==1 && num1==0 && dec1==0)//第一个负号
		{
			negative1=0;
		}
		else if(decimal1 == 0)
			num1=num1/10;//第一个整数
		else if(decimal1 == 1)//第一个小数
		{
			if(dec1 == 0) decimal1 = 0;//第一个小数符号
			else 
			{
				dec1=dec1/10;
				mul1=mul1/10;//第一个小数数字
			}
		}
	}
}

void write_comm(u16 c)
{
 delay(1000);
 rs=0;
 rw=0;
 e=0;
 P0=c;
 e=1;
 delay(1000);
 e=0;
}//写命令



void write_data(u16 dat) //设置LCD写数据
{
 delay(1000);
 rs=1;
 rw=0;
 e=0;
 P0=dat;
 e=1;
 delay(1000);
 e=0;
 rs=0;
}

void lcdinit()   //初始化LCD
{
	delay(1500);
  write_comm(0x38);//写指令38H
  delay(500);
  write_comm(0x38);//显示模式设置
  delay(500);
  write_comm(0x38);
  delay(500);
  write_comm(0x38);//功能设定指令
  write_comm(0x08);
  write_comm(0x01);//清屏
  write_comm(0x06);//显示光标移动设置写入数据后移
  write_comm(0x0c); //显示开关控制指令
  write_comm(0x0f); //显示光标并闪烁
	negative1=0,negative2=0;
	fuhao=0,jjcc=4;
	mul1=1,mul2=1,key_value=0,j1=0;
	num1=0,num2=0,dec1=0,dec2=0,decimal1=0,decimal2=0;
	number1 = 0.0, number2 = 0.0, result = 0.0;
}



void resultShow(float value)//结果显示
{	
	long z_value = 0;
	long dec_value = 0;
	long z_value2=0;
	long value3=0;
	long z_value4=0;
	if(value<0)
	{ 
		write_data('-');
		value=-value;
	}
	if(value<=13000)//小数精度问题
	{	
		z_value = value * 10;//u16放大保留
		z_value2 = value;//u16截断
		z_value4 = value * 100;
		dec_value = z_value - z_value2*10;//要保留的小数
		value3=(z_value4 - z_value2*100)-dec_value*10;//四舍五入的小数
		if(value3>=5 && value3<=9)
		{
			dec_value = dec_value + 1;//获取小数
			if(dec_value==10)
			{
				value=value+1;
				dec_value=0;
			}
		}
		if(dec_value==0)//整数
		{	
			if(z_value2==0)
				write_data('0');
			else
				numShow(value);
		}
		else//有小数
		{	
			if(z_value2==0)
				write_data('0');
			else
				numShow(value);
			write_data('.');
//			if(dec_value<10)//一位小数补两个0
//			{
//				write_data('0');
				write_data('0');
//			}
//			else if(dec_value<100 && dec_value>=10)//两位小数补一个
//				write_data('0');
			numShow(dec_value);
		}
	}
	else
	{
		numShow(value);
	}
}

//数字显示
void numShow(long c)//加减乘
{	u8 cc[15];
	u16 nn=0;
	u16 ss=0;
	for(c;c>0;c=c/10)//按位存入数组,倒序存储,最左边是个位
	{ 
		cc[++ss]=c%10;//从个位开始存,然后存的位数加1并向右移位
		nn++;//结果位数加1
	}
  for(nn;nn>0;nn--)//循环显示结果
  {
    write_data(0x30+(cc[nn]));//从数组的右向左显示
  }  
} 

//主函数
void main ()
{
	
	lcdinit();
	
	for(x=0;x<12;x++)
	{
    write_data(wel[x]);//显示欢迎语句:Welcome 
		delay(3000); 
	}
	
	write_comm(0x01);

	
	while (1) 
	{
		key_scan();	
	}
}

三、实物演示

 

 

四、完整设计报告word文档

https://wwd.lanzoum.com/ieb421nk4xgd
密码:ae4n

五、参考博客

51单片机计算器(源程序+流程图+答辩报告+综合设计)-CSDN博客 

【优化】最强51单片机计算器(源程序+演示+串口通信)_基于串口的计算器-CSDN博客 

单片机实现简易计算器功能,附有解析与代码_简易计算器单片机-CSDN博客

 

  • 16
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 19
    评论
下面是一个基于51单片机简易计算器程序设计,实现加、减、乘、除四种基本运算: ```c #include <reg51.h> sbit Keys = P3^7; // 按键输入 sbit Led1 = P2^0; // 第一位数码管 sbit Led2 = P2^1; // 第二位数码管 sbit Led3 = P2^2; // 第三位数码管 sbit Led4 = P2^3; // 第四位数码管 sbit Beep = P2^7; // 蜂鸣器 unsigned char display[4]; // 数码管显示缓冲区 unsigned char num1 = 0; // 第一个操作数 unsigned char num2 = 0; // 第二个操作数 unsigned char operator = 0; // 运算符 unsigned char result = 0; // 运算结果 // 延时函数 void delay(unsigned int t) { unsigned int i, j; for (i = 0; i < t; i++) { for (j = 0; j < 125; j++); } } // 数码管显示函数 void ShowDigit() { Led1 = 1; Led2 = Led3 = Led4 = 0; P0 = display[0]; delay(2); Led2 = 1; Led1 = Led3 = Led4 = 0; P0 = display[1]; delay(2); Led3 = 1; Led1 = Led2 = Led4 = 0; P0 = display[2]; delay(2); Led4 = 1; Led1 = Led2 = Led3 = 0; P0 = display[3]; delay(2); } // 从按键中读取数字 unsigned char GetNumber() { unsigned char n = 0; while (Keys == 0); // 等待按键释放 while (Keys == 1); // 等待按键按下 Beep = 1; delay(10); Beep = 0; // 发出滴声 switch (P3) { case 0x7E: n = 0; break; case 0x30: n = 1; break; case 0x6D: n = 2; break; case 0x79: n = 3; break; case 0x33: n = 4; break; case 0x5B: n = 5; break; case 0x5F: n = 6; break; case 0x70: n = 7; break; case 0x7F: n = 8; break; case 0x7B: n = 9; break; } Beep = 1; delay(10); Beep = 0; // 发出滴声 return n; } // 从按键中读取运算符 unsigned char GetOperator() { unsigned char op = 0; while (Keys == 0); // 等待按键释放 while (Keys == 1); // 等待按键按下 Beep = 1; delay(10); Beep = 0; // 发出滴声 switch (P3) { case 0x77: op = '+'; break; case 0x7C: op = '-'; break; case 0x5E: op = '*'; break; case 0x4F: op = '/'; break; } Beep = 1; delay(10); Beep = 0; // 发出滴声 return op; } // 从缓冲区中读取一个数 unsigned char GetNum(unsigned char *buf) { unsigned char num = 0; while (*buf != 0) { num = num * 10 + (*buf - '0'); buf++; } return num; } // 将一个数转换为字符串 void PutNum(unsigned char num, unsigned char *buf) { unsigned char i = 0; if (num == 0) { *buf++ = '0'; *buf = 0; return; } while (num > 0) { buf[i++] = num % 10 + '0'; num /= 10; } buf[i] = 0; for (i = 0; i < strlen(buf) / 2; i++) { char c = buf[i]; buf[i] = buf[strlen(buf) - i - 1]; buf[strlen(buf) - i - 1] = c; } } // 执行加法运算 void Add() { result = num1 + num2; } // 执行减法运算 void Subtract() { result = num1 - num2; } // 执行乘法运算 void Multiply() { result = num1 * num2; } // 执行除法运算 void Divide() { if (num2 == 0) result = 0; else result = num1 / num2; } // 主函数 void main() { unsigned char buf[10]; while (1) { // 读取第一个操作数 memset(display, 0, sizeof(display)); memset(buf, 0, sizeof(buf)); num1 = GetNumber(); PutNum(num1, buf); strcpy(display, buf); ShowDigit(); // 读取运算符 operator = GetOperator(); switch (operator) { case '+': Add(); break; case '-': Subtract(); break; case '*': Multiply(); break; case '/': Divide(); break; } // 读取第二个操作数 memset(display, 0, sizeof(display)); memset(buf, 0, sizeof(buf)); num2 = GetNumber(); PutNum(num2, buf); strcat(display, buf); ShowDigit(); // 显示结果 memset(display, 0, sizeof(display)); memset(buf, 0, sizeof(buf)); PutNum(result, buf); strcat(display, buf); ShowDigit(); } } ``` 该程序使用 P2 端口控制数码管显示,P3.7 端口读取按键输入,P2.7 端口控制蜂鸣器发声。在按键输入中,使用了滴声提示,增强了用户体验。在操作数和运算符输入后,使用相应的函数执行运算,并将结果显示在数码管上。注意,该程序中没有进行错误处理,例如除数为零等情况,需要根据实际需求进行改进。
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值