51单片机实现简易计算机,Keil4代码Proteus工程一步到位

目录

 前言

 Proteus硬件部分

键盘

程序部分

运算代码逻辑(代码解释)

LCD屏幕显示运算结果

输入部分

键值判断部分

删除按键的实现

程序执行运算


 前言

Hello,大家好。想做关于嵌入式的一些小项目已经很久了,今天借着我们课设的机会,给大家展示我自己对代码逻辑的理解,为了方便简易,所有代码我都放在了一个.c文件里面,希望我的代码能给读者带来不一样的收获与编写简易计算机的思路,创作不易,大家觉得好的话点个赞呗~

简易计算机前后最大位均是三位,可以实现加减乘除四种运算功能,输入键盘采用的是4×4行列式的循环扫描按键键盘

 Proteus硬件部分

 Proteus版本是8.6,我采用的显示屏是LCD1602用来显示计算的结果与输入,其次D1标志灯常用于显示程序运行正常的标志,KEY为复位按键

键盘

 键盘扫描逻辑:

 键盘部分的接线图如图所示,我看到很多博主都喜欢使用switch(a)...case...的逻辑运行按键,但本次我根据书上的方法(《单片机原理与应用(P103页,林立版)》)使用的是扫描的方法启动按键,即在循环口输出一组扫描码(以P3为例),首先规定键盘的行(图A1 A2 A3 A4)都为高电压,而列(A5 A6 A7 A8 )开启循环扫描,即轮流有一列为0,其余都为1。

利用条件表达式(P3&0x0f)判断按键有无按压,若低4位不全为1,则说明有按键按压,则此时可以执行key_buf函数

key_buf[]={0xee,0xde,0xbe,0x7e,
           0xed,0xdd,0xbd,0x7d,
           0xeb,0xdb,0xbb,0x7b,
           0xe7,0xd7,0xb7,0x77}

     

键值计算:

若将行列式键盘自左至右,自上至下排列序号作为键值,则通过逐一对比P2读入值与键模数组,可求闭合按键键值j,即:

 if((P3&0x0f)!=0x0f){
      for(j=0;j<16;j++)
       {if (key_buf[j]==P3) return j;
			 }
		 }
	 }
return -1;

以上两步完成对键盘的编写。

程序部分

 话不多说,直接上所有程序吧

//Grumpy cat

#include <reg51.h>
char key_buf[]={0xee,0xde,0xbe,0x7e,0xed,0xdd,0xbd,0x7d,0xeb,0xdb,0xbb,0x7b,0xe7,0xd7,0xb7,0x77};//定义键盘按键
unsigned char code sable[]="error!";
unsigned char code table0[]="0";
unsigned char code table[]="1";
unsigned char code table2[]="2";
unsigned char code table3[]="3";
unsigned char code table4[]="4";
unsigned char code table5[]="5";
unsigned char code table6[]="6";
unsigned char code table7[]="7";
unsigned char code table8[]="8";
unsigned char code table9[]="9";
unsigned char code table10[]="+";
unsigned char code table11[]="-";
unsigned char code table12[]="*";
unsigned char code table13[]="/";
unsigned char code table14[]="=";//以上是LCD屏幕需要展现的符号
unsigned char code mode[]={0x00,0x01,0x02,0x03,0x004,0x05,0x06,0x07,0x08,0x09};//10位地址,每当按下一次按键,地址+1,实现右移功能
unsigned char flash[]={0,0,0,0,0,0,0};//存储符号内容,转化为数字
sbit P1_7=P1^7;//灯标志位
sbit RS=P2^0;
sbit RW=P2^1;
sbit EN=P2^2;//LCD设置
int i;

int  a=0;
unsigned int p;
char c=0;
char m=0;
char op;
//定义按键
char getkey(void){
	char key_scan[]={0xef,0xdf,0xbf,0x7f};
  char i=0,j=0;
  for(i=0;i<4;i++){
  P3=key_scan[i];
  if((P3&0x0f)!=0x0f){
      for(j=0;j<16;j++)
       {if (key_buf[j]==P3) return j;
			 }
		 }
	 }
return -1;
 }
//定义延时函数
 void delay(unsigned int time){
	  unsigned int j = 0;
	  for (;time>0;time--)
	    for (j=0;j<125;j++);
}
//定义按键中的延时函数
void delay1(unsigned int x){
    unsigned int i;
    for(i=x;i>0;i--);
}
//初始化设置LCD显示屏
void write_com(unsigned char com){
      P0=com;
	  RS=0;RW=0;EN=1;
	  delay1(200);
	  EN=0;}
//LCD显示内容
void write_dat(unsigned char dat){
      P0=dat;
	  RS=1;RW=0;EN=1;
	  delay1(200);
	  EN=0;
	  }
//初始化LCD显示屏
void init(){
    write_com(0x01);
	  write_com(0x38);
	  write_com(0x0f);
	  write_com(0x06);
	  }
//显示得出结果后的地址
void address(unsigned char x,unsigned char y){
	 unsigned char location;
	 if(x==0)
		 location=0x80|y;
	 else if(x==1)
		 location=0xc0|y;
	 write_com(location);}
//加法减法乘法运算函数
void printtemp(unsigned char x,unsigned char y,unsigned long temp3)
  {
		if(temp3<=99){
		address(x,y);
		write_dat(temp3/10 + '0');
		address(x,y + 1);
		write_dat(temp3%10 + '0');}
		else if(temp3>99&&temp3<=999){
         	address(x,y);
		write_dat(temp3/100 + '0');
		address(x,y + 1);
		write_dat(temp3%100/10 + '0');
			address(x,y + 2);
		write_dat(temp3%10 +  '0');
          }
		else if(temp3>999&&temp3<=9999){
		    address(x,y);
			write_dat(temp3/1000 + '0');
			address(x,y + 1);
			write_dat(temp3%1000/100 + '0');
			address(x,y + 2);
			write_dat(temp3%100/10 + '0');
			address(x,y +3);
			write_dat(temp3%10 + '0');
        }
		else if(temp3>9999&&temp3<=99999){
		    address(x,y);
			write_dat(temp3/10000 + '0');
			address(x,y + 1);
			write_dat(temp3%10000/1000 + '0');
			address(x,y + 2);
			write_dat(temp3%1000/100 + '0');
			address(x,y +3);
			write_dat(temp3%100/10 + '0');
			address(x,y + 4);
			write_dat(temp3%10 + '0');
        }
		else if(temp3>99999&&temp3<=999999){
         address(x,y);
			write_dat(temp3/100000 + '0');
			address(x,y + 1);
			write_dat(temp3%100000/10000 + '0');
			address(x,y + 2);
			write_dat(temp3%10000/1000 + '0');
			address(x,y +3);
			write_dat(temp3%1000/100 + '0');
			address(x,y + 4);
			write_dat(temp3%100/10 + '0');
			address(x,y + 5);
			write_dat(temp3%10 + '0');
      }
    }
//除法运算函数
void printtemp_c(unsigned char x,unsigned char y,double temp)
		{
			unsigned int temp1;
			temp1=temp*100;
			if(temp1<100)
			{
				address(x,y);
				write_dat(temp1/100 + '0');
				address(x,y + 1);
				write_dat('.');
				address(x,y + 2);
				write_dat(temp1/10 + '0');
				address(x,y + 3);
				write_dat(temp1%10 + '0');
				}
			else if (temp1>=100&&temp1<1000){
				address(x,y);
				write_dat(temp1/100 + '0');
				address(x,y + 1);
				write_dat('.');
				address(x,y + 2);
				write_dat(temp1%100/10 + '0');
				address(x,y + 3);
				write_dat(temp1%10 + '0');}
			else if (temp1>=1000&&temp1<10000){
				address(x,y);
				write_dat(temp1/1000 + '0');
				address(x,y + 1);
				write_dat(temp1%1000/100 + '0');
				address(x,y + 2);
				write_dat('.');
				address(x,y + 3);
				write_dat(temp1%100/10 + '0');
				address(x,y + 4);
				write_dat(temp1%10 + '0');}
			else if (temp1>=10000&&temp1<100000){
        address(x,y);
				write_dat(temp1/10000 + '0');
				address(x,y + 1);
				write_dat(temp1%10000/1000 + '0');
				address(x,y + 2);
				write_dat(temp1%1000/100 + '0');
				address(x,y + 3);
				write_dat('.');
				address(x,y + 4);
				write_dat(temp1%100/10 + '0');
				address(x,y + 5);
				write_dat(temp1%10 + '0'); }
			} 				

void main(void){
	int q=0;
	char dir=0,run=0;
	unsigned char judge=1;
	unsigned long result;
	double result2;
	unsigned long num1=0,num2=0;
	unsigned long num1_t,num2_t;
   char key=0;
    init();
   while(1){
     key=getkey();
		 flash[q]=key;
		 if(key<=14){
		 
		 if (flash[5]==4){P1_3=0;}
		 if(key!=-1) {
			  a=a+1;
			  p=a;
		    delay(400);
       if(key==14)
          a--;				 
         }
				 
			if(a==1){
				P1_1=0;
           }
			else if(a==2){
                   P1_1=1;


}
			else if(a==3){P1_2=0;

}
//judge=1,判断flash[]在0~9之间说明为第一个数值的输入
 if(judge==1&&flash[q]>=0&&flash[q]<=9){
		 if(key==1) {
			    
          write_com(0x80+mode[a]);
			 for(i=0;i<1;i++){
	        write_dat(table[i]);
			    delay1(3000);				 
                 }
				 q++;
				 num1++;
      //   HEX_U(a);							 
					}
		 if(key==2) {
			    
			    write_com(0x80+mode[a]);
			    
			 for(i=0;i<1;i++){
				 write_dat(table2[i]);
				     delay1(3000);}
						 q++;
						 num1++;
			//	 HEX_U(a);	
                     }
		 if(key==3) {
			 write_com(0x80+mode[a]);
			 for(i=0;i<1;i++){
	        write_dat(table3[i]);
			    delay1(3000);				 
                 }
							q++;
							num1++;
			//		HEX_U(a);		 	 
                }
		 if(key==4) {
			 write_com(0x80+mode[a]);
			 for(i=0;i<1;i++){
	        write_dat(table4[i]);
			    delay1(3000);				 
                 }
								q++;
								 num1++;
			//			HEX_U(a);	
						 	 }
		 if(key==5) {
			 write_com(0x80+mode[a]);
			 for(i=0;i<1;i++){
	        write_dat(table5[i]);
			    delay1(3000);				 
                 }
								q++;
								num1++;
			//				HEX_U(a);	
						 	 }
		 if(key==6) {
			 write_com(0x80+mode[a]);
			 for(i=0;i<1;i++){
	        write_dat(table6[i]);
			    delay1(3000);				 
                 }
							q++;
							num1++;
				//				HEX_U(a);	
						 	 }
		 if(key==7) {
			 write_com(0x80+mode[a]);
			 for(i=0;i<1;i++){
	        write_dat(table7[i]);
			    delay1(3000);				 
                 }
							q++;
							num1++;
			//			HEX_U(a);	
						 	 }
		 if(key==8) {
			 write_com(0x80+mode[a]);
			 for(i=0;i<1;i++){
	        write_dat(table8[i]);
			    delay1(3000);				 
                 }
							q++;
							num1++;
			//					HEX_U(a);	
						 	 }
		 if(key==9) {
			 write_com(0x80+mode[a]);
			 for(i=0;i<1;i++){
	        write_dat(table9[i]);
			    delay1(3000);				 
                 }
							q++;
							num1++;
			//				HEX_U(a);	
						 	 }
      if(key==0) {
			 write_com(0x80+mode[a]);
			 for(i=0;i<1;i++){
	        write_dat(table0[i]);
			    delay1(3000);				 
                 }
							q++;
							num1++;
			//					HEX_U(a);	
						 	 }
  //当位数超过三报错
			if(num1>3){
          write_com(0x01);
				 write_com(0x80);
			      for(i=0;i<6;i++){
					 write_dat(sable[i]);
					 delay1(3000);}
}
       }
   //+
			 if(key==10){
				 judge=2;
				 write_com(0x80+mode[a]);
				 for(i=0;i<1;i++){
					 write_dat(table10[i]);
					 delay1(3000);}
					 op=111;
					 
				 }
//-
        if(key==11){
					judge=2;
				 write_com(0x80+mode[a]);
				 for(i=0;i<1;i++){
					 write_dat(table11[i]);
					 delay1(3000);}
					 op=222;
					 
				 }
//*
				 if(key==12){
					 judge=2;
				 write_com(0x80+mode[a]);
				 for(i=0;i<1;i++){
					 write_dat(table12[i]);
					 delay1(3000);}
					 op=333;
					 
				 }
// /
         if(key==13){
					 judge=2;
				 write_com(0x80+mode[a]);
				 for(i=0;i<1;i++){
					 write_dat(table13[i]);
					 delay1(3000);}
					 op=444;
					 
				 }
				
 if(judge==2&&flash[q]>=0&&flash[q]<=9)	{	
        if(key==1) {
			    
          write_com(0x80+mode[a]);
			 for(i=0;i<1;i++){
	        write_dat(table[i]);
			    delay1(3000);				 
                 }
				 q++;
				 num2++;
      //   HEX_U(a);							 
					}
		 if(key==2) {
			    
			    write_com(0x80+mode[a]);
			    
			 for(i=0;i<1;i++){
				 write_dat(table2[i]);
				     delay1(3000);}
						 q++;
						 num2++;
			//	 HEX_U(a);	
                     }
		 if(key==3) {
			 write_com(0x80+mode[a]);
			 for(i=0;i<1;i++){
	        write_dat(table3[i]);
			    delay1(3000);				 
                 }
							q++;
							num2++;
			//		HEX_U(a);		 	 
                }
		 if(key==4) {
			 write_com(0x80+mode[a]);
			 for(i=0;i<1;i++){
	        write_dat(table4[i]);
			    delay1(3000);				 
                 }
								 q++;
								 num2++;
			//			HEX_U(a);	
						 	 }
		 if(key==5) {
			 write_com(0x80+mode[a]);
			 for(i=0;i<1;i++){
	        write_dat(table5[i]);
			    delay1(3000);				 
                 }
								q++;
								num2++;
			//				HEX_U(a);	
						 	 }
		 if(key==6) {
			 write_com(0x80+mode[a]);
			 for(i=0;i<1;i++){
	        write_dat(table6[i]);
			    delay1(3000);				 
                 }
							q++;
							num2++;
				//				HEX_U(a);	
						 	 }
		 if(key==7) {
			 write_com(0x80+mode[a]);
			 for(i=0;i<1;i++){
	        write_dat(table7[i]);
			    delay1(3000);				 
                 }
							q++;
							num2++;
			//			HEX_U(a);	
						 	 }
		 if(key==8) {
			 write_com(0x80+mode[a]);
			 for(i=0;i<1;i++){
	        write_dat(table8[i]);
			    delay1(3000);				 
                 }
							q++;
							num2++;
			//					HEX_U(a);	
						 	 }
		 if(key==9) {
			 write_com(0x80+mode[a]);
			 for(i=0;i<1;i++){
	        write_dat(table9[i]);
			    delay1(3000);				 
                 }
							q++;
							num2++;
			//				HEX_U(a);	
						 	 }
      if(key==0) {
			 write_com(0x80+mode[a]);
			 for(i=0;i<1;i++){
	        write_dat(table0[i]);
			    delay1(3000);				 
                 }
							q++;
							num2++;
			//					HEX_U(a);	
						 	 }
			if(num2>3){
          write_com(0x01);
				 write_com(0x80);
			      for(i=0;i<6;i++){
					 write_dat(sable[i]);
					 delay1(3000);}
}                     
  
}
      if(key==14){
			 flash[q-1]=0;
			 q--;
			  write_com(0x80+mode[p-1]);
			 write_dat(' ');
//				write_com(0x18);
			 if(judge==1)	
				 num1--;
			 if(judge==2)
				 num2--;
     }
            
 }
	///当按下第15个按键(=),则运行:
     
				 if(key==15){
					 if(num1==1){
						 num1_t=flash[0];}
					 else if(num1==2){
						 num1_t=flash[0]*10+flash[1];}
					 else if(num1==3){
						 num1_t=flash[0]*100+flash[1]*10+flash[2];}
						 
						///Åжϵڶþ¸ö¼üÖµ
					 if(num2==1){
						 num2_t=flash[num1];}
					 else if(num2==2){
						 num2_t=flash[num1]*10+flash[num1+1];}
					 else if(num2==3){
						 num2_t=flash[num1]*100+flash[num1+1]*10+flash[num1+2];}
						 delay(400);
					 switch(op){
						   case 111: result=num1_t+num2_t;dir=1;break;
						   case 222: result=num1_t-num2_t;dir=1;break;
  						 case 333: result=num1_t*num2_t;dir=1;break;
  						 case 444: result2=((double)num1_t)/((double)num2_t);run=1;break;
					 }
					
					 if(dir==1){
  					  printtemp(1,1,result);}
						else if(run==1){ 
					    printtemp_c(1,1,(double)result2);}

						if(flash[5]==5){
						    P1_7=0;
                         }
							
					 
				 }


            }


      }

运算代码逻辑(代码解释)

LCD屏幕显示运算结果

当我们输出结果之后,应该在屏幕中输出我们想要得到的结果,使用addressprinttemp函数实现

void address(unsigned char x,unsigned char y){
	 unsigned char location;
	 if(x==0)
		 location=0x80|y;
	 else if(x==1)
		 location=0xc0|y;
	 write_com(location);}
void printtemp(unsigned char x,unsigned char y,unsigned long temp3)
  {
		if(temp3<=99){
		address(x,y);
		write_dat(temp3/10 + '0');
		address(x,y + 1);
		write_dat(temp3%10 + '0');}
		else if(temp3>99&&temp3<=999){
         	address(x,y);
		write_dat(temp3/100 + '0');
		address(x,y + 1);
		write_dat(temp3%100/10 + '0');
			address(x,y + 2);
		write_dat(temp3%10 +  '0');
          }
		else if(temp3>999&&temp3<=9999){
		    address(x,y);
			write_dat(temp3/1000 + '0');
			address(x,y + 1);
			write_dat(temp3%1000/100 + '0');
			address(x,y + 2);
			write_dat(temp3%100/10 + '0');
			address(x,y +3);
			write_dat(temp3%10 + '0');
        }
		else if(temp3>9999&&temp3<=99999){
		    address(x,y);
			write_dat(temp3/10000 + '0');
			address(x,y + 1);
			write_dat(temp3%10000/1000 + '0');
			address(x,y + 2);
			write_dat(temp3%1000/100 + '0');
			address(x,y +3);
			write_dat(temp3%100/10 + '0');
			address(x,y + 4);
			write_dat(temp3%10 + '0');
        }
		else if(temp3>99999&&temp3<=999999){
         address(x,y);
			write_dat(temp3/100000 + '0');
			address(x,y + 1);
			write_dat(temp3%100000/10000 + '0');
			address(x,y + 2);
			write_dat(temp3%10000/1000 + '0');
			address(x,y +3);
			write_dat(temp3%1000/100 + '0');
			address(x,y + 4);
			write_dat(temp3%100/10 + '0');
			address(x,y + 5);
			write_dat(temp3%10 + '0');
      }
    }

 我们取加减乘的函数部分,首先我们显示的最大位为999*999=998001,最大位是六位,当我们经运算得到的代码结果最大也不会超过六位,可能位是1,2,3,4,5,6,因此当temp3<99是(运算值为一位或两位),那么LCD输出的第一位是结果的十位,即write_dat(temp/10 + '0'),其中address为地址函数x,y分别是对应输出在LCD屏幕上的位置,当输入完毕后,address+1输出下一位,当为两位时,我们在屏幕上首先输出第一位是十位之后,需要地址(address+1),之后再输出第二位,即输出完毕,同理一直输出到第六位都是用的同样的逻辑

还有一个部分是我们计算除法的时候,和加减乘除还是有些区别的,因为我们除法需要有小数,则我们在对函数定义temp的时候也需要将其定义为double类型。读者可以自行下载编译代码试一试。

输入部分

在编写函数之前我们要明白,当我们最大输入前三个数值前,需要知道当输入第一个数字后,LCD的地址就要加1,方便之后继续输入,同时flash[0]也要保存第一位,同时num++用于判断之后运算为到底是几位,

首先我们要输入第一个数字,使用write_com(0x80+mode[0]),表明的是输入的起点是第一行第一个字符,其次函数中a需要做a++判断,当我们再次按下另一个数值,这个数字就会被保存在下一个地址中,则我们使用write_com(0x80+mode[a]).

键值判断部分

在我们输入完前半部分数值之后,之后进入加减乘除按键的判断选择,这里我们设置一个变量judge2,当我们还在输入第一个数值的时候,赋值judge1=1,当我们输入完毕之后,按下运算按键,则judge1换为judge2,这时程序就跳出数字输入的循环,直接判断加减乘除符号符号,值得注意的是我们输入符号的时候,其实并没有占用flash[]的位,因此当我们使用DEL删除键,有 ‘     ’ 来占位,之后程序进入op值的判断(以+为例)

	 if(key==10){
				 judge=2;
				 write_com(0x80+mode[a]);
				 for(i=0;i<1;i++){
					 write_dat(table10[i]);
					 delay1(3000);}
					 op=111;
					 
				 }

不难看出, ‘+’ 为键值10的表示,op=111,这时程序知道你要做的是加法运算,op=111是一个标志,待会将会直接进入加法运算执行

删除按键的实现

 if(key==14){
			 flash[q-1]=0;
			 q--;
			  write_com(0x80+mode[p-1]);
			 write_dat(' ');
				write_com(0x18);
			 if(judge==1)	
				 num1--;
			 if(judge==2)
				 num2--;
     }

不难看出,删除键为key=14,我们按下删除按键的时候需要让flash[]和q(q就理解为程序中的a)都减一,,因为只有LCD和flash[]中储存有数值,只有用if判断句,实现num--,目的是减少一位

程序执行运算

 if(key==15){
					 if(num1==1){
						 num1_t=flash[0];}
					 else if(num1==2){
						 num1_t=flash[0]*10+flash[1];}
					 else if(num1==3){
						 num1_t=flash[0]*100+flash[1]*10+flash[2];}
						 
						

					 if(num2==1){
						 num2_t=flash[num1];}
					 else if(num2==2){
						 num2_t=flash[num1]*10+flash[num1+1];}
					 else if(num2==3){
						 num2_t=flash[num1]*100+flash[num1+1]*10+flash[num1+2];}
						 delay(400);
					 switch(op){
						   case 111: result=num1_t+num2_t;dir=1;break;
						   case 222: result=num1_t-num2_t;dir=1;break;
  						 case 333: result=num1_t*num2_t;dir=1;break;
  						 case 444: result2=((double)num1_t)/((double)num2_t);run=1;break;
					 }
					
					 if(dir==1){
  					  printtemp(1,1,result);}
						else if(run==1){ 
					    printtemp_c(1,1,(double)result2);}

						if(flash[5]==5){
						    P1_7=0;
}
							
					 
				 }

一   首先判断num的位数,然后根据位数将flash[]里面存储的数拿出来进行相应位数的运算,num=1说明前一个数值只有一位,num=2说明有两位,num=3说明有三位,且数值最大不超过三位,其次判断第二个数值(num2),第二个数值程序逻辑与第一个相同

二   判断完前后两个数值大小后,再去判断op,op的判断应用于程序应该进行怎么样的运算操作,运算结果都将保留在result或者result2中,再通过printtemp函数在LCD屏幕中显示出运算结果

以上就是代码的全部内容了,下面是随机的运算。非常感谢大家能够读到这里,喜欢的话,就点个赞再走吧~,还是有什么有疑问的话小伙伴可以在评论区或者留言私信我,我会以最快的速度回复大家,感谢大家的支持!!!!

 

  • 17
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Grumpy Cat 刘sir

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值