51单片机简易计算器的实现(带MR+、MR-、存储数据等附加功能)

 项目最后附有本项目程序源码!!

如果对你有帮助不妨点个赞!

本项目使用:51单片机、矩阵键盘、LCD1602;

使用数码管进行显示的思路相差不大。

电路仿真图:

代码: 

        为方便大家观看,小编分功能展示,相信具有一定编程基础,再搭配上注释看明白小编的代码应该不成问题,能力有限,如有不对,欢迎在评论区留言!!

        在文章最后附有代码链接,如有需要自行下载。

主程序代码:

头文件代码:

#ifndef _MAIN_H_
#define _MAIN_H_


/**********************************
包含头文件
**********************************/
#include<reg52.h>
#include<intrins.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdio.h>


/**********************************
重定义关键词
**********************************/
#define uchar unsigned char 
#define uint unsigned int 


/**********************************
函数声明
**********************************/
void Delay_function(uint x);						//延时x ms函数


#endif

源文件代码:

/**********************************
包含头文件
**********************************/
#include "main.h"
#include "lcd1602.h"
#include "key.h"


/**********************************
变量定义
**********************************/
uchar key_bianma = 0;													//按键编码标志位变量
uchar key_num = 0;														//按键扫描标志位变量
uint time_num = 0;														//10ms计时变量
uchar password_input[7];											//输入数组
uchar password_reset[7];											//重置数组
uchar flag_num_index1= 0;											//输入第一个数的数组下标
uchar flag_num_index2= 0;											//输入第二个数的数组下标
uchar flag_num_1_2= 0;												//第一、二个数据标志位
uchar flag_sign = 0;													//符号标志位
double num_a = 0.0;														//数据a
double num_b = 0.0;														//数据b
double num_result = 0.0;											//得出的结果
char resault_buf[10];													//得出的结果数组
uchar flag_sign_offset = 0;										//符号偏移量
uchar flag_result = 0;												//结果标志位
uchar flag_clean = 1;													//清除标志位													
uchar flag_lock_time = 0;											//锁定时间
double mr= 0.0;
uchar mi= 0;
double m1= 0.0;
double m2= 0.0;
double m3= 0.0;

/**********************************
函数声明
**********************************/
void Delay_function(uint x);									//延时函数
void Key_function(void);											//按键函数
void Display_function(void);									//显示函数
void Ensure_function(void);										//确定函数
void Result(void);														//求取结果函数

/****
*******	主函数 
*****/
void main()
{
	Lcd1602_Init();		 													//LCD1602初始化
	Delay_function(50);													//延时50ms
	lcd1602_clean();														//清屏
	Delay_function(50);													//延时50ms


	while(1)
	{
		Key_function();														//按键函数
		Display_function();												//显示函数
		
		Delay_function(10);												//延时10ms
		time_num++;																//计时变量+1
		if(time_num == 5000)
		{
			time_num = 0;
		}
	}
}

/****
*******	延时函数
*****/
void Delay_function(uint x)
{
	uint m,n;
	for(m=x;m>0;m--)
	for(n=110;n>0;n--);
}

/****
*******按键函数
*****/
void Key_function(void)
{
	key_bianma = matrix_keyboard_scan();											//读按键的位置码
	if(key_bianma != 0)																				//当有按键按下时
	{
		key_num = matrix_keyboard_coding(key_bianma);						//根据按键的位置将其编码,编码值赋值给NUM
		{
			if(flag_result == 1 && flag_clean == 1)								//第一次得出结果,清除输入的数据
			{
				flag_clean = 0;
				lcd1602_display_str(1,4,"                ");
			}
			if(flag_result == 2)																	//得出的结果为error时,只能按复位键
			{
				
				if(key_num == 'L')  																//复位
				{
					flag_num_1_2 = 0;
					flag_clean = 1;
					flag_result = 0;
					flag_num_index1 = 0;
					flag_num_index2 = 0;
					flag_sign_offset = 0;
					memset(password_input,'\r',7);
					memset(password_reset,'\r',7);
					lcd1602_clean();
					Display_function();			
				}
			}
			else
			{
				switch(key_num)
				{  
					case ('A'):   																	//M1
						flag_sign = 1;
						lcd1602_display_str(1,4,"M1");
						flag_sign_offset = 2;
					break;
						
					case ('B'):   																	//M2
						flag_sign = 2;
						lcd1602_display_str(1,4,"M2");
						flag_sign_offset = 2;
					break;
					
					case ('C'):   																	//M3
						flag_sign = 3;
						lcd1602_display_str(1,4,"M3");
						flag_sign_offset = 2;
					break;
					
					case ('D'):   																	//MR+
						flag_sign = 4;
						lcd1602_display_str(1,4,"MR+");
						flag_sign_offset = 3;
					break;
					
					case ('E'):   																	//MR-
						flag_sign = 5;
						lcd1602_display_str(1,4,"MR-");
						flag_sign_offset = 3;
					break;

					case ('F'):   																	//÷
						flag_sign = 6;
						flag_num_1_2 = 1;
						lcd1602_display_char(1,4+flag_num_index1,'/');
					break;
			
					case ('G'):   																	//x
						flag_sign = 7;
						flag_num_1_2 = 1;
						lcd1602_display_char(1,4+flag_num_index1,'*');
					break;
					
					case ('H'):   																	//-
						flag_sign = 8;
						flag_num_1_2 = 1;
						lcd1602_display_char(1,4+flag_num_index1,'-');
					break;
							
					case ('L'):   																	//+
						flag_sign = 9;
						flag_num_1_2 = 1;
						lcd1602_display_char(1,4+flag_num_index1,'+');
					break;

					case ('I'):   																	//复位
						flag_num_1_2 = 0;
						flag_clean = 1;
						flag_result = 0;
						flag_num_index1 = 0;
						flag_num_index2 = 0;
						flag_sign_offset = 0;
						memset(password_input,'\r',7);
						memset(password_reset,'\r',7);
						lcd1602_clean();
						Display_function();					
					break;
					
					case ('J'):   																	//.
						if(flag_num_1_2 == 0)
						{
							if(flag_num_index1 < 7)
							{
								password_input[flag_num_index1] = '.';
								lcd1602_display_char(1,4+flag_num_index1+flag_sign_offset,'.');
								flag_num_index1++;
							}
						}
						else
						{
							if(flag_num_index2 < 7)
							{
								password_reset[flag_num_index2] = '.';
								lcd1602_display_char(1,4+flag_num_index1+1+flag_num_index2+flag_sign_offset,'.');
								flag_num_index2++;
							}
						}
					break;
					
					case ('K'):   																	//=
						Result();
					break;
				
					default:																				//0-9数字键
						if(flag_num_1_2 == 0)													//用于输入的第一个数据
						{
							if(flag_num_index1 < 7)
							{
								password_input[flag_num_index1] = key_num+'0';
								lcd1602_display_char(1,4+flag_num_index1+flag_sign_offset,key_num+'0');
								flag_num_index1++;
							}
						}
						else																					//用于输入的第二个数据
						{
							if(flag_num_index2 < 7)
							{
								password_reset[flag_num_index2] = key_num+'0';
								lcd1602_display_char(1,4+flag_num_index1+1+flag_num_index2+flag_sign_offset,key_num+'0');
								flag_num_index2++;
							}
						}
						
					break;
				}
			}
		}
	}
}

/****
*******显示函数
*****/
void Display_function(void)
{
	lcd1602_display_str(1,0,"For:");
	lcd1602_display_str(2,0,"Res:");
}
	
/****
*******求取结果函数
*****/
void Result(void)
{
	if(flag_result == 0)										//第一次输入的公式
	{
		num_a = atof(password_input);					//解析数据a和b
		num_b = atof(password_reset);
	}
	else																		//未按复位键,第一次的结果当成第一个数
	{
		num_a = num_result;
		num_b = atof(password_reset);
	}

	switch(flag_sign)
	{
		 case (1):   															//M1
			num_result=m1;					  
		break;
			
		case (2):   															//M2
			num_result=m2;						
		break;

		case (3):   															 //M3 
			 num_result=m3;
			 	break;

		 case (4):
		    mr =num_a;   													//MR+
			num_result = num_a + num_b;
		break;
		 
		case (5):  
		    mr =num_a; 													//MR-
			num_result = num_a - num_b;
		break;

		case (6):   													//÷
			if(flag_num_index2 == 1 && (password_reset[0] == '0' || password_reset[0] == '.'))		//除数不能为0或.
			{
				lcd1602_display_str(2,4,"                ");
				lcd1602_display_str(2,4,"Error           ");
				return ;
			}
			else
			{
				num_result = num_a / num_b;
			}
		break;
		
		case (7):   													//x
			num_result = (num_a * num_b);
		break;
		
		case (8):   													//-
			num_result = num_a - num_b;
		break;
		
		case (9):   													//+
			num_result = num_a + num_b;
		break;
	}
	 mr=num_result;
	 if(mi==3)
	 {
	 mi=0;
	 }
	 else 
	 {
	 switch(mi)					
	{
		case 0 :m1=num_result;break;
		case 1 :m2=num_result;break;
		case 2 :m3=num_result;break; 
	}
    mi++;
	} 
	sprintf(resault_buf,"%.2f",num_result);													//将结果解析到数组中
	if(num_result > 9999999 || num_result < -9999999)								//结果超过-9999999~9999999,显示error
	{
		lcd1602_display_str(2,4,"Error        ");
		flag_result = 2;
	}
	else																														//未超过,显示结果
	{
		lcd1602_display_str(2,4,"                        ");
		lcd1602_display_str(2,4,resault_buf);
		flag_result = 1;
		flag_clean = 1;
		flag_num_1_2 = 1;
		flag_num_index1 = 0;
		flag_num_index2 = 0;
		flag_sign_offset = 0;
		memset(password_input,'\r',7);
		memset(password_reset,'\r',7);
	}
}

矩阵键盘功能区代码:

头文件代码:

#ifndef _KEY_H_
#define _KEY_H_


/**********************************
包含头文件
**********************************/
#include "main.h"


/**********************************
PIN口定义
**********************************/
#define MATRIX_KEYBOARD_DATA P1     		//矩阵键盘引脚
#define MATRIX_KEYBOARD_DATA1 P3     		//矩阵键盘引脚


/**********************************
函数声明
**********************************/
uchar matrix_keyboard_coding(uchar m);	//矩阵键盘键值编码为数值函数
uchar matrix_keyboard_scan(void);				//矩阵键盘扫描函数


#endif

源文件代码: 

/**********************************
包含头文件
**********************************/
#include "key.h"


/**********************************
变量定义
**********************************/
extern uchar flag_beep;


/**********************************
函数定义
**********************************/
/****
*******矩阵键盘键值编码为数值函数
*******返回值:键值数值
*****/
uchar matrix_keyboard_coding(uchar m)
{
	uchar k;
	switch(m)
	{
		case (46): 	k='A';		break;			 		//K1按下
		case (238): k='B';		break;			 		//K2按下
		case (110): k='C';		break;			 		//K3按下
		case (102): k='D';		break;			 		//K4按下
		case (94): 	k='E';		break;			 		//K5按下
		case (233): k=7;			break;			 		//K7按下
		case (105): k=8;			break;			 		//K8按下
		case (97): 	k=9;			break;			 		//K9按下
		case (89): 	k='F';		break;			 		//K10按下
		case (223): k=4;			break;			 		//K12按下
		case (95): 	k=5;			break;			 		//K13按下
		case (87): 	k=6;			break;			 		//K14按下
		case (79): 	k='G';		break;			 		//K15按下
		case (203): k=1;			break;			 		//K17按下
		case (75): 	k=2;			break;			 		//K18按下
		case (67): 	k=3;			break;			 		//K19按下
		case (59): 	k='H';		break;			 		//K20按下
		case (227): k='I';		break;			 		//K21按下
		case (163): k='J';		break;			 		//K22按下
		case (35): 	k=0;			break;			 		//K23按下
		case (27): 	k='K';		break;			 		//K24按下
		case (19): 	k='L';		break;			 		//K25按下
	}
	return(k);
}

uchar matrix_keyboard_scan(void)
{
	uchar cord_h,cord_l;											//行列值中间变量
	MATRIX_KEYBOARD_DATA=0x1f;            		//列线输出全为0
	MATRIX_KEYBOARD_DATA1=0xf3;            		//列线输出全为0
	cord_h=MATRIX_KEYBOARD_DATA&0x1f;     		//读入行线值
	if(cord_h!=0x1f)    											//先检测有无按键按下
	{
		Delay_function(10);        							//去抖
		if((MATRIX_KEYBOARD_DATA&0x1f)!=0x1f)
		{
			cord_h=MATRIX_KEYBOARD_DATA&0x1f;  			//读入行线值
			MATRIX_KEYBOARD_DATA=cord_h|0xe0;  			//输出当前列线值
			MATRIX_KEYBOARD_DATA1=0x0c;  						//输出当前列线值
			cord_l=MATRIX_KEYBOARD_DATA&0xe0 | MATRIX_KEYBOARD_DATA1&0x0c;  		//读入列线值
			
			if(flag_beep == 1)
				BEEP = 0;
			while((MATRIX_KEYBOARD_DATA&0xe0)!=0xe0 || (MATRIX_KEYBOARD_DATA1&0x0c)!= 0x0c);		//等待松开并输出
			BEEP = 1;
			return(cord_h*5+cord_l*2);							//键盘最后组合码值
		}
  }

	return 0;     															//返回该值
}

LCD1602 显示代码:

头文件:

#ifndef _LCD1602_H_
#define _LCD1602_H_


/**********************************
包含头文件
**********************************/
#include "main.h"


/**********************************
PIN口定义
**********************************/
#define LCD1602_PORT P0      		 //数据总线P0.0-P0.7
sbit LCD1602_RS=P2^5;						 //数据/命令选择引脚P2.5
sbit LCD1602_RW=P2^6;						 //读/写选择P2.6
sbit LCD1602_E=P2^7;						 //使能信号引脚P2.7
sbit LCD1602_BUSY=P0^7;					 //检测状态引脚P0.7


/**********************************
函数声明
**********************************/
void lcd1602_display_char(uchar hang, uchar add, uchar dat);					//LCD1602显示字符函数
void lcd1602_display_str(uchar hang, uchar add, uchar *dat);					//LCD1602显示字符串函数
void lcd1602_clean();																									//LCD1602清屏函数
void Lcd1602_Init();																									//LCD1602初始化函数


#endif

源文件代码: 

/**********************************
包含头文件
**********************************/
#include "lcd1602.h"


/**********************************
函数定义
**********************************/
/****
*******1602检测忙函数 
*****/
void lcd1602_check_busy()
{  
	P0=0xff;
	do
	{
		LCD1602_RS=0;
		LCD1602_RW=1;
		LCD1602_E=0;
		LCD1602_E=1;
	} while(LCD1602_BUSY==1);
	LCD1602_E=0;
}

/****
*******1602写数据忙函数 
*****/
void lcd1602_write_date(uchar date)
{
	lcd1602_check_busy();
	LCD1602_E=0;
	LCD1602_PORT=date;
	LCD1602_RS=1;
	LCD1602_RW=0;
	LCD1602_E=1;
	LCD1602_E=0;
}

/****
*******1602写命令函数 
*****/
void lcd1602_write_com(uchar com)
{
	lcd1602_check_busy();
	LCD1602_E=0;
	LCD1602_PORT=com;
	LCD1602_RS=0;
	LCD1602_RW=0;
	LCD1602_E=1;
	LCD1602_E=0;
}

/****
*******LCD1602显示字符函数 
*******参量定义:	hang:输入显示行数  1 第一行  2 第二行
*******           add:偏移量,0-15
*******           dat:所要显示的字符,输入格式 ' '
*****/
void lcd1602_display_char(uchar hang, uchar add, uchar dat)
{
	if(hang==1)   
		lcd1602_write_com(0x80+add);			//第一行
	else
		lcd1602_write_com(0x80+0x40+add);	//第二行

	lcd1602_write_date(dat);
}

/****
*******LCD1602显示字符串函数 
*******参量定义:	hang:输入显示行数  1 第一行  2 第二行
*******           add:偏移量,0-15
*******           dat:所要显示的字符串,输入格式 " "
*****/
void lcd1602_display_str(uchar hang, uchar add, uchar *dat)
{
	if(hang==1)   
		lcd1602_write_com(0x80+add);			//第一行
	else
		lcd1602_write_com(0x80+0x40+add);	//第二行

	while(*dat != '\0')
	{
		lcd1602_write_date(*dat++);
	
	}
}

/****
*******LCD1602清屏函数 
*****/
void lcd1602_clean()
{
	lcd1602_display_str(1,0,"                    ");
	lcd1602_display_str(2,0,"                    ");
}

/****
*******LCD1602初始化函数 
*****/
void Lcd1602_Init()
{
	lcd1602_write_com(0x38);
	lcd1602_write_com(0x0c);
	lcd1602_write_com(0x06);
	lcd1602_write_com(0x01);
}

中断程序代码: 

头文件:

#ifndef _UART_H_
#define _UART_H_


/**********************************
包含头文件
**********************************/
#include "main.h"


/**********************************
函数声明
**********************************/
void Uart_init();									//串口初始化函数


#endif

源文件:

/**********************************
包含头文件
**********************************/
#include "uart.h"


/**********************************
变量定义
**********************************/
uchar uart_num;


/**********************************
函数定义
**********************************/
/****
*******串口初始化函数
*****/
void Uart_init()
{
	TMOD=0x20;
	SCON=0x50;
	TH1=0xFD;
	TL1=0xFD;
	TR1=1;
	
	ES=1;
	EA=1;

//	UART_EN=1;  //485一直在写
}

/****
*******	串口中断服务程序函数 
*****/
void ser() interrupt 4
{
	static uchar string[1];		//接收一位数据,如果接收两位数据,则string[2]
	if(RI)
	{
		RI=0;
		string[0]=SBUF;

		switch(string[0])
		{
			case('1'):  uart_num = 1  ;break;

			case('2'):  uart_num = 2  ;break;

			default: break;
		}
	}	
}

         以上是小编整理的51单片机简易计算器的实现(带MR+、MR-、存储数据等附加功能)项目的仿真图与所有程序。亲测有效!

http://链接:https://pan.baidu.com/s/1IJNwaztdbampXONvLOmu5Q?pwd=sl3k 提取码:sl3k --来自百度网盘超级会员V4的分享

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值