注:本课题的记忆功能未能全部完成,只完成了部分
实 习 报 告
实习课程名称: 计算机硬件实习 实 习 题 目: 简易计算器设计
一、 实习任务书 单片机实习任务书 一、设计题目 简易计算器设计 二、设计背景 计算器是现代人发明的可以进行数字运算的电子机器。现代的电子计算器能进行数学运算的手持电子机器,拥有集成电路芯片,但结构比电脑简单得多,可以说是第一代的电子计算机(电脑),且功能也较弱,但较为方便与廉价,可广泛运用于商业交易中,是必备的办公用品之一。
三、设计内容及目标 设计内容: 1、 利用键盘及数码管或者LCD1602作为计算器的输入及显示模块; 2、 2、能进行10以内的加、减、乘、除的基本运算;按键有0~9,“±*/=”。 3、有清零“CR"按键; 4、有记忆功能键“M+”“RM”“M-”,可以保存、显示并运用存储数据进行计算。
设计目标: 1.掌握单片机定时器及中断的应用方法。 2.掌握按键、数码管扩展方法。 四、进度安排 周次 工 作 内 容 预 定 目 标 第1周周一至周二 题目安排;图书馆查相关资料 查阅相关资料 第1周周三至周四 系统架构分析与总体设计 提出系统架构方案 第2周周一 仿真调试 完成Proteus仿真 第2周周二至周三 系统设计与调试 设计硬件电路、软件编码 第2周周四 系统调试 完成软硬件调试 第2周周五 完成实习任务;完善实习报告。答辩。 完成实习,提交报告。 五、设计时间:
二、 课题背景 目前单片机渗透到我们生活的各个领域,几乎很难找到哪个领域没有单片机的踪迹。导弹的导航装置,飞机上各种仪表的控制,计算机的网络通讯与数据传输,工业自动化过程的实时控制和数据处理,广泛使用的各种智能IC卡,民用豪华轿车的安全保障系统,录像机、摄像机、全自动洗衣机的控制,以及程控玩具、电子宠物等等,这些都离不开单片机。更不用说自动控制领域的机器人、智能仪表、医疗器械了。因此,单片机的学习、开发与应用将造就一批计算机应用与智能化控制的科学家、工程师。单片机广泛应用于仪器仪表、家用电器、医用设备、航空航天、专用设备的智能化管理及过程控制等领域,大致可分如下几个范畴: (1)在智能仪器仪表上的应用 (2)在工业控制中的应用 (3)在家用电器中的应用 (4)在计算机网络和通信领域中的应用 (5)单片机在医用设备领域中的应用 (6)在各种大型电器中的模块化应用 (7)单片机在汽车设备领域中的应用 此外,单片机在工商,金融,科研、教育,国防航空航天等领域都有着十分广泛的用途。 随着智能化的逐步提高,单片机在我们生活中得到了越来越广泛的应用,其是一种集成在电路芯片,是采用超大规模集成电路技术把具有数据处理能力的中央处理器CPU、随机存储器RAM、只读存储器ROM、多种I/O口和中断系统、定时器/计时器等功能(可能还包括显示驱动电路、脉宽调制电路、模拟多路转换器、A/D转换器等电路)集成到一块硅片上构成的一个小而完善的计算机系统。本设计要制作的就是单片机于生活中最为常见的一种应用——简易计算器。本简易计算器是在普中A2开发板的基础上,利用开发板上已有的资源设计开发的,本开发板上有着相对丰富的硬件资源,可以较好的完成一些设计。
三、 课题原理介绍 本设计所用的单片机为STC90C51RC,具体的设计要求如下:通过矩阵键盘检测按下的数字和运算符号,在LCD1602液晶显示屏上面显示运算的结果,在第一行上显示输入的计算式,为左对齐;在第二行显示等于号以及最后的运算结果,为了较好的显示效果和使用的效果,第二行的计算结果显示设计为右对齐。这样在LCD1602的显示屏上可以有较好的显示效果,计算效果比较分明。由于本次实验的矩阵按键只有16个,所以我们使用了独立按键来完成计算器的记忆功能。当我们按下独立按键时候,是通过51单片机自带的EEPROM来进行数据的存储和读出。 四、 总体设计方案概述 根据计算器的功能要求,选择AT89C51为主控机,通过扩展必要的外围接口电路,实现对计算器的设计。外部主要由独立按键、4*4矩阵键盘和一个液晶显示屏构成,内部由一块AT89C51单片机构成。计算器电路包括四个模块:选用LCD作为显示部分,独立按键、矩阵键盘作为输入部分,运算模块,单片机控制部分。总体结构逻辑框图如图4-1所示。
图4-1 计算器电路包括三个部分:显示电路、44键扫描电路、独立按键、单片机微控制电路。具体设计如下: (1)由于要设计的是简单的计算器,可以进行四则运算,为了得到较好的显示效果,采用1602液晶显示数据和结果。 (2)另外键盘包括数字键(0~9)、符号键(+、-、×、÷)、清除键、等号键、M+、M-、MR,一共需要19个按键。 (3)执行过程:开机,等待键入数值,当键入数字,通过LCD显示出来,当键入+、一、、/运算符,计算器在内部执行数值转换和存储,并等待再次键入数值,当再键入数值后将显示键入的数值,按等号就会在LCD上输出运算结果。当我们在输入数值时候,按下记忆按键,便通过单片机的EEPROM来进行数据的存储与读出
五、 硬件电路设计 5.1、单片机概述 单片机通常由控制器,存储器,运算器等构成,和一台小的计算机没什么区别。它具有轻质量、小体积、成本低等优点,这也为它的发展做了铺垫。 5.2、AT89C51简介 AT89C51是一种带4K字节FLASH存储器的微处理器,通俗的称为单片机。在电路设计中,AT89C51被很多控制系统采用,因为其具有较高的灵活性和成本小等优点。它的引脚如图5-2所示
图5-1 5.3、LED接口电路 1602采用标准的16脚接口,其管脚功能介绍如下: 1: VSS为电源地 2: VDD接5V电源正极 3: V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高。 4 :RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器。 5:RW为读写信号线,高电平1时进行读操作,低电平0时进行写操作。 6:E(或EN)端为使能(enable)端。 7~14:D0~D7为8位双向数据端。 15~16:空脚或背灯电源。15脚背光正极,16脚背光负极 LCD1602接口图如图5-3所示
图5-2 5.4、独立按键 本次系统使用了独立按键的三个按键,分别实现了计算器的记忆功能M+,M-和MR。当按下k1的时候将当前的数值送到EEPROM存储,并进行加法运算;当按下k2的时候则将存储的数值读出;当按下k3的时候将当前的数值送到EEPROM存储,并可以进行减法运算,使用的独立按键的接口图如图5-4所示
图5-3
5.5、矩阵按键 计算器的输入通过4X4的矩阵按键来实现,由于软件上做了相应的映射处理,因此该4X4按键可以实现在极少代码更改下随意安排每个按键的实际意义。矩阵按键通过行列扫描的方式快速求出当前的按下按键并等待起弹起以防止重复触发。 矩阵键盘原理图如图5-5所示
图5-4 5.6 EEPROM 在实际的应用中,保存在RAM 中的数据,掉电后就丢失了,保存在单片机的FLASH 中的数据,又不能随意改变,也就是不能用它来记录变化的数值。但是在某些场合,我们又确实需要记录下某些数据,而它们还时常需要改变或更新,掉电之后数据还不能丢失,比如我们的电表度数,电视机里边的频道记忆,一般都是使用 来保存数据,就是掉电后不丢失。我们板子上使用的这个器件是 24C02,是一个容量大小是 2Kbits,也就是 256 个字节的 EEPROM。一般情况下,EEPROM 拥有 30 万到 100 万次的寿命,也就是它可以反复写入 30-100 万次,而读取次数是无限的。 5.7、系统总电路 系统总电路如图5-6所示
图5-5
六、 系统软件设计 6.1、本设计的主要功能模块: 1、按键模块。 2、LCD显示模块。 3、EEPROM模块 4、主模块单片机为系统提供初始化。 6.2、系统总流程图,如图4-2
图6-1 首先打开单片机电源,从而使得LCD1602得到初始化,无任何数据。判断是否有键值,当没有检测到有键值的时候,LCD1602依然是空白,而如果检测到矩阵键盘或者独立按键有被按下的时候,读取是那个键被按下。当按下的是数字键的时候,键入数值,并将数值送到显示缓冲;当按下的是清零键的时候,则将状态全部清除,同时将数值送到显示缓冲,使得LCD1602无任何显示;当我们按下功能键即运算符号的时候,根据上次功能键和输入的数据计算结果,然后将数值送到显示缓冲,然后再次判断本次功能键是做什么的是加还是减或者是别的,然后将结果送到显示缓冲,再次等待下一个数值的键入,最后将结果送到显示缓冲,算出结果在LCD1602上显示;当我们按下记忆按键的时候,若是M+或者M_进行存储,如果是MR的时候则将存储的数据读出来,然后在LCD1602上显示。 6.3 LCD1602显示 其流程图如图6-2所示
图6-2 首先将单片机打开,LCD1602初始化,当我们按下按键后显示汉字,或者是ACSII码或者是图形符号,显示符号的,设置相应的功能,并给与它相应的行地址和列地址,然后送入缓存,判断是否显示,不显示则接着放入缓存。当显示汉字或者ACSII的时候,要设置相应功能,给与地址送入缓存,判断是否显示完成。没显示完成,接着送入地址缓存。当然在这个过程中如何让LCD1602正确显示,而不是出现乱码,这一点很重要,由此我们去翻阅了LCD1602的技术手册,从而正确的写入数据,最后完成该设计。
6.4按键模块 其流程图如图6-3所示
图6-3 打开单片机后,判断按键是否是闭合状态,没有闭合,则返回初始状态,不做反应,要是闭合了,则去抖动,然后再判断是否有按下按键,要是没有则返回初始状态,有按下则判断是什么键,然后判断是否释放,释放则将该键的值送入LCD1602中,否则重新判断。矩阵键盘采用行列扫描:通过高四位全部输出低电平,低四位输出高电平。当接收到的数据,低四位不全为高电平时,说明有按键按下,然后通过接收的数据值,判断是哪一列有按键按下,然后再反过来,高四位输出高电平,低四位输出低电平,然后根据接收到的高四位的值判断是那一行有按键按下,这样就能够确定是哪一个按键按下了。
七、 实习总结 本课题对计算器进行了简单的研究,本系统采用AT89C51芯片,实现了计算器的基本功能。本设计随着一开始不知如何下手到如今的下笔有神,其中的滋味令人印象深刻。 在这次设计中,在硬件方面:我利用PROTEUS绘制电路原理图,在软件方面:先用KEIL软件进行编程,然后,把HEX加载到单片机芯片中,最后,对电路进行仿真、调试。另外需要说明的是,各个模块是可以替换的,本次设计可以用其他显示器代替液晶显示器,如LED 数码管显示等。不管怎么换,都必须熟悉单片机原理和结构,只有这样才能灵活运用。这次课题设计不但使我理论知识得到巩固,而且也使我的检索能力得到提高,本设计经过反复的及调试,基本上能实现设定的要求,但由于仿真系统原因,本设计视觉效果不是很好。不足之处有以下几点:1、不能进行连加和带小数的运算;2、界面还不够人性化。 在课题设计的过程中,如何使用EEPROM来进行数据的写入和读出困扰了我许久。在后面几天中和同伴不断地查阅各种文献资料,通过CDSN论坛的检索,才渐渐地对这一方面,有了初步的构思。这让我想起了一个人生道理“天才在于积累,聪明在于勤奋”,所以我们想要做成一件事,就需要我们用看书来积累这一方面的知识,用实践来验证我们所学的知识从而做到知行合一。切忌不可妄自尊大,想要一步登天,那样只会白白地浪费青春,做不成事情。在设计的这一阶段也给了我很多的感悟: 一、在此次的课题设计中,让我对EEPROM有了初步的了解. EEPROM ,是一种掉电后数据不丢失的存储芯片。其可以在电脑上或专用设备上擦除已有信息,重新编程。且其可以按“位”进行擦写。 二、在制作的途中,让我发觉了自己专业知识并不如自己想象的那么扎实,对自身的专业知识仅仅限制于课堂所讲的内容,并没有在课后继续自主钻研,这导致了自己在课题开始的第一个阶段寸步难行。专业知识的匮乏,是我在此过程中的首要感受,这对我今后的学习之路是一个很好的鞭策。 三、在此次的设计过程中,仅凭自己的埋头苦干就想完成之一课题制作,对我们这些学生来说,这就像是在徒手攀爬高峰,显得异常困难。故寻求老师、同学的帮助显得尤为重要。在完成这一课题的那一瞬间让我懂得的团队的重要性。 “吾生也有涯,而知也无涯”,这一阶段的结束,也意味着下一个征程即将开始,我会带着不断学习的态度继续走下去。
八、 参考文献 [1]张毅刚.新编MCS-51单片机应用设计.哈尔滨:哈尔滨工业大学出版社,2003 [2]谭浩强.C程序设计.北京:清华大学出版社,1991 [3] 陈明荧,89C51单片机课程设计实训教材.北京:清华大学出版社,2004 [4]刘瑞新,单片机原理及应用教程.北京:机械工业出版社,2003 [5]刘洋,郭培英.基于89c51单片机实现简单计算器的功能探索.内蒙古石油化工, 2020-05-30
附录 智能计算器设计.c
#include<reg52.h>
#include"lcd.h"
#include"i2c.h"
typedef unsigned char uint8;
typedef unsigned int uint16;
sbit led=P3^7;
sbit beep=P2^0;
sbit k1=P3^1;
sbit k2=P3^0;
sbit k3=P3^2;
char res=0;
uint8 key,num;
uint8 fuhao;
uint8 flag;
long a,b,c,d,sum,sub;
uint8 k;
uint8 biao;
uint8 dat1[]={1,2,3,0x2b-0x30, 4,5,6,0x2d-0x30, 7,8,9,0x2a-0x30, 0,0x01-0x30,0x3d-0x30,0x2b-0x30 };
void delay(uint16 i)
{
while(i--);
}
void lcdwrc(uint8 c)
{
LcdWriteCom(c);
}
void lcdwrd(uint8 dat)
{
LcdWriteData(dat);
}
void lcd_init()
{
LcdInit();
key=0;
num=0;
flag=0;
fuhao=0;
a=0;
b=0;
c=0;
d=0;
biao=0;
led=0;
}
void keyscan()
{
P1=0xfe;
if(P1!=0xfe)
{
delay(1000);
if(P1!=0xfe)
{
key=P1&0xf0;
switch(key)
{
case 0xe0: num=0;break;
case 0xd0: num=1;break;
case 0xb0: num=2;break;
case 0x70: num=3;break;
}
}
while(P1!=0xfe);
if(num==0||num==1||num==2)
{
if(flag==0)
{
a=a*10+dat1[num];
res =a;
}
else
{
b=b*10+dat1[num];
res =b;
}
}
if(num==3)
{
flag=1;
fuhao=1;
}
lcdwrd(0x30+dat1[num]);
}
P1=0xfd;
if(P1!=0xfd)
{
delay(1000);
if(P1!=0xfd)
{
key=P1&0xf0;
switch(key)
{
case 0xe0: num=4;break;
case 0xd0: num=5;break;
case 0xb0: num=6;break;
case 0x70: num=7;break;
}
}
while(P1!=0xfd);
if(num==4||num==5||num==6)
{
if(flag==0)
{
a=a*10+dat1[num];
res =a;
}
else
{
b=b*10+dat1[num];
res =b;
}
}
else
{
flag=1;
fuhao=2;
}
lcdwrd(0x30+dat1[num]);
}
P1=0xfb;
if(P1!=0xfb)
{
delay(1000);
if(P1!=0xfb)
{
key=P1&0xf0;
switch(key)
{
case 0xe0: num=8;break;
case 0xd0: num=9;break;
case 0xb0: num=10;break;
case 0x70: num=11;break;
}
}
while(P1!=0xfb);
if(num==8||num==9||num==10)
{
if(flag==0)
{
a=a*10+dat1[num];
res =a;
}
else
{
b=b*10+dat1[num];
res =b;
}
}
else
{
flag=1;
fuhao=3;
}
lcdwrd(0x30+dat1[num]);
}
P1=0xf7;
if(P1!=0xf7)
{
delay(1000);
if(P1!=0xf7)
{
key=P1&0xf0;
switch(key)
{
case 0xe0: num=12;break;
case 0xd0: num=13;break;
case 0xb0: num=14;break;
case 0x70: num=15;break;
}
}
while(P1!=0xf7);
switch(num)
{
case 12:
if(flag==0)
{
a=a*10+dat1[num];
res =a;
lcdwrd(0x30);
}
else
{
b=b*10+dat1[num];
res =b;
lcdwrd(0x30);
}
break;
case 13:
lcdwrc(0x01);
a=0;
b=0;
flag=0;
fuhao=0;
break;
case 15:
flag=1;
fuhao=4;
lcdwrd(0x2f);
break;
case 14:
if(fuhao==1)
{
lcdwrc(0x4f+0x80);
lcdwrc(0x04);
c=a+b;
res =c;
while(c!=0)
{
lcdwrd(0x30+c%10);
c=c/10;
}
lcdwrd(0x3d);
a=0;
b=0;
flag=0;
fuhao=0;
}
if(fuhao==2)
{
lcdwrc(0x4f+0x80);
lcdwrc(0x04);
if(a>b)
c=a-b;
else
c=b-a;
res=c;
while(c!=0)
{
lcdwrd(0x30+c%10);
c=c/10;
}
if(a<b) lcdwrd(0x2d);
lcdwrd(0x3d);
a=0;
b=0;
flag=0;
fuhao=0;
}
if(fuhao==3)
{
lcdwrc(0x4f+0x80);
lcdwrc(0x04);
c=a*b;
while(c!=0)
{
lcdwrd(0x30+c%10);
c=c/10;
}
lcdwrd(0x3d);
a=0;
b=0;
flag=0;
fuhao=0;
}
if(fuhao==3)
{
lcdwrc(0x4f+0x80);
lcdwrc(0x04);
c=a*b;
while(c!=0)
{
lcdwrd(0x30+c%10);
c=c/10;
}
lcdwrd(0x3d);
a=0;
b=0;
flag=0;
fuhao=0;
}
if(fuhao==4)
{
k=0;
lcdwrc(0x4f+0x80);
lcdwrc(0x04);
c=(long)(((float)a/b)*1000);
while(c!=0)
{
k++;
lcdwrd(0x30+c%10);
c=c/10;
if(k==3)
{
lcdwrd(0x2e);
k=0;
}
}
if(a/b<0)
{
lcdwrd(0x30);
}
lcdwrd(0x3d);
a=0;
b=0;
flag=0;
fuhao=0;
}
break;
}
}
}
void keyscan2()
{
keyscan();
if(k1==0)
{
delay(1000);
if(k1==0)
{
At24c02Write(1,res);
}
while(!k1);
key=P1&0xf0;
switch(key)
{
case 0xb0: num=14;break;
}
switch(num) {
case 14:
lcdwrc(0x4f+0x80);
lcdwrc(0x04);
sum = res+res;
while(sum!=0)
{
lcdwrd(0x30+sum%10);
sum=sum/10;
}
lcdwrd(0x3d);
}
}
if(k2==0)
{
delay(1000);
if(k2==0)
{
res=At24c02Read(1);
lcdwrc(0x4f+0x80);
lcdwrc(0x04);
while(res!=0)
{
lcdwrd(0x30+res%10);
res=res/10;
}
}
while(!k2);
}
if(k3==0)
{
delay(100);
if(k3==0)
{
At24c02Write(1,res);
}
while(!k3);
lcdwrc(0x4f+0x80);
lcdwrc(0x04);
sub=res-res;
while(sub!=0)
{
lcdwrd(0x30+sub%10);
sub=sub/10;
}
if(res<res) lcdwrd(0x2d);
lcdwrd(0x3d);
}
}
void main()
{
lcd_init();
while(1)
{
keyscan();
keyscan2();
}
}
|