基于51单片机的简易计算器的实现

目录

一、硬件简介

1、LCD1602液晶显示器介绍

(1)LCD1602的组成

(2)各引脚功能介绍

(3)DDRAM

 2、矩阵按键介绍

(1)矩阵按键的优点:

 (2)原理:

 (3)检测方法:

(4)矩阵按键实物图

 3、开发板原理图

 二、算法设计

 三、编程实现

1、主函数部分:

2、矩阵按键扫描函数


一、硬件简介

        本次的设计利用了两个外设模块,一个是利用了4*4的矩阵按键,另一个则是利用了LCD1602显示屏进行显示。

1、LCD1602液晶显示器介绍

(1)LCD1602的组成

        1602 液晶也叫 1602 字符型液晶,它能显示 2 行字符信息,每行又能显示 16 个字符。它是一种专门用来显示字母、数字、符号的点阵型液晶模块。它是由若 干个 5x7 或者 5x10 的点阵字符位组成,每个点阵字符位都可以用显示一个字符, 每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作 用,正因为如此,所以它不能很好的显示图片。其实物图如下所示

基于51单片机的简易计算器的实现

(2)各引脚功能介绍

         上图中可以看到有16个管脚孔,从左到右的编号顺序是1-16,其功能定义如下:

基于51单片机的简易计算器的实现

(3)DDRAM

         在 LCD1602 内部含有 80 个字节的 DDRAM,它是用来寄存显示字符的。其地址 和屏幕的对应关系如下表:

基于51单片机的简易计算器的实现

 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)矩阵按键实物图

基于51单片机的简易计算器的实现

 3、开发板原理图

 基于51单片机的简易计算器的实现

其中矩阵按键与LCD1602对应的模块分别为:

基于51单片机的简易计算器的实现基于51单片机的简易计算器的实现

在本次实验中矩阵键盘各位置代表的数值或符号:

                | 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;
}

上一篇:002、Fiddler实现弱网测试


下一篇:RTOS笔记(2)----- STM32使用HAL库自带延时函数HAL_Delay时存在1ms误差