C51实现矩阵运算

1,按键的消抖,防止两次进入同一语句块
2,优先级运算的数组实现
3,lcd1602写数据,写命令,写光标地址(调用写命令函数)

/********	矩阵按键实现四则运算,可退格(独立按键控制)可清屏,实现了优先级运算。   ******/
#include<reg52.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
typedef unsigned char uint8;
typedef unsigned int uint16;
//退格键的实现
sbit delet=P3^3;
//lcd的相关引脚
sbit rw=P2^5;
sbit rs=P2^6;
sbit e=P2^7;
uint8 key,num;
uint8 flag=0; //定义有没有按下符号按键,如果按下,flag置1,说明一个数值已经输入完毕,要让value_num+1,在value数组的下一个位置储存新的数值,直到再遇到符号
uint8 sign_num=0;//符号的数量
uint8 value_num=0;//数值的数量
float value[32];//存储输入的数值
uint8 sign[20];	//存储符号:  +:1    -:2    *:3    /:4    这里的同级符号也要分出等级,因为/和-在运算时有数值的前后顺序    
uint8 max=0,idx=0;//找出符号中优先级最大的赋值给max,idx 为其下标
long total=0;	//最后结果
uint8 pos=0;//当前光标已经运行到哪里
uint8 pre;//存储光标前显示的那位字符,即将要退格删除的字符,根据判断为符号还是数字,来将两个数组中的元素进行对应的修改
uint8 dat1[]={1,2,3,0x2b-0x30, 4,5,6,0x2d-0x30, 7,8,9,0x2a-0x30, 0,0x01-0x30,0x3d-0x30,0x2b-0x30 };//保存显示的数据:1,2,3,+,4,5,6,-......

void delay(uint16 i)
{
	while(i--);
}
void lcdwrc(uint8 c)
{
	delay(1000);
	rs=0;
	rw=0;
	e=0;
	P0=c;
	e=1;
	delay(1000);
	e=0;
}
void lcdwrd(uint8 dat)
{
	delay(1000);
	rs=1;
	rw=0;
	e=0;
	P0=dat;
	e=1;
	delay(1000);
	e=0;
	rs=0;
}

void lcdinit()
{
	delay(1500);
	lcdwrc(0x38);
	delay(500);
	lcdwrc(0x38);
	delay(500);
	lcdwrc(0x38);
	delay(500);
	lcdwrc(0x38);
	lcdwrc(0x08);
	lcdwrc(0x01);
	lcdwrc(0x06);
	lcdwrc(0x0f);
	key=0;
	num=0;
	memset(value,0,sizeof(value));
	memset(sign,0,sizeof(sign));
}

void keyscan()
{

uint8 i,j,k=0;

P1=0x7f;   //定义第一行为零,然后判断哪一列按下
if(P1!=0x7f)
{
    delay(1000);
    if(P1!=0x7f)
    {
        key=P1&0x0f;
        switch(P1)
        {
            case 0x77: num=0;break;   //1
            case 0x7b: num=1;break;   //2
            case 0x7d: num=2;break;   //3
            case 0x7e: num=3;break;   //+
        }
    }
	//消抖操作,防止两次进入该if语句块
    while(P1!=0x7f);
    if(num==0||num==1||num==2)   //确认第一行的数1,2,3
    {
        if(flag==0)  //没有按下符号建
        {
            value[value_num]=value[value_num]*10+dat1[num];   
        }
        else
        {
				flag=0;
			value_num++;
           value[value_num]=dat1[num];
        }

    }
    if(num==3)
    {
        flag=1;
        sign[sign_num]=1;//加号
		sign_num++;
    }
    lcdwrd(0x30+dat1[num]);
	pre=dat1[num];
	pos++;
}

P1=0xbf;                //令第二行为零,然后判断第几行按下
if(P1!=0xbf)
{
    delay(1000);
    if(P1!=0xbf)
    {
        key=P1&0xf0;
        switch(P1)
        {
            case 0xb7: num=4;break;   //4
            case 0xbb: num=5;break;   //5
            case 0xbd: num=6;break;   //6
            case 0xbe: num=7;break;   //减-
        }   
    }
		//消抖操作,防止两次进入该if语句块
    while(P1!=0xbf);
    if(num==4||num==5||num==6)
    {
        if(flag==0)  //没有按下符号建
        {
            value[value_num]=value[value_num]*10+dat1[num];   
        }
        else
        {
				flag=0;
			value_num++;
           value[value_num]=value[value_num]*10+dat1[num];
        }
         
    }
    else
    {
         flag=1;
        sign[sign_num]=2;//减号
		sign_num++;
    }
    lcdwrd(0x30+dat1[num]);
	pre=dat1[num];
	pos++;
}


P1=0xdf;         //令第三行为零,然后判断第几列按下
if(P1!=0xdf)
{
    delay(1000);
    if(P1!=0xdf)
    {
        key=P1&0xf0;
        switch(P1)
        {
            case 0xd7: num=8;break;   //7
            case 0xdb: num=9;break;   //8
            case 0xdd: num=10;break;  //9
            case 0xde: num=11;break;  //乘*
        }   
    }
	//消抖操作,防止两次进入该if语句块
    while(P1!=0xdf);
    if(num==8||num==9||num==10)
    {
       if(flag==0)  //没有按下符号建
        {
            value[value_num]=value[value_num]*10+dat1[num];   
        }
        else
        {
				flag=0;
			value_num++;
           value[value_num]=value[value_num]*10+dat1[num];
        }

    }
    else
    {
         flag=1;
        sign[sign_num]=3;//乘号
		sign_num++;
    }
    lcdwrd(0x30+dat1[num]);
	pre=dat1[num];
	pos++;
}

P1=0xef;         //令第四行为零,然后判断第几列按下
if(P1!=0xef)
{
    delay(1000);
    if(P1!=0xef)
    {
        key=P1&0xf0;
        switch(P1)
        {
            case 0xe7: num=12;break;  //0
            case 0xeb: num=13;break;  //清楚rst
            case 0xed: num=14;break;  //等号=
            case 0xee: num=15;break;  //除/
        }   
    }
    while(P1!=0xef);
    switch(num)
    {
        case 12: 
		        if(flag==0)  //没有按下符号建
		        {
		            value[value_num]=value[value_num]*10+dat1[num];   
		        }
		        else
		        {
					flag=0;
					value_num++;
		           value[value_num]=value[value_num]*10+dat1[num];
		        }
				 lcdwrd(0x30+dat1[num]);
				 pre=dat1[num];
				 pos++;
		        break;

        case 13: 
                lcdwrc(0x01);   //清屏指令                     
                flag=0;              
                break;

        case 15:

                flag=1;
        		sign[sign_num]=4;//除号
				sign_num++;
                lcdwrd(0x2f);//除号/
				pre=dat1[num];
				pos++;
                break;

        case 14: 
				//以符号数量为基准,进行运算
				for(i=0;i<sign_num;i++)
				{
					//依次取出符号数组中的优先级最高的符号进行运算
					max=0;
					for(j=0;j<sign_num;j++)
					{
						if(sign[j]>max)
						{
							max=sign[j];
							idx=j;
						}
					}
				   switch(max)
				   {
				   		case 1:
								//如果该符号对应的数值已经被运算过,则向前找新数值参与运算
								//每次两个数运算完毕后,前一个位置 置新数值,后一个位置 置-1000;俩位置可以不相邻
								//同时相应符号数组中的符号位也置0,不要置-1,因为uint8无符号型,置-1会使该值一直为最大
								k=idx;
								if(value[k]==-1000)
								{
									while(value[k]==-1000)k--;
									value[k]=value[k]+value[idx+1];
									value[idx+1]=-1000;
									sign[idx]=0;
								}
								else 
								{
									value[k]=value[k]+value[k+1];
									value[k+1]=-1000;
									sign[k]=0;	
								}
								break;	
						case 2:
								k=idx;
								if(value[k]==-1000)
								{
									while(value[k]==-1000)k--;
									value[k]=value[k]-value[idx+1];
									value[idx+1]=-1000;
									sign[idx]=0;
								}
								else 
								{
									value[k]=value[k]-value[k+1];
									value[k+1]=-1000;
									sign[k]=0;	
								}
								break;	
						case 3:
								k=idx;
								if(value[k]==-1000)
								{
									while(value[k]==-1000)k--;
									value[k]=value[k]*value[idx+1];
									value[idx+1]=-1000;
									sign[idx]=0;
								}
								else 
								{
									value[k]=value[k]*value[k+1];
									value[k+1]=-1000;
									sign[k]=0;	
								}
								break;
						case 4:
								k=idx;
								if(value[k]==-1000)
								{
									while(value[k]==-1000)k--;
									value[k]=value[k]/value[idx+1];
									value[idx+1]=-1000;
									sign[idx]=0;
								}
								else 
								{
									value[k]=value[k]/value[k+1];
									value[k+1]=-1000;
									sign[k]=0;	
								}
								break;
								
				   }
				   //不断运算,最后全部结果都会前移加和到第一位
				   //这里注意value为float型,强制类型转换要放在最后,以防止8*9*2/5的算式得到答案为0
					total=(long)value[0];
				}
				//右下角显示结果
				 lcdwrc(0x4f+0x80);
                 lcdwrc(0x04);//设置光标左移ˉ,屏幕不移动
				
				if(total>0)		
                 while(total!=0)  //一位一位显示
                 {  
				  //若total为float类型则编译不通过
				 	lcdwrd('0'+total%10);//显示结果的最后一位在0x4f的位置
                    total=total/10;//取前面的结果数据   
                 }
				 else if(total<0)
				 {
				 	total=-total;
					 while(total!=0)  //一位一位显示
                	 {  
				  //若total为float类型则编译不通过
				 	lcdwrd(0x30+total%10);//显示结果的最后一位在0x4f的位置
                    total=total/10;//取前面的结果数据   
                	 }
					 lcdwrd('-');
				 }
				 else
				 {
				 	lcdwrd('0');
				 }
                 lcdwrd(0x3d); //显示等于号=
				 //每运算出一次结果之后,需要将所有数据重置,以进行下一次运算
				 total=0;
				 memset(value,0,sizeof(value));
				 memset(sign,0,sizeof(sign));
				sign_num=0;
				value_num=0;			
				max=0;
				idx=0;
				j=0;
				i=0;
				k=0;
				pos=0;
				pre=0;
				
    }
}
delet=1;
if(delet==0)
{
	delay(1000);
	if(delet==0)
	{
		if(pre>=0&&pre<=9)
		{
			value[value_num]=value[value_num]/10;
			lcdwrc(pos+0x00+0x80-1);
			lcdwrd(' ');
			lcdwrc(pos+0x00+0x80-1);
			pos--;
		}
		else
		{
			sign_num--;
			sign[sign_num]=0;
			lcdwrc(pos+0x00+0x80-1);
			lcdwrd(' ');
			lcdwrc(pos+0x00+0x80-1);
			pos--;
		}
	}
	delet=1;
	while(delet==0);  //需要消抖,不然按一次之后,可能会两次进入这个if语句块
}

}

void main()
{
	lcdinit();
	while(1)
	{
  	  keyscan();  
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值