#include<stdio.h>
#include<reg51.h>	
#include"lcd.h"
#define GPIO_KEY P1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<ctype.h>

//按键检测函数
unsigned char PuZh[]="  ZHQ CRH HTK   ";
unsigned char KeyValue;
//用来存放读取到的键值
unsigned char KeyState;
//用来存放按键状态
unsigned char Key;
void Delay10ms();   //延时50us
void Delay10(unsigned int c);
void KeyDown();		 //检测按键函数
unsigned char h=0,wei=0;
unsigned char i=0;
unsigned char d=0;
 char s[30],gg[5];
void KeyDown(void)										
{
	char a;
	GPIO_KEY=0x0f;
	if(GPIO_KEY!=0x0f)
	{	  
		Delay10ms();
		if(GPIO_KEY!=0x0f)
		{
			KeyState=1;
			//测试列
			GPIO_KEY=0X0F;
// 			Delay10ms();
			switch(GPIO_KEY)
			{
				case(0X07):	KeyValue=0;break;
				case(0X0b):	KeyValue=1;break;
				case(0X0d): KeyValue=2;break;
				case(0X0e):	KeyValue=3;break;
//				default:	KeyValue=17;	//检测出错回复17意思是把数码管全灭掉。
			}
			//测试行
			GPIO_KEY=0XF0;
			Delay10ms();
			switch(GPIO_KEY)
			{
				case(0X70):	KeyValue=KeyValue;break;
				case(0Xb0):	KeyValue=KeyValue+4;break;
				case(0Xd0): KeyValue=KeyValue+8;break;
				case(0Xe0):	KeyValue=KeyValue+12;break;
//				default:	KeyValue=17;
			}
			switch(KeyValue)
			{
			case(0): Key=0x31;break;
			case(1): Key=0x32;break;
			case(2): Key=0x33;break;
			case(3): Key=0x01;break;
			case(4): Key=0x34;break;
			case(5): Key=0x35;break;
			case(6): Key=0x36;break;
			case(7): Key=0x2a;break;
			case(8): Key=0x37;break;
			case(9): Key=0x38;break;
			case(10): Key=0x39;break;
			case(11): Key=0x2f;break;
			case(12): Key=0x30;break;
			case(13): Key=0x2b;break;
			case(14): Key=0x2d;break;
			case(15): Key=0x3d;break;
			}
	
			while((a<50)&&(GPIO_KEY!=0xf0))	 //检测按键松手检测
			{
				Delay10ms();
				a++;
			}
			a=0;
		}		
	} 
}
/*******************************************************************************
* 函 数 名         : Delay10ms
* 函数功能		   : 延时函数,延时10ms
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void Delay10ms(void)   //误差 0us
{
    unsigned char a,b,c;
    for(c=1;c>0;c--)
        for(b=38;b>0;b--)
            for(a=130;a>0;a--);
}
void Delay10(unsigned int c)   //误差 0us
{
    unsigned char a,b;
    for(c;c>0;c--)
        for(b=38;b>0;b--)
            for(a=130;a>0;a--);
}
/*************************************/

int shuru(unsigned char s[])                  //构建一个子函数,用以输入字符串
{
	i=0;
	do
	s[i++]=Key;                 //将输入的字符串中的每一个字符存到字符型数组s中
	while(s[i-1]!='=');               //单s[i-1]为等号时,结束循环
	s[i]='\0';                        //在s[i]处插入终止符
	return i;                         //返回字符的个数
}
/**************************************/
int numb(unsigned char s[])            //构建一个子函数,用以找出字符串中的数字
{
	unsigned char r=0;
	while(isdigit(s[i]))           //当输入的是数字时
	{
		r=r*10+s[i]-'0';
	    i++;
	}                                 //将字符串中的数字找出
	return r;                         //返回被找出的数字
}	  
/**************************************/ 
void inumb()            //构建一个子函数, 讲一个数字安每一位分解成固定五位长度的数组
{														  
	int k;
for(k=5;k>0;k--)
{
gg[k]=d%10;
d/=10;
} 
LcdWriteCom(0x01);
	for(k=16;k>0;k--)
	{
	LcdWriteData(gg[k]);	
	}	                                                  
}
 /*************************************/ //ERROR
void er()
  	 {	
	  int ii;
	 char e[5]={'E','R','R','O','r'};
	 for(ii=0;ii<5;ii++)
	{LcdWriteData(e[ii]);} 
	LcdWriteCom(0x01);
  	 
	 }
/*************************************/
	
	 
void computer(char s[])               //构建一个子函数,用以进行计算
{
	int q,b;

	char c;
    q=numb(s);                      //找出字符串中的第一个数,并将它赋值给a
	c=s[i++];                      //找出字符串中的运算字符,并将它赋值给c
	b=numb(s);                      //找出字符串中的第二个数,并将它赋值给b
	switch(c)                         //判断运算字符是什么字符
	{
	case'+':d=q+b,inumb()  ;break;
	case'-':d=q-b,inumb()  ;break;
	case'*':d=q*b,inumb()  ;break;		
	}  
	if(c=='/')
	{
		if(!b)               //除数为0
            er();
	    else
         	d=q/b;inumb();  
	}  	
}
 /**************************************/
  void sss()
  {	 	
 if(wei>=16)	
		  {LcdWriteCom(0x07);
		  }
 else						  
		   { 
		   LcdWriteCom(0x06);
		   }
	KeyState=0;	
	LcdWriteCom(0x80+wei);
	wei++;
			   	
			    if(Key!=0x01)	  
			      LcdWriteData(Key);
			    else
			     {	LcdWriteCom(0x01);
			       wei=0;}
  }
/**************************************/
void main()
{
	
	int o;   	
	LcdInit();
	KeyState=0;
	for(o=0;o<16;o++)
	{
	LcdWriteData(PuZh[o]);	
	}
	Delay10(100);	
	LcdWriteCom(0x01);
	while(1)														    
	{
		KeyDown();			 
		if(KeyState)
		{   
	    	if(Key==0x3d)
			{inumb();break;}
          
	     	sss();		
            shuru(s);
            computer(s);

        }
    }
}


#include"lcd.h"

/*******************************************************************************
* 函 数 名         : Lcd1602_Delay1ms
* 函数功能		   : 延时函数,延时1ms
* 输    入         : c
* 输    出         : 无
* 说    名         : 该函数是在12MHZ晶振下,12分频单片机的延时。
*******************************************************************************/

void Lcd1602_Delay1ms(uint c)   //误差 0us
{
    uchar a,b;
	for (; c>0; c--)
	{
		 for (b=199;b>0;b--)
		 {
		  	for(a=1;a>0;a--);
		 }      
	}
    	
}

/*******************************************************************************
* 函 数 名         : LcdWriteCom
* 函数功能		   : 向LCD写入一个字节的命令
* 输    入         : com
* 输    出         : 无
*******************************************************************************/
#ifndef 	LCD1602_4PINS	 //当没有定义这个LCD1602_4PINS时
void LcdWriteCom(uchar com)	  //写入命令
{
	LCD1602_E = 0;     //使能
	LCD1602_RS = 0;	   //选择发送命令
	LCD1602_RW = 0;	   //选择写入
	
	LCD1602_DATAPINS = com;     //放入命令
	Lcd1602_Delay1ms(1);		//等待数据稳定

	LCD1602_E = 1;	          //写入时序
	Lcd1602_Delay1ms(5);	  //保持时间
	LCD1602_E = 0;
}
#else 
void LcdWriteCom(uchar com)	  //写入命令
{
	LCD1602_E = 0;	 //使能清零
	LCD1602_RS = 0;	 //选择写入命令
	LCD1602_RW = 0;	 //选择写入

	LCD1602_DATAPINS = com;	//由于4位的接线是接到P0口的高四位,所以传送高四位不用改
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;	 //写入时序
	Lcd1602_Delay1ms(5);
	LCD1602_E = 0;

//	Lcd1602_Delay1ms(1);
	LCD1602_DATAPINS = com << 4; //发送低四位
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;	 //写入时序
	Lcd1602_Delay1ms(5);
	LCD1602_E = 0;
}
#endif
/*******************************************************************************
* 函 数 名         : LcdWriteData
* 函数功能		   : 向LCD写入一个字节的数据
* 输    入         : dat
* 输    出         : 无
*******************************************************************************/		   
#ifndef 	LCD1602_4PINS		   
void LcdWriteData(uchar dat)			//写入数据
{
	LCD1602_E = 0;	//使能清零
	LCD1602_RS = 1;	//选择输入数据
	LCD1602_RW = 0;	//选择写入

	LCD1602_DATAPINS = dat; //写入数据
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;   //写入时序
	Lcd1602_Delay1ms(5);   //保持时间
	LCD1602_E = 0;
}
#else
void LcdWriteData(uchar dat)			//写入数据
{
	LCD1602_E = 0;	  //使能清零
	LCD1602_RS = 1;	  //选择写入数据
	LCD1602_RW = 0;	  //选择写入

	LCD1602_DATAPINS = dat;	//由于4位的接线是接到P0口的高四位,所以传送高四位不用改
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;	  //写入时序
	Lcd1602_Delay1ms(5);
	LCD1602_E = 0;

	LCD1602_DATAPINS = dat << 4; //写入低四位
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;	  //写入时序
	Lcd1602_Delay1ms(5);
	LCD1602_E = 0;
}
#endif
/*******************************************************************************
* 函 数 名       : LcdInit()
* 函数功能		 : 初始化LCD屏
* 输    入       : 无
* 输    出       : 无
*******************************************************************************/		   
#ifndef		LCD1602_4PINS
void LcdInit()						  //LCD初始化子程序
{
 	LcdWriteCom(0x38);  //开显示
	LcdWriteCom(0x0c);  //开显示不显示光标
	LcdWriteCom(0x06);  //写一个指针加1
	LcdWriteCom(0x01);  //清屏
	LcdWriteCom(0x80);  //设置数据指针起点
}
#else
void LcdInit()						  //LCD初始化子程序
{
	LcdWriteCom(0x32);	 //将8位总线转为4位总线
	LcdWriteCom(0x28);	 //在四位线下的初始化
	LcdWriteCom(0x0c);  //开显示不显示光标
	LcdWriteCom(0x06);  //写一个指针加1
	LcdWriteCom(0x01);  //清屏
	LcdWriteCom(0x80);  //设置数据指针起点
}
#endif