简易计算器实验.docx
《简易计算器实验.docx》由会员分享,可在线阅读,更多相关《简易计算器实验.docx(33页珍藏版)》请在冰点文库上搜索。
![简易计算器实验.docx](https://file1.bingdoc.com/fileroot1/2023-5/24/3463ba8c-41c2-4ac6-af23-3f18194615cd/3463ba8c-41c2-4ac6-af23-3f18194615cd1.gif)
简易计算器实验
目录
第一节引言2
1.1AT89C51单片机介绍2
1.2LED数码管显示器概述5
1.3输入设备键盘的简述6
第二节系统总体方案及硬件设计7
2.1设计要求7
2.2设计方案7
2.3硬件系统设计7
2.3.1时钟电路设计7
2.3.2复位电路8
2.3.3显示驱动电路8
2.3.4蜂鸣器提示9
第三节软件设计10
3.1键盘的扫描10
3.2按键的处理11
3.3动态数码显示12
第四节Proteus软件仿真13
4.1ProteusISIS简介13
4.2Proteus工作过程13
4.2.1加法演示结果14
4.2.2减法演示结果14
4.2.3乘法演示结果15
4.2.4除法演示结果16
结束语27
参考文献28
计算器模拟系统
第一节引言
本设计是一个计算器模拟系统,可以实现加减乘除的运算以及对计算器的数字信息的输入和运算结果并且显示在相应的LED上,输入完毕要求有声音提示。
对于计算器模拟系统的实现,很多种语言都可以实现,但C语言是我们学到的一种高级语言程序,用它来实现程序较为简单,易于实现。
又由于要求模拟的计算器显示8位数字,所以采用八位LED动态显示,为了简化线路采用以软件为主的接口方法,即不使用专门的硬件译码器,而采用软件程序进行译码。
输出采用动态扫描的方式,每次中断时间一到,选通所要显示那一个的LED,并对其送相应的二进制代码,使其显示一位字符。
中断时间很短,人眼分辨不出,所以可以实现数字一起显示出来
由于输入采用4X4矩阵式键盘,所以本设计避免了I/O口扩展使程序简化。
对于键盘为了消除抖动,需要进行延迟,再判断,确实有键按下后,可以根据该行不同的值用选择分支语句进行相应的操作。
八个引脚用来扫描键盘的输入,八个引脚用来驱动八位LED显示,八个引脚用作八位LED的位选信号。
当显示器输出大于八位时,可以在剩下的I/O口中任意选一个用来使一扬声器发出声音表示输出超出预定的范围。
本设计实现功能:
(1)计算器最多只能显示8位数字,开机运行时,只有数码管最低位显示为“0”,其余位全部不显示;
(2)具有4×4键盘,分别表示0~9、+、-、×、/、=和清零键CL,输入的数字从设计的键盘输入;
(3)第一次按下时,显示“D1”;第二次按下时,显示“D1D2”;第三次按下时,显示“D1D2D3”,8个全显示完毕,再按下按键下时,发出“嘀”提示音;
(4)可以对计算结果小于256的两个无符号数进行加、减、乘、除运算,并显示计算结果。
(5)结果溢出时发出“嘀”报警声。
1.1AT89C51单片机介绍
AT89C51是一种带4K字节闪烁可编程可擦除只读存储器(FPEROM—FalshProgrammableandErasableReadOnlyMemory)的低电压,高性能CMOS8位微处理器,俗称单片机。
AT89C2051是一种带2K字节闪烁可编程可擦除只读存储器的单片机。
单片机的可擦除只读存储器可以反复擦除100次。
该器件采用ATMEL高密度非易失存储器制造技术制造,与工业标准的MCS-51指令集和输出管脚相兼容。
由于将多功能8位CPU和闪烁存储器组合在单个芯片中,ATMEL的AT89C51是一种高效微控制器,AT89C2051是它的一种精简版本。
AT89C单片机为很多嵌入式控制系统提供了一种灵活性高且价廉的方案。
图1-1AT89C51结构图
管脚说明:
VCC:
供电电压。
GND:
接地。
P0口:
P0口为一个8位漏级开路双向I/O口,每脚可吸收8TTL门电流。
当P1口的管脚第一次写1时,被定义为高阻输入。
P0能够用于外部程序数据存储器,它可以被定义为数据/地址的第八位。
在FIASH编程时,P0口作为原码输入口,当FIASH进行校验时,P0输出原码,此时P0外部必须被拉高。
P1口:
P1口是一个内部提供上拉电阻的8位双向I/O口,P1口缓冲器能接收输出4TTL门电流。
P1口管脚写入1后,被内部上拉为高,可用作输入,P1口被外部下拉为低电平时,将输出电流,这是由于内部上拉的缘故。
在FLASH编程和校验时,P1口作为第八位地址接收。
P2口:
P2口为一个内部上拉电阻的8位双向I/O口,P2口缓冲器可接收,输出4个TTL门电流,当P2口被写“1”时,其管脚被内部上拉电阻拉高,且作为输入。
并因此作为输入时,P2口的管脚被外部拉低,将输出电流。
这是由于内部上拉的缘故。
P2口当用于外部程序存储器或16位地址外部数据存储器进行存取时,P2口输出地址的高八位。
在给出地址“1”时,它利用内部上拉优势,当对外部八位地址数据存储器进行读写时,P2口输出其特殊功能寄存器的内容。
P2口在FLASH编程和校验时接收高八位地址信号和控制信号。
P3口:
P3口管脚是8个带内部上拉电阻的双向I/O口,可接收输出4个TTL门电流。
当P3口写入“1”后,它们被内部上拉为高电平,并用作输入。
作为输入,由于外部下拉为低电平,P3口将输出电流(ILL)这是由于上拉的缘故。
P3口也可作为AT89C51的一些特殊功能口,如下表所示:
口管脚 备选功能
P3.0 RXD(串行输入口)
P3.1 TXD(串行输出口)
P3.2 /INT0(外部中断0)
P3.3 /INT1(外部中断1)
P3.4 T0(记时器0外部输入)
P3.5 T1(记时器1外部输入)
P3.6 /WR(外部数据存储器写选通)
P3.7 /RD(外部数据存储器读选通)
P3口同时为闪烁编程和编程校验接收一些控制信号。
RST:
复位输入。
当振荡器复位器件时,要保持RST脚两个机器周期的高电平时间。
ALE/PROG:
当访问外部存储器时,地址锁存允许的输出电平用于锁存地址的地位字节。
在FLASH编程期间,此引脚用于输入编程脉冲。
在平时,ALE端以不变的频率周期输出正脉冲信号,此频率为振荡器频率的1/6。
因此它可用作对外部输出的脉冲或用于定时目的。
然而要注意的是:
每当用作外部数据存储器时,将跳过一个ALE脉冲。
如想禁止ALE的输出可在SFR8EH地址上置0。
此时,ALE只有在执行MOVX,MOVC指令是ALE才起作用。
另外,该引脚被略微拉高。
如果微处理器在外部执行状态ALE禁止,置位无效。
/PSEN:
外部程序存储器的选通信号。
在由外部程序存储器取指期间,每个机器周期两次/PSEN有效。
但在访问外部数据存储器时,这两次有效的/PSEN信号将不出现。
/EA/VPP:
当/EA保持低电平时,则在此期间外部程序存储器(0000H-FFFFH),不管是否有内部程序存储器。
注意加密方式1时,/EA将内部锁定为RESET;当/EA端保持高电平时,此间内部程序存储器。
在FLASH编程期间,此引脚也用于施加12V编程电源(VPP)。
XTAL1:
反向振荡放大器的输入及内部时钟工作电路的输入。
XTAL2:
来自反向振荡器的输出。
振荡器特性:
XTAL1和XTAL2分别为反向放大器的输入和输出。
该反向放大器可以配置为片内振荡器。
石晶振荡和陶瓷振荡均可采用。
如采用外部时钟源驱动器件,XTAL2应不接。
有余输入至内部时钟信号要通过一个二分频触发器,因此对外部时钟信号的脉宽无任何要求,但必须保证脉冲的高低电平要求的宽度。
芯片擦除:
整个PEROM阵列和三个锁定位的电擦除可通过正确的控制信号组合,并保持ALE管脚处于低电平10ms来完成。
在芯片擦操作中,代码阵列全被写“1”且在任何非空存储字节被重复编程以前,该操作必须被执行。
此外,AT89C51设有稳态逻辑,可以在低到零频率的条件下静态逻辑,支持两种软件可选的掉电模式。
在闲置模式下,CPU停止工作。
但RAM,定时器,计数器,串口和中断系统仍在工作。
在掉电模式下,保存RAM的内容并且冻结振荡器,禁止所用其他芯片功能,直到下一个硬件复位为止。
1.2LED数码管显示器概述
LED,发光二极管,是一种固态的半导体器件,它可以直接把电转化为光。
LED的心脏是一个半导体的晶片,晶片的一端附在一个支架上,一端是负极,另一端连接电源的正极,使整个晶片被环氧树脂封装起来。
半导体晶片由两部分组成,一部分是P型半导体,在它里面空穴占主导地位,另一端是N型半导体,在这边主要是电子。
但这两种半导体连接起来的时候,它们之间就形成一个“P-N结”。
当电流通过导线作用于这个晶片的时候,电子就会被推向P区,在P区里电子跟空穴复合,然后就会以光子的形式发出能量,这就是LED发光的原理。
而光的波长也就是光的颜色,是由形成P-N结的材料决定的。
LED的内在特征决定了它是最理想的光源去代替传统的光源,它有着广泛的用途。
七段LED有7个发光二极管按”日”字形排列,所有二极管的阳极或阴极连在一起。
当某个发光二极管的阴极接低电平或阳极接高电平是时,对应二极管点亮,根据不同的组合。
形成不同的字符0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f。
LED具有静态和动态显示之分,动态是一个字位一个字位各只LED轮流点亮,每个字位停留小于人的视觉,好像LED是点亮的。
LCD显示器有分段式和点阵式两种结构。
LCD是一种被动显示器,由于它的功耗极低,抗干扰能力强,因而在低功耗的单片机系统中大量使用。
1.3输入设备键盘的简述
键盘是有若干案件组成的开关矩阵,他能实现简单的人机对话。
而与计算机系统的键盘有两类:
一类是编码键盘,即键盘上比合建的识别由专门硬件来实现;另一类是非编码键盘,即键盘输入及闭合键的识别由软件来完成。
图1-2输入设备键盘图
第二节系统总体方案及硬件设计
2.1设计要求
设计具体要求:
(1)要求模拟的计算器至少显示8位数字,开机运行时,只有数码管最低位显示为“0”,其余位全部不显示;
(2)设计4×4键盘,分别表示0~9、+、-、×、/、=和清零键CL,输入的数字从设计的键盘输入;
(3)第一次按下时,显示“D1”;第二次按下时,显示“D1D2”;第三次按下时,显示“D1D2D3”,8个全显示完毕,再按下按键下时,给出“嘀”提示音;
(4)可以对计算结果小于256的两个无符号数进行加法运算,并显示计算结果。
对于×、/、和—的运算为提高部分;
(5)编写程序,用proteus软件进行仿真。
报告中给出操作过程及运行效果图。
2.2设计方案
(1)I/O口扩展问题
本次设计要用到8个口作为输出显示LED的位选通信号,8个口用作LED的驱动而对于16个输入键,可以用矩阵式4X4键盘仅用8个口来实现,这样可以节省I/O口,不过需要对各个键盘进行动态扫描。
另外,还需要一个口作为输入大于8位时的报警信号。
这样,还会剩余一些个I/O口。
小于AT89C51的32个口,因此不需要进行I/O口的扩展。
(2)语言的选择
根据设计要求需完成加减乘除的算术运算,若使用汇编语言来编程,语句可能会较多而且比较复杂,编起来会不大方便。
而采用现在比较流行的C语言来编写会比较方便。
2.3硬件系统设计
2.3.1时钟电路设计
本设计采用内部时钟产生方式。
内部振荡方式所得的时钟信号比较稳定。
在XTAL1和XTAL2两端跨接晶体或陶瓷谐振器,与内部反相器构成稳定的自激振荡器。
晶振选用的是12MHZ的内部振荡方式,电路如图:
电容器C1,C2起稳定振荡频率,快速起振的作用,电容值取33P。
图2-1内部振荡结构图
2.3.2复位电路
采用上电+按键复位电路如下,上电后,由于电容充电,使RST持续一段高电平时间。
当单片机已在运行之中时,按下复位键也能使用使RST持续一段时间的高电平,从而实现上电加开关复位的操作。
C3选择30uF,R2选择10K。
这不仅能使单片机复位,而且还能使单片机的外围芯片也同时复位。
图2-2复位电路图
2.3.3显示驱动电路
数码管发光需要一定的电流,但单片机本身不可能提供足够的电流,即拉电流和灌电流不能满足要求,所以想要数码管正常发光,就要加适当的驱动电路。
首先考虑数码管的段码输出端,单片机的P0口可带8个TTL负载,而其他的I/O口只能带4个TTL负载,所以采用P0口作数码管的段码输出端,但P0口是集电极开路输出,要想输出拉电流,必须加上拉电阻,提高驱动能力,电路如图所示。
图2-3显示驱动电路图
2.3.4蜂鸣器提示
在89s52的p3.6连一个蜂鸣器,在输入8位数后,再输入数时,从p3.6脚输入一低电平,并延时一定时间,蜂鸣器发出一“嘀”的声音,提醒使用者输入也达8位数。
为限制电流,在电路中加一限流电阻。
图2-4蜂鸣器电路图
第三节软件设计
3.1键盘的扫描
图3-1键盘扫描流程图
对键盘的识别可以对键盘所有列送高电平1,然后逐行送低电平,并判断列的值是否全为高电平,若不是说明该行有键按下,为了消除抖动,需要进行一延迟环节,再判断,确实有键按下后,可以根据该行不同的值用选择分支语句进行相应的操作。
3.2按键的处理
图3-2键盘处理流程图
当有有效键按下后,需要对它进行一系列判断和处理。
3.3动态数码显示
数码管采取的动态扫描,每一位数码管被点亮一小段时间,并且每只有一个被点亮次,就又熄灭,但当扫描频率大于一定时,人眼就不能分辨出闪烁的现象,看起来就像一直被点亮,若扫描频率太低,就会出现闪烁现象。
第四节Proteus软件仿真
4.1ProteusISIS简介
Proteus的ISIS是一款Labcenter出品的电路分析实物仿真系统,可仿真各种电路和IC,并支持单片机,元件库齐全,使用方便,是不可多得的专业的单片机软件仿真系统。
该软件的特点:
①全部满足我们提出的单片机软件仿真系统的标准,并在同类产品中具有明显的优势。
②具有模拟电路仿真、数字电路仿真、单片机及其外围电路组成的系统的仿真、RS一232动态仿真、1C调试器、SPI调试器、键盘和LCD系统仿真的功能;有各种虚拟仪器,如示波器、逻辑分析仪、信号发生器等。
③目前支持的单片机类型有:
68000系列、8051系列、AVR系列、PIC12系列、PIC16系列、PIC18系列、Z80系列、HC11系列以及各种外围芯片。
④支持大量的存储器和外围芯片。
总之该软件是一款集单片机和SPICE分析于一身的仿真软件,功能极其强大,可仿真51、AVR、PIC。
4.2Proteus工作过程
单击屏幕左下方的“开始”→“程序”→“Proteus7Professional”→“ISIS7Professional”,出现如图所示屏幕,表明进入ProteusISIS集成环境。
图4-1Proteus界面图
4.2.1加法演示结果
在键盘上依次按下如图所示:
图4-2-1按111LED显示图
按下“+”号键后屏幕显示如图所示:
图4-2-2按“+”号LED显示图
在键盘上依次按下111LED显示如图所示:
图4-2-3按111LED显示图
按下“=”号键后屏幕显示正确结果222如图所示:
图4-2-4按“=”号111LED显示图
4.2.2减法演示结果
在键盘上依次按下87LED显示如图所示:
图4-2-5按下87LED显示图
按下“-”号键后屏幕显示如图所示:
图4-2-6按“-”号LED显示图
在键盘上依次按下32LED显示如图所示:
图4-2-7按下32LED显示图
按下“=”号键后屏幕显示正确结果55如图所示:
图4-2-8按“=”号LED显示图
4.2.3乘法演示结果
在键盘上依次按下35LED显示如图所示:
图4-2-9按下35LED显示图
按下“×”号键后屏幕显示如图所示:
图4-2-10按“X”号LED显示图
在键盘上依次按下12LED显示如图所示:
图4-2-11按下12LED显示图
按下“=”号键后屏幕显示正确结果420如图所示:
图4-2-12按“=”号LED显示图
4.2.4除法演示结果
在键盘上依次按下62LED显示如图所示:
图4-2-13按下62LED显示图
按下“÷”号键后屏幕显示如图所示:
图4-2-14按“÷”号LED显示图
在键盘上依次按下2LED显示如图所示:
图4-2-15按下2LED显示图
按下“=”号键后屏幕显示正确结果31如图所示:
图4-2-16按“=”号LED显示图
系统具体代码如下:
#include
#include
sbitP1_0=P1^0;
sbitP3_5=P3^5;
sbitP3_6=P3^6;
sbitP3_7=P3^7;
sbitP3_4=P3^4;
unsignedintnum0,result;
unsignedintnumber,num1;
unsignedcharcodedispcode[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};
unsignedcharcodedispbitcode[]={0xfe,0xfd,0xfb,0xf7,0xef,
0xdf,0xbf,0x7f};
unsignedchardispbuf[8]={0,16,16,16,16,16,16,16};
unsignedchardisp[8]={0,16,16,16,16,16,16,16};
unsignedchardispbitcount;
unsignedchartemp;
unsignedchari,j;
unsignedcharkey;
unsignedcharkeypres;
unsignedcharyunsuanfu;/*************运算标志符***************/
bitalarmflag;/*************溢出报警标识符*********/
biteq;
voidrresult()/******拆分result并送入显示数组******/
{i=0;number=result;
if(number<0)alarmflag=1;
else{for(i=0;i<9;i++)
{if(number==0)break;
elsedispbuf[i]=number%10;
number/=10;
}
}
}
/*************运算num1值*******************/
unsignedlongintcalcul()
{switch(yunsuanfu)
{
case1:
result+=num1;return(result);break;
case2:
result-=num1;return(result);break;
case3:
result*=num1;return(result);break;
case4:
result/=num1;return(result);break;
default:
yunsuanfu=0;
}
}
/*****************************************/
unsignedlongintnum1process(unsignedchar*p,unsignedcharcount)
{num0=*p;
while(count-1>0)
{for(i=0;inum0+=*(p+count-1);
count--;
}
return(num0);
}
/**************************************/
voidreset(void)
{
for(i=0;i<8;i++)
{dispbuf[i]=disp[i];}
keypres=0;
}
/************************************/
voidchange(unsignedchar*p,unsignedcharcount)
{
while(count>0)
{
*(p+count)=*(p+count-1);
count--;
}
dispbuf[0]=key;
}
/*********中断动态显示LED*************/
voidt0(void)interrupt1
{
TH0=(65536-4000)/256;
TL0=(65536-4000)%256;
P2=dispbitcode[dispbitcount];
P0=dispcode[dispbuf[dispbitcount]];
dispbitcount++;
if(dispbitcount==8)dispbitcount=0;
if(alarmflag==1)
{for(i=0;i<50;i++)
{P1_0=~P1_0;
for(j=0;j<50;j++);
}
}alarmflag=0;
}
voidmain(void)
{
TMOD=0x01;
TH0=(65536-3000)/256;
TL0=(65536-3000)%256;
TR0=1;
ET0=1;
EA=1;
/***********扫描1**************/
while
(1)
{
P3=0xff;
P3_4=0;
temp=P3;
temp=temp&0x0f;
if(temp!
=0x0f)
{
for(i=50;i>0;i--)
for(j=100;j>0;j--);
temp=P3;
temp=temp&0x0f;
if(temp!
=0x0f)
{
temp=P3;
temp=temp&0x0f;
switch(temp)
{
case0x0e:
key=7;break;
case0x0d:
key=8;break;
case0x0b:
key=9;break;
case0x07:
key=10;break;
}
/**********加法***********/
if(key==10)
{
yunsuanfu=1;
result=num1process(dispbuf,keypres);
reset();
}
if(key>=7&&key<10)
{
keypres++;
if(keypres==1)dispbuf[0]=key;
elseif(keypres<9)change(dispbuf,keypres);
elseif(keypres>8)alarmflag=1;
}
temp=P3;
temp=temp&0x0f;
wh