单片机原理及应用课程设计实验报告基于89C52的液晶计算器.docx
《单片机原理及应用课程设计实验报告基于89C52的液晶计算器.docx》由会员分享,可在线阅读,更多相关《单片机原理及应用课程设计实验报告基于89C52的液晶计算器.docx(25页珍藏版)》请在冰豆网上搜索。
单片机原理及应用课程设计实验报告基于89C52的液晶计算器
《MCS-51单片机原理及应用》
课程设计实验报告
题目:
基于89C52的液晶计算器
学校:
学院:
专业班级:
学号:
学生姓名:
指导老师:
目录·····················································2
摘要·····················································3
Abstract·················································4
一、设计任务·············································4
二、正文·················································4
第1节、1602液晶与矩阵键盘概述··························4
1.1、1602液晶的介绍以及使用方法·················4
1.2、矩阵键盘的工作原理··························6
第2节、设计方案辨析·····································8
第3节、硬件电路的设计···································8
3.1矩阵键盘电路·································8
3.21602液晶显示电路····························10
第4节、设计心得·········································11
三、参考文献·············································11
四、程序清单·············································12
摘要
本次课程设计基于89C52单片机,用一个1602与矩阵键盘来制作成一个液晶计算器。
可以完成计算器的键盘输入,进行加、减、乘六位数范围内的基本运算。
,并在LCD上显示相应的结果。
设计电路采用AT89C51单片机为主要控制电路,利用MM74C922作为计算器3*4键盘的扫描IC读取键盘上的输入。
显示采用字符LCD静态显示。
软件方面使用C语言编程,并用PROTUES仿真。
关键词:
计算器;单片机;LCD
Abstract
Thiscoursedesignbasedonthe89C52singlechip,witha1602andmatrixkeyboardtomakeintoaliquidcrystalcalculator.Cancompletecalculatorkeyboardinput,add,subtract,multiplysixfigureswithinthescopeofthebasicoperations.,andisdisplayedonLCDandthecorrespondingresults.CircuitdesignAT89C51microcontrollerasthemaincontrolcircuit,useasacalculatorMM74C9223*4keyboardscanreadkeyboardinputoftheIC.TheLCDdisplaycharactersstaticdisplay.ThesoftwareusedintheCprogramminglanguage,andPROTUESsimulation.
Keyords:
Calculator;Singlechipmicrocomputer;LCD
一、设计任务
1、由于设计的是简单的计算器,可以进行四则运算,为了较好的显示效果,采用LCD显示数据和结果。
2、另外键盘包括数字键、符号键、等号键,故只需12个键即可,设计中采用集成的计算键盘。
3、执行过程:
开机显示零,等待键入数值,当键入数字,通过LCD显示出来,当键入+、-、×运算符,计算机在内部执行数值转换盒存储,并等待再次键入数值,当再键入数值后将显示键入的数值,按等号就会在LCD上输出运算结果。
4、错误显示:
当计算器执行过程中有错误时,会在LCD上显示相应的提示,如:
当输入的数值或计算结果大于计算器的表示范围时,计算器会在LCD上提示溢出。
二、正文
第1节、1602液晶与矩阵键盘概述
1.1、1602液晶的介绍以及使用方法
1602液晶是工业字符型液晶,能够同时显示16x02即32个字符(16列2行)。
具有显示质量高、数字式接口、功耗低、体积小、重量轻等优点。
液晶显示的原理是利用液晶的物理特性,通过电压对其显示区域进行控制,有电就有显示,这样即可以显示出图形。
液晶显示的分类方法有很多种,通常可按其显示方式分为段式、字符式、点阵式等。
除了黑白显示外,液晶显示器还有多灰度有彩色显示等。
如果根据驱动方式来分,可以分为静态驱动(Static)、单纯矩阵驱动(SimpleMatrix)和主动矩阵驱动(ActiveMatrix)三种。
点阵图形式液晶由M×N个显示单元组成,假设LCD显示屏有64行,每行有128列,每8列对应1字节的8位,即每行由16字节,共16×8=128个点组成,屏上64×16个显示单元与显示RAM区1024字节相对应,每一字节的内容和显示屏上相应位置的亮暗对应。
例如屏的第一行的亮暗由RAM区的000H——00FH的16字节的内容决定,当(000H)=FFH时,则屏幕的左上角显示一条短亮线,长度为8个点;当(3FFH)=FFH时,则屏幕的右下角显示一条短亮线;当(000H)=FFH,(001H)=00H,(002H)=00H,……(00EH)=00H,(00FH)=00H时,则在屏幕的顶部显示一条由8段亮线和8条暗线组成的虚线。
这就是LCD显示的基本原理。
1602LCD采用标准的14脚(无背光)或16脚(带背光)接口,各引脚接口说明如下表所示:
编号
符号
引脚说明
编号
符号
引脚说明
1
VSS
电源地
9
D2
数据
2
VDD
电源正极
10
D3
数据
3
VL
液晶显示偏压
11
D4
数据
4
RS
数据/命令选择
12
D5
数据
5
R/W
读/写选择
13
D6
数据
6
E
使能信号
14
D7
数据
7
D0
数据
15
BLA
背光源正极
8
D1
数据
16
BLK
背光源负极
1602液晶模块内部的控制器共有11条控制指令,如下表所示:
序号
指令
RS
R/W
D7
D6
D5
D4
D3
D2
D1
D0
1
清显示
0
0
0
0
0
0
0
0
0
1
2
光标返回
0
0
0
0
0
0
0
0
1
*
3
置输入模式
0
0
0
0
0
0
0
1
I/D
S
4
显示开/关控制
0
0
0
0
0
0
1
D
C
B
5
光标或字符移位
0
0
0
0
0
1
S/C
R/L
*
*
6
置功能
0
0
0
0
1
DL
N
F
*
*
7
置字符发生存贮器地址
0
0
0
1
字符发生存贮器地址
8
置数据存贮器地址
0
0
1
显示数据存贮器地址
9
读忙标志或地址
0
1
BF
计数器地址
10
写数到CGRAM或DDRAM)
1
0
要写的数据内容
11
从CGRAM或DDRAM读数
1
1
读出的数据内容
1602LCD的一般初始化(复位)过程:
延时15mS,写指令38H(不检测忙信号);延时5mS,写指令38H(不检测忙信号);延时5mS,写指令38H(不检测忙信号);以后每次写指令、读/写数据操作均需要检测忙信号。
写指令38H:
显示模式设置;写指令08H:
显示关闭;写指令01H:
显示清屏;写指令06H:
显示光标移动设置;写指令0CH:
显示开及光标设置。
1.2、矩阵键盘的工作原理
在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式。
在矩阵式键盘中,每条水平线和垂直线在交叉处不直接连通,而是通过一个按键加以连接。
这样,一个端口(如P1口)就可以构成4*4=16个按键,比之直接将端口线用于键盘多出了一倍,而且线数越多,区别越明显,比如再多加一条线就可以构成20键的键盘,而直接用端口线则只能多出一键(9键)。
由此可见,在需要的键数比较多时,采用矩阵法来做键盘是合理的。
矩阵式结构的键盘显然比直接法要复杂一些,识别也要复杂一些,上图中,列线通过电阻接正电源,并将行线所接的单片机的I/O口作为输出端,而列线所接的I/O口则作为输入。
这样,当按键没有按下时,所有的输入端都是高电平,代表无键按下。
行线输出是低电平,一旦有键按下,则输入线就会被拉低,这样,通过读入输入线的状态就可得知是否有键按下了。
具体的识别方法如下所述。
确定矩阵式键盘上何键被按下介绍一种“行扫描法”。
行扫描法行扫描法又称为逐行(或列)扫描查询法,是一种最常用的按键识别方法,介绍过程如下:
1、判断键盘中有无键按下将全部行线Y0-Y3置低电平,然后检测列线的状态。
只要有一列的电平为低,则表示键盘中有键被按下,而且闭合的键位于低电平线与4根行线相交叉的4个按键之中。
若所有列线均为高电平,则键盘中无键按下。
2、判断闭合键所在的位置在确认有键按下后,即可进入确定具体闭合键的过程。
其方法是:
依次将行线置为低电平,即在置某根行线为低电平时,其它线为高电平。
在确定某根行线位置为低电平后,再逐行检测各列线的电平状态。
若某列为低,则该列线与置为低电平的行线交叉处的按键就是闭合的按键。
下面给出一个具体的例子:
8031单片机的P1口用作键盘I/O口,键盘的列线接到P1口的低4位,键盘的行线接到P1口的高4位。
列线P1.0-P1.3分别接有4个上拉电阻到正电源+5V,并把列线P1.0-P1.3设置为输入线,行线P1.4-P.17设置为输出线。
4根行线和4根列线形成16个相交点。
1、检测当前是否有键被按下。
检测的方法是P1.4-P1.7输出全“0”,读取P1.0-P1.3的状态,若P1.0-P1.3为全“1”,则无键闭合,否则有键闭合。
2、去除键抖动。
当检测到有键按下后,延时一段时间再做下一步的检测判断。
3、若有键被按下,应识别出是哪一个键闭合。
方法是对键盘的行线进行扫描。
P1.4-P1.7按下述4种组合依次输出:
P1.71110
P1.61101
P1.51011
P1.40111
在每组行输出时读取P1.0-P1.3,若全为“1”,则表示为“0”这一行没有键闭合,否则有键闭合。
由此得到闭合键的行值和列值,然后可采用计算法或查表法将闭合键的行值和列值转换成所定义的键值
4、为了保证键每闭合一次CPU仅作一次处理,必须却除键释放时的抖动。
键盘扫描程序:
uchartemp;
P1=0xfd;
temp=P1;
temp=temp&0xf0;
if(temp!
=0xf0)
{
delay20ms();
temp=P1;
temp=temp&0xf0;
if(temp!
=0xf0)
{
temp=P1;
switch(temp)
{
case0xed:
key1=4;break;
case0xdd:
key1=5;break;
case0xbd:
key1=6;break;
case0x7d:
key1=7;break;
}
while(temp!
=0xf0)
{
temp=P1;
temp=temp&0xf0;
}
}
}
第2节、设计方案的辨析
液晶显示与数码管显示:
(1)、通过1602液晶来显示信号,通过让单片机扫描按键并处理显示,进而完成输入数字及运算符来完成计算器的基本功能,液晶可以显示的字符量更大,相对于数码管更加方便且美观。
(2)、通过数码管来显示输出的结果,我们要控制数码管的位选来让每个数码管相应显示各位数字。
上述方案比较得:
液晶相对于数码管更加方便且表现效果更好,而且还可以显示更多内容。
第3节、硬件电路的设计
硬件电路的设计大致步骤如下:
3.1矩阵键盘电路
键盘扫描方法:
行线p1.0^p1.3为输入线,列线p1.4^p1.7为输出线。
一开始单片机将行线(p1.0^p1.3)全部输出低电平,此时读入线数据,若列线全部为高电平则没有键按下,当列线有出线低电平时调用延时程序以此来去除键抖动,延时完成后再判断是否有低电平,如果此时读入列线数据还是有低电平,则说明确实有键按下。
最后一步确定键值。
在键盘矩阵扫描时,首先检查有否键按动。
若无键按动,则清零一次键解读标志位就返回;若有键按下,则再查询键解读标志位是逻辑0还是逻辑1。
如果是逻辑1,表明本次按键已解读过,可直接从键扫描处理程序中返回;如果是逻辑0,说明本次按键尚未解读过,则启用消抖动延时。
经消抖动延时后即查询键盘矩阵输入口线的各端口是否有拉低。
若一个端口也没被拉低,则说明本次按键无效,那可能是某种干扰引起的“抖动”,立即从键扫描处理程序中返回;若查询到其中之一端口的电平被拉低了,则表明本次按键盘是有效的,将跳转查询与之相交的那个扫描有效输出口线,进而确定具体是哪一个键按下,并跳转赋予其相应的解释处理。
解释处理后,置键解读标志位为逻辑1再返回,即完成一次键盘矩阵的扫描解读。
不管键盘矩阵有多少个键,其扫描确定一个具体键所需位查询的总次数S不会大于行数x与列数y之和;但也不少于2次,即2≤S≤x+y。
·矩阵式键盘识别硬件电路原理图如下:
第一步:
在“单片机系统”区域中,把单片机的P1.0-P1.7端口通过8联拨动拨码开关JP3连接到“4×4行列式键盘”区域中的M1-M4,N1-N4端口上。
第二步:
在“单片机系统”区域中,把单片机的P0.0-P0.7端口连接到“静态数码显示模块”区域中的任何一个a-h端口上;要求:
P0.0对应着a,P0.1对应着b,……,P0.7对应着h。
·软件设计程序流程图如下:
P3=FFH,P3.0=0
P3=FFH,P3.2=0
有键按下吗?
有键按下吗?
延时10ms
延时10ms
真的有键按下吗?
真的有键按下吗?
根据当前状况识别按键
根据当前状况识别按键
P3=FFH,P3.1=0
P3=FFH,P3.3=0
有键按下吗?
有键按下吗?
延时10ms
延时10ms
真的有键按下吗?
真的有键按下吗?
根据当前状况识别按键
根据当前状况识别按键
3.2、1602显示电路
·1602显示硬件电路如下图所示:
此图是1602的引脚链接图,不过本图上有一个错误,就是BLK,BLA接反了,本来BLK应该接VCC,BLA接GND,本图接错了,这也是我在学习中的一点心得体会吧,尽信书不如无书。
·软件程序流程图如下图所示:
第4节、设计心得
一周的单片机课程设计终于顺利完成了,其中包含着快乐,也有辛酸。
我们选的设计题目是“液晶计算器”,大家都觉得这个题目是比较简单的。
其实不然,做了之后,发现设计电路虽然简单,但我们认为它真正困难的地方是程序设计,不过在我们同心努力下最终完成了。
我们刚选该题目时,真的是一头雾水,硬件电路不知如何下手,更何谈解决程序那块,因为我们所学的都是单片机方面的理论知识,应用到实践中去还比较少。
不过,我们四人也没偷下懒,迅速分工去查阅和收集资料。
我们去了图书馆借一些参考书,上网找一些相关资料,并且请教指导老师。
通过不断努力,终于把液晶计算器的思路和模型定了下来并开始分一个人去焊接硬件电路,剩下的去整理和修改程序。
在完成单片机课程设计后,我们发现我们还有许多不足,所学到的知识还远远不够,以至于还有一些功能不能被动完成。
但通过学习这一次实践,增强了我们的动手能力,提高和巩固了单片机方面的知识,特别是软件方面。
从中增强了我们的团队合作精神,并让我们认识到把理论应用到实践中去是多么重要。
三、参考文献
Mcu-51单片机原理及应用秦实宏徐春晖华中科技大学出版社
自动控制原理胡寿松科学出版社
51单片机C语言教程郭天祥电子工业出版社
四、程序清单
#include
#defineucharunsignedchar
#defineuintunsignedint
uintsum;
uintm,n,k,p;
uintkey1;
sbitP14=P1^4;//键盘定义I/O口
sbitP15=P1^5;
sbitP16=P1^6;
sbitP17=P1^7;
uintd[10]={0,1,2,3,4,5,6,7,8,9};
uinta[4]={0,0,0,0};//暂存输入数字的数组
uintb[4]={0,0,0,0};//暂存结果的数组
voidkey_deal(uintkey1);
voidkeyscan();
voidshow();
voidlcd_write_com(ucharcom);
voidlcd_write_dat(uchardat);
voidinit_lcd();
voiddelay1(uchart);
sbitlcdrs=P2^6;//定义1602的I/O口
sbitrw=P2^5;
sbitlcden=P2^7;
voiddelay20ms()
{
uchari,j;
for(i=0;i<100;i++)
for(j=0;j<60;j++);
}
voidmain()//主函数
{
init_lcd();//液晶初始化
while
(1)
{
key1=0;//扫描全键盘
keyscan();//键盘扫描
key_deal(key1);//键盘处理
show();//显示计算结果
}
}
voidshow()
{
uchari,temp;
if(sum>1000&&sum<6555)//此处对计算结果进行判断是否大于1000
{
lcd_write_com(0x80+0x04);//如果大于1000,就在结果显示栏目全部显示E
for(i=0;i<4;i++)//通过FOR循环,使一排四个为E
{
temp=0x45;//通过查ASCII,知道大写字母E的ASCII为0x45
lcd_write_dat(temp);
delay20ms();
}
}
else
{
lcd_write_com(0x80+0x44);//在LCD上面第二排第五个开始显示数组
for(i=0;i<4;i++)
{
temp=(a[i]+'0');//对数据进行强制转换成液晶8位的字符型
lcd_write_dat(temp);
delay20ms();
}
lcd_write_com(0x80+0x04);//在LCD上面第一排第五个开始显示数组b[i]中的字符
for(i=0;i<4;i++)
{
temp=(b[i]+'0');//对数据进行强制转换成液晶8位的字符型
lcd_write_dat(temp);
delay20ms();
}
}
}
/***********************************************************
键盘处理区间
***********************************************************/
voidkey_deal(uintkey1)//键盘扫描
{
if(key1!
=0)
{
if(key1<10)//存储数字
{
a[0]=a[1];
a[1]=a[2];
a[2]=a[3];
a[3]=key1;
}
if(key1==10)//加法运算
{
m=a[0]*1000+a[1]*100+a[2]*10+a[3];
b[0]=d[m/1000];//千位
b[1]=d[m%1000/100];//百位
b[2]=d[m%100/10];//十位
b[3]=d[m%10];//个位
a[3]=0,a[2]=0,a[1]=0,a[0]=0;//取完清零
p=1;//加法的标志位
}
if(key1==11)//乘法运算
{
m=a[0]*1000+a[1]*100+a[2]*10+a[3];
b[0]=d[m/1000];
b[1]=d[m%1000/100];
b[2]=d[m%100/10];
b[3]=d[m%10];
a[3]=0,a[2]=0,a[1]=0,a[0]=0;//取完清零
p=2;//乘法的标志位
}
if(key1==12)//减法运算
{
m=a[0]*1000+a[1]*100+a[2]*10+a[3];
b[0]=d[m/1000];
b[1]=d[m%1000/100];
b[2]=d[m%100/10];
b[3]=d[m%10];
a[3]=0,a[2]=0,a[1]=0,a[0]=0;//取完清零
p=3;//减法的标志位
}
if(key1==14)//等号运算
{
n=a[0]*1000+a[1]*100+a[2]*10+a[3];//将第二个数填入
if(p==1)
sum=n+m;
if(p==2)
sum=n*m;
if(p==3)
sum=m-n;
/*if(sum<0)
{
sum=-sum;
lcd_write_com(0x80+0x00);
lcd_write_dat(0x2d);
delay20ms();
}*/
b[0]=d[sum%10000/1000];
b[1]=d[sum%1000/10