单片机开发之LCD1602显示实验

简介: 本文主要介绍了单片机开发之LCD1602显示的过程


一、实验题目
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 文件:

image.png

图1:实验原理图

  1. 编写源程序,将其保存为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”仿真器。

  1. 构造(Build)工程LCD1602_self.uV2。如果输入有误进行修改,直至构造正确,生成可执行程序LCD1602_self.hex 为止,为AT89C51 设置可执行程序LCD1602_self.hex。
  2. 运行程序,点击按键输入数据与运算符,计算,观察计算结果,并验证其是否正确,输入过程中,按“清除按键”观察结果,重新输入数据计算并验证。

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

image.png

图2:加法测试

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

image.png

图3:减法测试

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

image.png

图4:负数减法测试

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

image.png

图5:乘法测试

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

image.png

图6:除法测试

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

image.png

图7:带余数的除法测试

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

image.png

图8:除法为0报错

8) 清零,如图9:

image.png

图9:清零

四、实验流程图

image.png

图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();  // 键盘扫描函数扫描输入
}

}

目录
相关文章
|
6月前
|
物联网
STC51单片机-实验开发装置仿真-物联网应用系统设计
STC51单片机-实验开发装置仿真-物联网应用系统设计
132 0
|
3月前
【51单片机】在LCD1602上显示时间:包含按键进行校准时间+闹钟功能:按键设置闹钟响铃时间,以及响铃的时间长度
【51单片机】在LCD1602上显示时间:包含按键进行校准时间+闹钟功能:按键设置闹钟响铃时间,以及响铃的时间长度
|
3月前
|
C语言
【51单片机】LCD1602显示字符串,时间、时间+按键校准、秒表计时的功能代码。
【51单片机】LCD1602显示字符串,时间、时间+按键校准、秒表计时的功能代码。
|
5月前
技术心得记录:单片机开发过程中使用结构体简化程序
技术心得记录:单片机开发过程中使用结构体简化程序
28 0
|
6月前
|
内存技术
模块化编程+LCD1602调试工具——“51单片机”
模块化编程+LCD1602调试工具——“51单片机”
模块化编程+LCD1602调试工具——“51单片机”
|
6月前
|
传感器
51单片机矩阵键盘超详解!(内含LCD1602代码)
51单片机矩阵键盘超详解!(内含LCD1602代码)
79 0
|
6月前
|
数据可视化 API
【51单片机】LCD1602(可视化液晶屏)调试工具的使用(6)
【51单片机】LCD1602(可视化液晶屏)调试工具的使用(6)
|
6月前
|
IDE 开发工具 C++
【51单片机】开发板&开发软件(Keil5&STC-ISP)简介&下载安装破译传送门(1)
【51单片机】开发板&开发软件(Keil5&STC-ISP)简介&下载安装破译传送门(1)
|
存储 芯片
51单片机--LCD1602
51单片机--LCD1602
330 1
|
6月前
|
缓存 编译器 程序员
嵌入式开发环境Vscode开发STM32单片机程序
嵌入式开发环境Vscode开发STM32单片机程序
151 0