目录
一、硬件简介
本次的设计利用了两个外设模块,一个是利用了4*4的矩阵按键,另一个则是利用了LCD1602显示屏进行显示。
1、LCD1602液晶显示器介绍
(1)LCD1602的组成
1602 液晶也叫 1602 字符型液晶,它能显示 2 行字符信息,每行又能显示 16 个字符。它是一种专门用来显示字母、数字、符号的点阵型液晶模块。它是由若 干个 5x7 或者 5x10 的点阵字符位组成,每个点阵字符位都可以用显示一个字符, 每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作 用,正因为如此,所以它不能很好的显示图片。其实物图如下所示
(2)各引脚功能介绍
上图中可以看到有16个管脚孔,从左到右的编号顺序是1-16,其功能定义如下:
(3)DDRAM
在 LCD1602 内部含有 80 个字节的 DDRAM,它是用来寄存显示字符的。其地址 和屏幕的对应关系如下表:
2、矩阵按键介绍
(1)矩阵按键的优点:
独立键盘与单片机连接时,每一个按键都需要单片机的一个 I/O 口,若某 单片机系统需较多按键,如果用独立按键便会占用过多的 I/O 口资源。单片机 系统中 I/O 口资源往往比较宝贵,当用到多个按键时为了减少 I/O 口引脚,所以就引 入了矩阵键盘。
(2)原理:
开发板上将16个按键排成 4 行 4 列,第一行将每个按键的一端连接在一起构成行线,第一列将每 个按键的另一端连接在一起构成列线,这样便一共有 4 行 4 列共 8 根线,我们将 这 8 根线连接到单片机的 8 个 I/O 口上,通过程序扫描键盘就可检测 16 个 键。用这种方法我们也可实现 3 行 3 列 9 个键、 5 行 5 列 25 个键、 6 行 6 列 36个键甚至更多。
(3)检测方法:
矩阵键盘两端都与单片机 I/O 口相连, 因此在检测时需编程通过单片机 I/O 口送出低电平。检测方法有多种,最常用的是行列扫描和线翻转法。
行列扫描法检测时,先送一列为低电平,其余几列全为高电平(此时我们确 定了列数),然后立即轮流检测一次各行是否有低电平,若检测到某一行为低电 平(这时我们又确定了行数),则我们便可确认当前被按下的键是哪一行哪一列 的,用同样方*流送各列一次低电平,再轮流检测一次各行是否变为低电平, 这样即可检测完所有的按键,当有键被按下时便可判断出按下的键是哪一个键。 当然我们也可以将行线置低电平,扫描列是否有低电平。从而达到整个键盘的检 测。
线翻转法,就是使所有行线为低电平时,检测所有列线是否有低电平,如果 有,就记录列线值;然后再翻转,使所有列线都为低电平,检测所有行线的值, 由于有按键按下,行线的值也会有变化,记录行线的值。从而就可以检测到全部 按键。 矩阵键盘也少不了按键消抖的环节,本章实验中采用的是行列扫描法来检测哪个按键按下。
(4)矩阵按键实物图
3、开发板原理图
其中矩阵按键与LCD1602对应的模块分别为:
在本次实验中矩阵键盘各位置代表的数值或符号:
| 1 | | 2 | | 3 | | 4 |
| 5 | | 6 | | 7 | | 8 |
| 9 | | 0 | | + | | - |
| * | | / | | = |
二、算法设计
本次设计采用遍历的思想,将输入的数据和符号分别存储在两个不同的数组,其中为了实现优先级计算,即先计算乘除法再计算加减法,所以本实验采用两次遍历思想:第一次遍历找出乘除符号和其对应的两个数存入两个不同的数组,并对它们进行优先计算,计算完成后,则进行第二次遍历,计算加减法,把数据和运算符存在两个不同的数组,按照从头到尾的顺序依次对它们相加减,最后数组的最后一个元素则为输出的结果。
注:本计算器可以计算整数型加减乘除运算,
并且符合加减乘除的优先率,但不能计算浮点型。
三、编程实现
1、主函数部分:
#include <REGX51.H>
#include "LCD1602.h"
#include "MatrixKey.h"
/***********************************************
51单片机大作业 —— 基于AT89C51的简易计算器
作者:智能医学工程2002班 龙思成
| 1 | | 2 | | 3 | | 4 |
| 5 | | 6 | | 7 | | 8 |
| 9 | | 0 | | + | | - |
| * | | / | | = |
LCD屏显示:
******************************************
* INPUT:输入的数值 OP:输入的运算符 *
* OUTPUT:计算结果 *
******************************************
注意:本计算器可以计算整数型加减乘除运算,
并且符合加减乘除的优先率,但不能计算浮点型。
***********************************************/
int shuju[5]; //存放数据的数组
char yunsuan[5]; //存放运算符的数组
int keynum; //返回矩阵键盘的简直
int dat;
int j=0;
int i=0;
int jj;
int ii;
int j3=0;
int i3=0;
int yshuju[5]; //存储*与/对应的数据
char youxian[5]; //存储 *与/运算符的数组
void result() //结果显示函数
{
LCD_ShowString(1,16," ");
if(shuju[jj]<=9){LCD_ShowNum(2,8,shuju[jj],1);}
if(shuju[jj]>9&&shuju[jj]<=99){LCD_ShowNum(2,8,shuju[jj],2);}
if(shuju[jj]>99&&shuju[jj]<=999){LCD_ShowNum(2,8,shuju[jj],3);}
}
void showdata() //显示输入的数据
{
if(dat<=9){LCD_ShowNum(1,7,dat,1);}
if(dat>9&&dat<=99){LCD_ShowNum(1,7,dat,2);}
if(dat>99&&dat<=999){LCD_ShowNum(1,7,dat,3);}
}
void main()
{
LCD_Init();
LCD_ShowString(1,1,"INPUT:");
LCD_ShowString(1,13,"OP:");
LCD_ShowString(2,1,"OUTPUT:");
while(1)
{
keynum=MatrixKey(); //返回矩阵键盘的键值
if(keynum)
{
if(keynum<=10) //输入的数据处理,若超过两位则左移
{
dat*=10;
dat+=keynum%10;
showdata();
}
if(keynum>10)
{
shuju[j]=dat;
j++;
dat=0;
LCD_ShowString(1,7," ");
if(keynum==11){yunsuan[i]='+';LCD_ShowString(1,16,"+");i++;}
if(keynum==12){yunsuan[i]='-';LCD_ShowString(1,16,"-");i++;}
if(keynum==13){yunsuan[i]='*';LCD_ShowString(1,16,"*");i++;}
if(keynum==14){yunsuan[i]='/';LCD_ShowString(1,16,"/");i++;}
if(keynum==15)
{
for(ii=0,jj=1;jj<j;jj++) //优先遍历,找出*与/对应的数组元素,并优先计算
{
if(yunsuan[ii]=='*'|yunsuan[ii]=='/')
{
youxian[i3]=yunsuan[ii];
yshuju[j3]=shuju[jj];
if(youxian[i3]=='*')
{
yshuju[j3]=shuju[jj]*shuju[jj-1];
shuju[jj]=yshuju[j3];
shuju[jj-1]=0;
}
if(youxian[i3]=='/')
{
yshuju[j3]=shuju[jj-1]/shuju[jj];
shuju[jj]=yshuju[j3];
shuju[jj-1]=0;
}
yunsuan[ii]='+';
}
ii++;
}
for(ii=0,jj=1;jj<j;jj++) //第二次遍历,计算+ -法
{
if(yunsuan[ii]=='+')
{
shuju[jj]=shuju[jj]+shuju[jj-1];
result();
}
if(yunsuan[ii]=='-')
{
shuju[jj]=shuju[jj-1]-shuju[jj];
result();
}
if(yunsuan[ii]=='*')
{
shuju[jj]=shuju[jj]*shuju[jj-1];
result();
}
if(yunsuan[ii]=='/')
{
shuju[jj]=shuju[jj-1]/shuju[jj];
result();
}
ii++;
}
}
}
}
}
}
2、矩阵按键扫描函数
#include <REGX52.H>
#include "delay.h"
unsigned char MatrixKey()
{
unsigned char KeyNumber=0;
P1=0xFF;
P1_3=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=1;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=5;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=9;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=13;}
P1=0xFF;
P1_2=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=2;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=6;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=10;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=14;}
P1=0xFF;
P1_1=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=3;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=7;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=11;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=15;}
P1=0xFF;
P1_0=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=4;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=8;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=12;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=16;}
return KeyNumber;
}