单片机开发之LCD1602显示实验

举报
timerring 发表于 2022/07/29 23:31:53 2022/07/29
【摘要】 ​ 一、实验题目3.7 LCD 1602显示实验二、实验要求1、画出实验的流程图2、编写源程序并进行注释3、记录实验过程4、记录程序运行结果截图三、实验过程及结果分析要求利用LCD1602和16个按键实现简单的十进制数的加减乘除四则运算。其中按键KEY0-KEY9代表数字0-9,按键KEY10-KEY13分别代表运算符+、-、*、/,按键KEY15代表=,按键KEY14代表清除命令。不管什么...

 一、实验题目

3.7 LCD 1602显示实验

二、实验要求

1、画出实验的流程图

2、编写源程序并进行注释

3、记录实验过程

4、记录程序运行结果截图

三、实验过程及结果分析

要求利用LCD1602和16个按键实现简单的十进制数的加减乘除四则运算。其中按键KEY0-KEY9代表数字0-9,按键KEY10-KEY13分别代表运算符+、-、*、/,按键KEY15代表=,按键KEY14代表清除命令。不管什么时候按下清除按键,计算过程均将停止,两个输入变量清零,屏幕将清屏。

LCD1602第一行用于显示所输入的两个计算数以及计算符,第二行用于显示计算结果,结果允许为附属,但输入的两个输入数都必须是双字节正整数范围内的数,即0-32767.除数必须保证不为0,否则将报错。在有余数除法中,必须能同时显示商与余数。

1. 在Proteus 环境下建立图1所示原理图,并将其保存为LCD1602_self.DSN 文件:

编辑

图1:实验原理图

2. 编写源程序,将其保存为LCD1602_self.c。运行Keil开发环境,建立工程LCD1602_self.uV2,CPU 为AT89C51,包含启动文件STARTUP.A51。将C 语言源程序LCD1602_self.c 加入工程LCD1602_self.uV2,并设置工程LCD1602_self.uV2 属性,将其晶振频率设置为12MHz,选择输出可执行文件,仿真方式为选择硬仿真,并选择其中的“PROTEUS VSM

MONITOR 51 DRIVER”仿真器。

3. 构造(Build)工程LCD1602_self.uV2。如果输入有误进行修改,直至构造正确,生成可执行程序LCD1602_self.hex 为止,为AT89C51 设置可执行程序LCD1602_self.hex。

4. 运行程序,点击按键输入数据与运算符,计算,观察计算结果,并验证其是否正确,输入过程中,按“清除按键”观察结果,重新输入数据计算并验证。

   1)加法:1+2=3,如图2:

编辑

图2:加法测试

2)减法:5-3=2,如图3:

编辑

图3:减法测试

3)特殊情况:6-9=-3,如图4:

编辑

图4:负数减法测试

4)乘法:4*5=20,如图5:

编辑

图5:乘法测试

  5) 除法:20/5=4,如图6:

编辑

图6:除法测试

6) 带余数的除法,如图7:

编辑

图7:带余数的除法测试

7) 除法为0报错,如图8:

编辑

图8:除法为0报错

8) 清零,如图9:

编辑

图9:清零

四、实验流程图

编辑

图10:实验流程图

编程时要有一个状态变量,该变量用于记录当前是输入的哪个变量。输入第一个变量,遇到输入运算符时结束第一个变量的输入。输入第二个变量,遇到“=”号时结束第二个变量的输入,并且开始计算结果。

计算结果由于是16 进制的,要将其转换成十进制,并将该十进制的数转换成字符串后逐位显示出来。减法时要注意结果是否为负,除法时要注意除数是否为0,结果是否带有余数。另外,按键要注意去抖动处理。

采用的是逐行扫描,扫描的时候将要扫描的行置0,其余的行置1;扫描过程中,所有的列全部置1,当某一行的其中一个按键被按下,且正好扫描到这一样,那么所在的列将会被置0. 这时只需要;将行与1111相与即可判断那一列为0,即按下了哪一列。也是实验3.6中键盘扫描的基本思路。

五、实验源代码

#include<reg51.h>     //预处理伪指令
#define uint unsigned int 
#define uchar unsigned char
sbit lcden=P1^5;       //定义引脚E使能端,高到低液晶模块执行任务
sbit rs=P1^7;
sbit rw=P1^6;         // 控制读写
sbit busy=P0^7;
char i,j,temp,num;
long a=0,b=0,c=0,d=0;  //初始化a参与运算的第一个数,b参与运算的第二个数,c得数,d余数 
float a_c,b_c;
uchar flag,signal;  //flag表示运算符是否按下
                //signal表示按下运算符的名称

uchar code table[]={
0,1,2,3,
4,5,6,7,
8,9,0x2b-0x30,0x2d-0x30,
0x2a-0x30,0x2f-0x30,0x01-0x30,0x3d-0x30};	 //定义table数组
uchar code error[]="Error!";	//定义error数组,用于显示除数为0的情况

void delay(uchar z)     // 设置延迟函数                       
{
	uchar y;
	for(z;z>0;z--)
    	for(y=0;y<110;y++);
}
void check()      // 判断系统状态                 
{
	do
	{
	    P2=0xFF;
	    rs=0;        
	    rw=1;        
	    lcden=0;     
	    delay(1);    
	    lcden=1;     
	}
	while(busy==1);  //判断是否为空闲,1为忙,0为空闲
}
void lcd_wcmd(uchar com) // 写指令             
{
	P2=com;          
	rs=0;			  
	rw=0;			  
	lcden=0;		 
	check();
	lcden=1;		 
}
void lcd_wdat(uchar date)       // 写数据          
{
    P2=date;		
	rs=1;	        
	rw=0;			
	lcden=0;
	check();
	lcden=1;
}
void init() //初始化
{
    num=-1;
	lcden=1;             // 使能信号为高电平
	lcd_wcmd(0x38);       // 8位,2行,5X7点阵
	lcd_wcmd(0x0c);      //显示开,光标关,不闪烁
	lcd_wcmd(0x06);     //增量方式不移位,地址自动增加 
	lcd_wcmd(0x80);     //检测忙信号
	lcd_wcmd(0x01);       //清屏
	i=0;
	j=0;
	flag=0;   
	signal=0;    
}
void keyscan() 	 // 键盘扫描
{

	P3=0xfe; 	  //扫描第一行,后四位是行							
	if(P3!=0xfe)
	{
   		delay(20);	//延时去抖动
   		if(P3!=0xfe)		//第一行有键按下  
   		{
    		temp=P3&0xf0;	// 将列与1111进行与操作取列号
    		switch(temp)   // 根据与出来的列号进行选择
    		{
    			 case 0xe0:num=0;
       			 break;
     			 case 0xd0:num=1;
       			 break; 
     			 case 0xb0:num=2;
      			 break;
      			 case 0x70:num=3;
      			 break;
    		}
   		}
   		while(P3!=0xfe);				
   		if(flag==0)    // 没有按过符号键时输入继续赋给第一个数
   		{
   			a=a*10+table[num]; 
		}
		else           // 如果按过符号键,则赋给第二个数
		{
			b=b*10+table[num]; 
		}
			i=table[num];
			lcd_wdat(0x30+i);	//  显示屏写入数字
	}
	P3=0xfd; //扫描第二行
	if(P3!=0xfd)
	{
	   delay(5);
	   if(P3!=0xfd)  // 不等于初值,即代表该行有按键按下
	   {			// 第二行有数被按下
	    temp=P3&0xf0;	// 列与1111相与,判断按下的列
	    switch(temp)
	    {
	     case 0xe0:num=4;
	         break;
	      
	     case 0xd0:num=5;
	         break;
	      
	     case 0xb0:num=6;
	         break;
	      
	     case 0x70:num=7;
	         break;
	    }
	   }
	   while(P3!=0xfd);
	   if(flag==0)   //没有按过符号键
	    {
	     a=a*10+table[num]; 
	    }
	    else  //按过符号键
	    {
	     b=b*10+table[num]; 
	    }
	   i=table[num];
	   lcd_wdat(0x30+i); //写入显示屏
	}
	P3=0xfb; //扫描第三行	
	if(P3!=0xfb)
	{
	   delay(5);
	   if(P3!=0xfb)
	   {
	    temp=P3&0xf0;
	    switch(temp)
	    {
	     case 0xe0:num=8;
	         break;
	      
	     case 0xd0:num=9;
	         break;
	      
	     case 0xb0:num=10;
	         break;
	      
	     case 0x70:num=11;
	         break;
	    }
	   }
	   while(P3!=0xfb);     // 第三行的话不全是数字 
	   if(num==8||num==9)   //按下的是'8','9'
	   { 
	      if(flag==0) //没有按过符号键
	    {
	     a=a*10+table[num]; 
	    }
	    else     //按过符号键
	    {
	     b=b*10+table[num]; 
	    }
	   }//0-9用table
	   else if(num==10)   // 如果按下的是'+'
	   {
	    flag=1;
	    signal=1;   // signal为1表示按下的是加号
	   }
	   else if(num==11) //如果按下的是'-'
	   {
	    flag=1;
	    signal=2;  //2表示按下的是减号
	   }
	   i=table[num];
	   lcd_wdat(0x30+i);
	}
	P3=0xf7;    // 第四行都是符号
	if(P3!=0xf7)
	{
	   delay(5);
	   if(P3!=0xf7)
	   {
	    temp=P3&0xf0;     // 列和1111相与取列号
	    switch(temp)
	    {
	     case 0xe0:num=12;
	         break;
	      
	     case 0xd0:num=13;
	         break;
	      
	     case 0xb0:num=14;
	         break;
	      
	     case 0x70:num=15;
	         break;
	    }
	   }
	   while(P3!=0xf7);
	   switch(num)
	   {
	    case 12:{lcd_wdat(0x30+table[num]); flag=1;signal=3;}
	     break;
	    case 13:{lcd_wdat(0x30+table[num]); flag=1;signal=4;}                //运算符号用table   
	     break;
	    case 14:{lcd_wcmd(0x01);i=0;j=0;a=0;b=0;c=0;d=0;flag=0;signal=0;}    //按下的是"清零" ,0x01指令
	     break;
	    case 15:{j=1;
	       if(signal==1)	//+号
		   {
			   lcd_wcmd(0x80+0x40); //第二行	           
	           c=a+b;
			   lcd_wdat(0x3d);
	           while(c!=0)
		       {
			    if(c/10000!=0)
			    {
				lcd_wdat(0x30+c/10000);
				c=c%10000;
			   	lcd_wdat(0x30+c/1000);
				c=c%1000;
			   	lcd_wdat(0x30+c/100);
				c=c%100;
				lcd_wdat(0x30+c/10);
				c=c%10;
				lcd_wdat(0x30+c);
			    }  
				else if(c/1000!=0)
				{
				lcd_wdat(0x30+c/1000);
				c=c%1000;
			   	lcd_wdat(0x30+c/100);
				c=c%100;
				lcd_wdat(0x30+c/10);
				c=c%10;
				lcd_wdat(0x30+c);
				}
			    else if(c/100!=0)
			    {
			   	lcd_wdat(0x30+c/100);
				c=c%100;
				lcd_wdat(0x30+c/10);
				c=c%10;
				lcd_wdat(0x30+c);
			    }
	            else if(c/10!=0)
			    {
				lcd_wdat(0x30+c/10);
				c=c%10;
				lcd_wdat(0x30+c);	
			    }
				else if(c/10==0)
			    {
				lcd_wdat(0x30+c);
		        }
			   a=0;b=0;c=0;flag=0;signal=0;
	          }
		  }
	      else if(signal==2)	
		  {
		  	   lcd_wcmd(0x80+0x40); //第二行
	           if(a-b>0)
	           c=a-b;
	           else 
	           c=b-a;				 //c为绝对值
			   lcd_wdat(0x3d);     //写"="           	           
			   if(a-b<0)
	           lcd_wdat(0x2d);	    //小于0时为负号
			   while(c!=0)			//若c不为0
			   {
			    if(c/10000!=0)			 //则先从最高位写起
			    {
				lcd_wdat(0x30+c/10000);
				c=c%10000;
			   	lcd_wdat(0x30+c/1000);
				c=c%1000;
			   	lcd_wdat(0x30+c/100);
				c=c%100;
				lcd_wdat(0x30+c/10);
				c=c%10;
				lcd_wdat(0x30+c);
			    }  
	            else if(c/1000!=0)
			    {
			   	lcd_wdat(0x30+c/1000);	
				c=c%1000; 
			   	lcd_wdat(0x30+c/100);
				c=c%100;
				lcd_wdat(0x30+c/10);
				c=c%10;
				lcd_wdat(0x30+c);
			    }
			    else if(c/100!=0)
			    {
			   	lcd_wdat(0x30+c/100);
				c=c%100;
				lcd_wdat(0x30+c/10);
				c=c%10;
				lcd_wdat(0x30+c);
			    }
	            else if(c/10!=0)
				{
				lcd_wdat(0x30+c/10);
				c=c%10;
				lcd_wdat(0x30+c);	
				}
				else if(c/10==0)
				{
				lcd_wdat(0x30+c);
				}
			    a=0;b=0;c=0;flag=0;signal=0;            	          
	           }
	   	  }
	      else if(signal==3)  //乘号的情况
		  {
			   lcd_wcmd(0x80+0x40);
	           c=a*b;
			   lcd_wdat(0x3d); 
			   while(c!=0)
			   {    
			   if(c/10000!=0)
			    {
				lcd_wdat(0x30+c/10000);
				c=c%10000;
			   	lcd_wdat(0x30+c/1000);
				c=c%1000;
			   	lcd_wdat(0x30+c/100);
				c=c%100;
				lcd_wdat(0x30+c/10);
				c=c%10;
				lcd_wdat(0x30+c);
			    }  	          	
	            else if(c/1000!=0)
			    {
			   	lcd_wdat(0x30+c/1000);
				c=c%1000;
			   	lcd_wdat(0x30+c/100);
				c=c%100;
				lcd_wdat(0x30+c/10);
				c=c%10;
				lcd_wdat(0x30+c);
			    }
			    else if(c/100!=0)
			    {
			   	lcd_wdat(0x30+c/100);
				c=c%100;
				lcd_wdat(0x30+c/10);
				c=c%10;
				lcd_wdat(0x30+c);
			    }
	            else if(c/10!=0)
				{
				lcd_wdat(0x30+c/10);
				c=c%10;
				lcd_wdat(0x30+c);	
				}
				else if(c/10==0)
				{
				lcd_wdat(0x30+c);
				}
			    a=0;b=0;c=0;flag=0;signal=0;
	           }
	      }
	      else if(signal==4)	//除号的情况
		  {
			   lcd_wcmd(0x80+0x40);
	           lcd_wcmd(0x06);
			   if(b==0)
			   {
				 	i=0;
					while(error[i]!='\0')
					{
						lcd_wdat(error[i]); 
						i++;
					}
					a=0;b=0;c=0;flag=0;signal=0;
				}							//被除数为0显示error
				else if((a%b==0)&&(b!=0))	// 整除时输出c
				{
			    	lcd_wdat(0x3d);                              
	            	c=a/b;
					if(a/b<=0)
					{
	             	lcd_wdat(0x30); 
	            	}
				 while(c!=0)
			     {
				 if(c/10000!=0)
			    {
				lcd_wdat(0x30+c/10000);
				c=c%10000;
			   	lcd_wdat(0x30+c/1000);
				c=c%1000;
			   	lcd_wdat(0x30+c/100);
				c=c%100;
				lcd_wdat(0x30+c/10);
				c=c%10;
				lcd_wdat(0x30+c);
			    }  
				  else if(c/1000!=0)
			    {
			   	lcd_wdat(0x30+c/1000);
				c=c%1000;
			   	lcd_wdat(0x30+c/100);
				c=c%100;
				lcd_wdat(0x30+c/10);
				c=c%10;
				lcd_wdat(0x30+c);
			    }
			     else if(c/100!=0)
			     {
			   	 lcd_wdat(0x30+c/100);
				 c=c%100;
				 lcd_wdat(0x30+c/10);
				 c=c%10;
				 lcd_wdat(0x30+c);
			     }
	             else if(c/10!=0)
				 {
				 lcd_wdat(0x30+c/10);
				 c=c%10;
				 lcd_wdat(0x30+c);	
				 }
				 else if(c/10==0)
				 {
				 lcd_wdat(0x30+c);
				 }
			     a=0;b=0;c=0;flag=0;signal=0;
	            }
			   }
			   else if((a%b!=0)&&(b!=0))	//若不整除输出c```d
			   {
					c=a/b;
					d=a%b;
					lcd_wdat(0x3d);  
					if(a/b<=0)
					{
	             	lcd_wdat(0x30); 
	            	}
				while(c!=0)
			    { 
				 if(c/10000!=0)
			    {
				lcd_wdat(0x30+c/10000);
				c=c%10000;
			   	lcd_wdat(0x30+c/1000);
				c=c%1000;
			   	lcd_wdat(0x30+c/100);
				c=c%100;
				lcd_wdat(0x30+c/10);
				c=c%10;
				lcd_wdat(0x30+c);
			    }  
				else if(c/1000!=0)
			    {
			   	lcd_wdat(0x30+c/1000);
				c=c%1000;
			   	lcd_wdat(0x30+c/100);
				c=c%100;
				lcd_wdat(0x30+c/10);
				c=c%10;
				lcd_wdat(0x30+c);
			    }                           
			   	else if(c/100!=0)
			    {
			   	lcd_wdat(0x30+c/100);
				c=c%100;
				lcd_wdat(0x30+c/10);
				c=c%10;
				lcd_wdat(0x30+c);
			    }
	            else if(c/10!=0)
			    {
				lcd_wdat(0x30+c/10);
				c=c%10;
				lcd_wdat(0x30+c);	
			    }
				else if(c/10==0)
			    {
				lcd_wdat(0x30+c);
			    }
			    a=0;b=0;c=0;flag=0;signal=0;
	           }
					lcd_wdat(0x2e);
					lcd_wdat(0x2e);
					lcd_wdat(0x2e);
				if(d/10000!=0)
			    {
				lcd_wdat(0x30+d/10000);
				d=d%10000;
				lcd_wdat(0x30+d/1000);
				d=d%1000;
			   	lcd_wdat(0x30+d/100);
				d=d%100;
				lcd_wdat(0x30+d/10);
				d=d%10;
				lcd_wdat(0x30+d);
			    }
				else if(d/1000!=0)
			    {
				lcd_wdat(0x30+d/1000);
				d=d%1000;
			   	lcd_wdat(0x30+d/100);
				d=d%100;
				lcd_wdat(0x30+d/10);
				d=d%10;
				lcd_wdat(0x30+d);
			    }
				else if(d/100!=0)
			    {
			   	lcd_wdat(0x30+d/100);
				d=d%100;
				lcd_wdat(0x30+d/10);
				d=d%10;
				lcd_wdat(0x30+d);
			    }
	            else if(d/10!=0)
			    {
				lcd_wdat(0x30+d/10);
				d=d%10;
				lcd_wdat(0x30+d);	
				}
				else if(d/10==0)
				{
				lcd_wdat(0x30+d);	
	            }
	           }
	      }
	     break;
	   }
	}
 }
 }

main()	// 定义主程序
{
	init();	//初始化子程序
	while(1)	  //一直循环
	{
   		keyscan();  // 键盘扫描函数扫描输入
	}
}				


【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。