⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 calculator.c

📁 基于51单片机的1602显示的计算器
💻 C
字号:
/********************************************************************************/
/*     Project: 计算器(Calculator)                 版本号:V1。0                */
/*  																			*/
/*																				*/
/*     Designed By: whoami                         CPU:AT89S51 or C51           */
/*																				*/
/*																				*/
/*     键盘布局如下:															*/
/*     K2(0)  K4(1)  K6(2)  K8(3)  K10(8)  K12(9)  K14(.)  K16(+)               */ 
/*     K3(4)  K5(5)  K7(6)  K9(7)  K11(-)  K13(*)  K15(/)  K17(=)               */
/*																				*/
/*	   功能描述:																*/
/*	       可以运算+,-,*,/等计算,运算的长度可以自行设定			    		*/
/*	   	   修改 Max_disp_buff 即可。											*/
/*																				*/
/*     http://www.mculover.net													*/
/*     http://www.mculover.net/bbs                    湘灵电子版权所有          */
/*																				*/
/*     转载请保留以上信息,谢谢合作	!											*/
/*																			    */
/********************************************************************************/

#include <reg51.h>
#include <math.h>
#include <stdlib.h>

#define key_yes   	0x18 //MENU_yes
#define key_left    0x14 //<-
#define key_right   0x12 //->
#define key_no     	0x11 //NO_back

#define key_1     	0x28 //1
#define key_2     	0x24 //2
#define key_3      	0x22 //3
#define key_add     0x21 //+

#define key_4      	0x48 //4
#define key_5       0x44 //5
#define key_6     	0x42 //6
#define key_sub    	0x41 //-

#define key_7      	0x88 //7
#define key_8      	0x84 //8
#define key_9    	0x82 //9
#define key_0    	0x81 //0

#define mul			key_left
#define div			key_right

#define uchar unsigned char
#define countend	40
#define countsub	5
#define L 10
bit keyflag = 0;

#define  Key_con        P3      //定义44键盘的连接口线

#define  Lcd_Data       P0          //定义数据端口
#define  TH0_TL0        (65536-5000)//设定中断的间隔时长

#define  Max_disp_buff  10      //定义最大的显示位数

sbit  RS = P2 ^ 0;       //定义和LCM的连接端口
sbit  RW = P2 ^ 1;
sbit  E = P2 ^ 2;
sbit  Busy = P0 ^ 7;

unsigned char Key_value, Time_delay;
static float left_value = 0;
static float right_value = 0;

//开机画面预定义
unsigned char code welcome[] = {"Welcome to :    "};
unsigned char code website[] = {"wumingshens Zone"};
unsigned char code designed[]= {"Designed By:    "};
unsigned char code whoami[]  = {"      wumingshen"};

//定义数组变量
unsigned char code keycodes[16]={'0','1','2','3','4','5','6','7','8','9','.','+','-','*','/','=',};
unsigned char number[Max_disp_buff + 1];//定义按键数字的缓冲大小

extern unsigned char keyscan(void);

//函数声明 
void Delay(unsigned char x);//延时处理
void Delay_1ms(unsigned char t);//延时子程序,延时 1MS*t S
unsigned char Read_key(void);//按键处理,返回按键的值
unsigned char Test_key(void);//按键检测函数
void Read_Busy(void);//读忙信号判断
void Write_Comm(unsigned char lcdcomm); //写指令函数
void Write_Data(unsigned char lcddata);//写数据函数
void Init_LCD_Cal(void);//初始化LCD
void Init_LCD_Logo(void);//初始化LCD
void Init_Timer0(void);//定时器0初始化
void Display (char *buf); //显示函数
void Display_Logo(unsigned char code *DData);//显示LOGO
void Digit_input_calcul(void);//字符输入
void Fun_calculator(unsigned int fuhao);//运算函数
void Calculator_output(float value);//输出计算结果函数
void Show_logo(void);//显示开机画面

/******************************************************************************/
void Delay(unsigned char x)//延时处理
{
	Time_delay = x;

	while(Time_delay != 0);
}

/******************************************************************************/
void Delay_1ms(unsigned char t)//延时子程序,延时 1MS*t S
{
	unsigned char a;
	while(--t != 0)
	{
		for(a = 0; a < 125; a++);
	}
}

/**************此函数具有长按加速功能******************/

unsigned char keyscan(void)
{
   	unsigned char i,code_l,code_h[4] = {0xfe,0xfd,0xfb,0xf7};
   	static unsigned char keycounter = 0;
   	Key_con = 0xF0;
   	if((Key_con & 0xF0)!= 0xF0)
   	{
      	Delay_1ms(20);
	 	if((Key_con & 0xf0)!= 0xF0)
	 	{ 
			for(i = 0; i<4; i++)
			{
			    Key_con = code_h[i];
		    	if((Key_con & 0xF0) != 0XF0)
		    	{
		       		code_l = (Key_con & 0xF0) | 0x0F;
			   		if(keyflag)//不是第一次按下则执行以下程序
			   		{
			   			keycounter++;//计数器加1
			   			if(keycounter == countend)
			   			{
			   				keycounter -= countsub;//到一百了再减去
							return ((~code_h[i])+(~code_l));
			   			}
						else    
						{return 0;}  //没有到100则返回0
					}
					else  //第一次按下则执行以下程序
		    		{
						keyflag = 1;  //置标志位
						return ((~code_h[i])+(~code_l));
					}
		    	}	 
		 	}
	  	}
   	}
   	else
	{
		keyflag = 0;keycounter = 0;return (0);
	}
}

/******************************************************************************/
unsigned char Read_key(void)//按键处理,返回按键的值
{
 	unsigned char  key;
	key = keyscan();
	switch(key)
	{
		case key_yes:	Key_value = keycodes[15]; 	break;	//=
 		case mul	:	Key_value = keycodes[13]; 	break;	//*
		case div    :	Key_value = keycodes[14]; 	break;	///
		case key_no :	Key_value = keycodes[10]; 	break;	//.

 	 	case key_1  :	Key_value = keycodes[1]; 	break;	//1
		case key_2  :	Key_value = keycodes[2]; 	break;	//2
		case key_3  :	Key_value = keycodes[3]; 	break;	//3
		case key_add:	Key_value = keycodes[11]; 	break;	//+

		case key_4  :	Key_value = keycodes[4]; 	break;	//4
		case key_5  :	Key_value = keycodes[5]; 	break;	//5
		case key_6  :	Key_value = keycodes[6]; 	break;	//6
		case key_sub:	Key_value = keycodes[12]; 	break;	//-

		case key_7  :	Key_value = keycodes[7]; 	break;	//7
		case key_8  :	Key_value = keycodes[8]; 	break;	//8
		case key_9  :	Key_value = keycodes[9]; 	break;	//9
		case key_0  :	Key_value = keycodes[0]; 	break; 	//0
		default:		Key_value = 0x00;			break;
	}
	//while(key != 0x00){;}
	return Key_value;
}

/******************************************************************************/
void Timer0_int(void) interrupt 1 using 1//定时0中断处理
{
	//	调整出入栈的时间,在精度不高的场合可不要!
	TR0 = 0;
    TL0 += (TH0_TL0 + 9) % 256;
    TH0 += (TH0_TL0 + 9) / 256 + (char)CY;
    TR0 = 1;

	if(Time_delay != 0)//延时函数用
	{
		Time_delay--; 
	}

	Read_key();//读取键盘的值
}

/******************************************************************************/
unsigned char Test_key(void)//按键检测函数
{
	unsigned char mykey;

	while((mykey = Key_value) == 0x00);//等待 

	return mykey;
}

/******************************************************************************/
void Read_Busy(void)//读忙信号判断
{
	do{
		Lcd_Data = 0xff;
		RS = 0;
		RW = 1;
		E = 0;
		Delay(2);//调用中断延时
		E = 1;
	  }while(Busy);
}

/******************************************************************************/ 
void Write_Comm(unsigned char lcdcomm) //写指令函数
{	
	Lcd_Data = lcdcomm;
	RS = 0;
	RW = 0;
	E = 0;
	Read_Busy();
	E = 1;
}

/******************************************************************************/
void Write_Data(unsigned char lcddata)//写数据函数
{	
	Lcd_Data = lcddata;
	RS = 1;
	RW = 0;
	E = 0;
	Read_Busy();
	E = 1;
}

/******************************************************************************/
void Init_LCD_Cal(void)//初始化LCD
{
	Delay_1ms(400);   //稍微延时,等待LCM进入工作状态
	Write_Comm(0x01);//清显示

    Write_Comm(0x38);    // 8位 2行.
    Write_Comm(0x0c);   // 
    Write_Comm(0x07);   // 显示模式,从左至右增加
    Write_Comm(0x80+0x10);    // 定义首地址.
}

/******************************************************************************/
void Init_LCD_Logo(void)//初始化LCD
{
	Delay_1ms(400);   //稍微延时,等待LCM进入工作状态
	Write_Comm(0x01);//清显示

	Write_Comm(0x38);//8位2行5*8
	Write_Comm(0x06);//文字不动,光标右移
	Write_Comm(0x0c);//显示开/关,光标开闪烁开
}

/******************************************************************************/
void Init_Timer0(void)//定时器0初始化
{
	TMOD=0x01;
	TH0=TH0_TL0 / 256;
	TL0=TH0_TL0 % 256;
	TR0=1;
	ET0=1;
	EA=1;
}

/******************************************************************************/
void Display(char *buf)//显示函数
{ 
	unsigned char i;
   	
	Write_Comm(0x01);//clearscreen,清屏命令
	Write_Comm(0x80+0x10);

   	for (i=0 ; buf[i] != 0; i++)
		Write_Data(buf[i]);    
}

/******************************************************************************/
void Display_Logo(unsigned char code *DData)//显示LOGO
{
	unsigned char  j;
  
	for(j=0;j<16;j++)
    {
    	Write_Data(DData[j]); //显示单个字符
		Delay(30);
	}
}

/*******************************************************************************/
void Digit_input_calcul(void)//字符输入
{
	static unsigned char pos;
	float tmp;

   	unsigned int last_op = 0;

	Write_Data('0');	//上电显示" 0 "
	pos = 0;//位置为0

	while(1)
	{
		Key_value = Test_key();//判断是数字还是运算符号,具有等待功能

		if((Key_value == '.') || ((Key_value >= '0') && (Key_value <= '9')))//如果是数字或小数点
		{
			if (pos != Max_disp_buff )  //最大计算位
          	{ 
				number[pos++] = Key_value;
	          	number[pos] = 0;
            	Display(number);
          	}
		}
		else //如果输入的是运算符号(+,-,*,/,=)
		{

			tmp = atof(number);//atof函数就是把字符转换成双精度的值

			if((Key_value == '+') || (Key_value == '-') || (Key_value == '*') || (Key_value == '/'))
			{
				left_value = tmp;
				last_op = Key_value;
			}
			else if (Key_value == '=')
			{
				right_value = tmp;

			    Fun_calculator(last_op);//计算
			}
			
			pos = 0;//从新归位,输入右值
        }//else
	}//for
}

/**********************************************************************************/
void Fun_calculator(unsigned int fuhao)//运算函数
{
	bit result = 1;

	switch(fuhao)
	{
		case '+': left_value += right_value;result = 1;break;
		case '-': left_value -= right_value;result = 1;break;
		case '*': left_value *= right_value;result = 1;break;
		case '/': 
			if(right_value != 0)
			{
				left_value /= right_value;
				result = 1;
			}
			else
				result = 0;//出错
			break;
		default : break;
	}

	if(result == 1)
		Calculator_output(left_value);
	else 
		Display("*ERROR*");
}

/******************************************************************************/
void Calculator_output(float value)//输出计算结果函数
{
	unsigned char buff[Max_disp_buff + 1];//定义显示缓冲
	unsigned char p1=0, p=0;
	float divisor = 100000000;//除数
	float digit = 0;

	if(value >= 0)
		buff[p++] = ' ';
	else
	{	
		buff[p++] = '-';
		value = -value;
	}

	if(value >= divisor )
		buff[p++]='E';
	else
		while((p < Max_disp_buff ) && (divisor > 1 || value >= 0.00000001))
		{
			divisor /= 10;
			digit = floor(value/divisor);//小于指定数的最小整数
			if (divisor < 1 && divisor > 0.01)
            buff[p++] = '.';
         	if (digit != 0 || divisor < 10)
          	{ 
				buff[p++] = digit + '0';
            	p1 = 1;        
          	}
         	else if (p1)
            	buff[p++] = '0';
         	value -= digit*divisor;
		}
	buff[p] = 0;           
	Display(buff);
}

/******************************************************************************/
void Show_logo(void)//显示开机画面
{
	Write_Comm(0x80);//写入"welcome to"首地址(第一行)
	Display_Logo(welcome);

	Write_Comm(0xc0);//写入"website"首地址(第2行)
	Display_Logo(website);
	Delay(200);

	Write_Comm(0x01);//清屏

	Write_Comm(0x80);//写入"designed "首地址(第一行)
	Display_Logo(designed);


	Write_Comm(0xc0);//写入"whoami"首地址(第2行)
	Display_Logo(whoami);
	Delay(200);

	Write_Data(0x01);//清屏
}

/******************************************************************************/
void main(void)//主函数
{
	Init_Timer0();//初始化T0
	Init_LCD_Logo(); //初始化 Logo

	Show_logo();//开机画面显示
	
	Init_LCD_Cal(); //初始化 LCM
	Digit_input_calcul();//计算值输入函数
}

	


		


	

 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -