目录
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(); // 键盘扫描函数扫描输入
- }
- }
初学单片机,可能存在错误之处,还请各位不吝赐教。
受于文本原因,本文相关实验工程无法展示出来,现已将资源上传,可自行下载。