简易计算器的设计报告

引言

当今时代,是一个新技术层出不穷的时代。在电子领域,尤其是自动化智能控制领域,传统的分立元件或数字逻辑电路构成的控制系统正以前所未见的速度被单片机智能控制系统所取代。单片机具有体积小、功能强、成本低、应用面广等优点,可以说,智能控制与自动控制的核心就是单片机。目前,一个学习与应用单片机的高潮正在工厂、学校及企事业单位大规模地兴起。过去习惯于传统电子领域的工程师、技术员正面临着全新的挑战,如不能在较短时间内学会单片机,势必会被时代所遗弃,只有勇敢地面对现实,挑战自我,加强学习,争取在较短的时间内将单片机技术融会贯通,才能跟上时代的步伐。

它所给人带来的方便也是不可否定的,它在一块芯片内集成了计算机的各种功能部件,构成一种单片式的微型计算机。20世纪80年代以来,国际上单片机的发展迅速,其产品之多令人目不暇接,单片机应用不断深入,新技术层出不穷。20世纪末,电子技术获得了飞速的发展,在其推动下,现代电子产品几乎渗透了社会的各个领域,有力地推动了社会生产力的发展和社会信息化程度的提高,同时也使现代电子产品性能进一步提高,产品更新换代的节奏也越来越快。

本设计是由单片机实现的模拟计算器,它不仅能实现数据的加减乘除运算,而且还能使数据及其计算结果在数码管上显示出来,能够实现0-256的数字四则运算。本设计是用单片机AT89C51来控制,采用LCD显示,软件部分是由C语言来编写的。

设计任务:利用键盘和LCD设计一个简单的数学计算器,可以完成简单的如加,减,乘,除的四则运算,并将运算结果在LCD上显示出来。

1.方案论证

1.1 方案一

   根据功能和指标要求,本系统选用MCS-51系列单片机AT89C51为主控机。通过扩展必要的外围接口电路,实现对计算器的设计。计算器电路包括三个部分:显示电路、4*4键扫描电路、单片机微控制电路。用七段数码管作为显示电路,矩阵键盘作为输入电路。模块图如图1.1所示。

   图1.1 方案一模块图

1.2 方案二

根据计算器的功能要求,选择AT89C51为主控机,通过扩展必要的外围接口电路,实现对计算器的设计。外部主要由4*4矩阵键盘和一个液晶显示屏构成,内部由一块AT89C51单片机构成。计算器电路包括四个部分:选用LCD作为显示部分,矩阵键盘作为输入部分,运算模块,单片机控制部分。模块图如图1.2所示。

               图1.2 方案二模块图

1.3对比选择

从电路结果的准确角度来说方案二要优于方案一,因为方案二用LCD作为显示电路,显示结果清楚明了,比用方案一的准确度更高,而且电路连线相对比较简单。为了得到更好的结果,所以选择方案二。

1.4整体设计

根据简易计算器的功能和指标要求,本设计系统选用MCS-51系列单片机AT89C51为主控机。通过扩展必要的外围接口电路,实现对简易计算器的设计。计算器电路包括三个部分:显示电路、4*4键扫描电路、单片机微控制电路。具体设计如下:

(1)由于要设计的是简单的计算器,可以进行四则运算,为了得到较好的显示效果,采用七段数码管显示数据和结果。

(2)另外键盘包括数字键(0~9)、符号键(+、-、×、÷)、清除键和等号键,故只需要16 个按键即可。

(3)执行过程:开机显示零,等待键入数值,当键入数字,通过LCD显示出来,当键入+、-、*、/运算符,计算器在内部执行数值转换和存储,并等待再次键入数值,当再键入数值后将显示键入的数值,按等号就会在LCD上输出运算结果。

(4)错误提示:当计算器执行过程中有错误时,会在LCD上显示相应的提示,如:当输入的数值或计算得到的结果大于计算器的表示范围时,计算器会在LCD上提示溢出;当除数为0时,计算器会在七段数码管上提示错误。

线路原理框图如图1.3所示。

2电路设计原理

2.1键盘接口电路

计算器输入数字和其他功能按键要用到很多按键,如果采用独立按键的方式,在这种情况下,编程会很简单,但是会占用大量的I/O 口资源,因此在很多情况下都不采用这种方式,而是采用矩阵键盘的方案。矩阵键盘采用四条I/O 线作为行线,四条I/O 线作为列线组成键盘,在行线和列线的每个交叉点上设置一个按键。这样键盘上按键的个数就为4×4个。这种行列式键盘结构能有效地提高单片机系统中I/O 口的利用率。

矩阵键盘的工作原理:

计算器的键盘布局如图2.1所示:一般有16个键组成,在单片机中正好可以用一个P口实现16个按键功能,这种形式在单片机系统中也最常用。

图2.1矩阵键盘布局图

电路中采用4*4键盘作为输入电路模块的话,电路连线会比较简单,而且这种行列式键盘结构能有效地提高单片机系统中I/O 口的利用率。但是在硬件电路设计的过程中,实验室没有提供矩阵键盘,所以我们将4*4的矩阵键盘换成了16个独立按键。采用独立按键的方式的话,会占用大量的I/O 口资源,但是在这种情况下,编程会很简单。

矩阵键盘内部电路图如图2.2所示(见下页)。

2.2显示模块

本设计采用LCD1602液晶显示屏来显示输出数据。通过D0-D7引脚向LCD写指令字或写数据以使LCD实现不同的功能或显示相应数据。LCD1602管脚图如图2.3所示。

图2.2 矩阵键盘内部电路图

图2.3  LCD1602管脚图

2.3运算模块(单片机控制)

MCS-51 单片机是在一块芯片中集成了CPU、RAM、ROM、定时器/计数器和多功能I/O等一台计算机所需要的基本功能部件。如果按功能划分,它由如下功能部件组成,即微处理器(CPU)、数据存储器(RAM)、程序存储器(ROM/EPROM)、并行I/O 口、串行口、定时器/计数器、中断系统及特殊功能寄存器(SFR)。

单片机是靠程序运行的,并且可以修改。通过不同的程序实现不同的功能,尤其是特殊的独特的一些功能,通过使用单片机编写的程序可以实现高智能,高效率,以及高可靠性!因此我们采用单片机AT89C51作为计算器的主要功能部件,可以很快地实现运算功能。

                    

                           图2.4  AT89C51管脚图

管脚说明:

  VCC:供电电压。

  GND:接地。

P0:P0口为一个8位漏级开路双向I/O口,每脚可吸收8TTL门电流。当P0口的管脚第一次写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:来自反向振荡器的输出。

3.仿真调试

Proteus软件是英国Labcenter electronics公司出版的EDA工具软件(该软件中国总代理为广州风标电子技术有限公司)。它不仅具有其它EDA工具软件的仿真功能,还能仿真单片机及外围器件。它是目前最好的仿真单片机及外围器件的工具。虽然目前国内推广刚起步,但已受到单片机爱好者、从事单片机教学的教师、致力于单片机开发应用的科技工作者的青睐。Proteus是世界上著名的EDA工具(仿真软件),从原理图布图、代码调试到单片机与外围电路协同仿真,一键切换到PCB设计,真正实现了从概念到产品的完整设计。是目前世界上唯一将电路仿真软件、PCB设计软件和虚拟模型仿真软件三合一的设计平台,其处理器模型支持8051、HC11、PIC10/12/16/18/24/30/DsPIC33、AVR、ARM、8086和MSP430等,20##年即将增加Cortex和DSP系列处理器,并持续增加其他系列处理器模型。在编译方面,它也支持IAR、Keil和MPLAB等多种编译器。

  其功能特点:

  (1)原理布图

  (2)PCB自动或人工布线   

(3)SPICE电路仿真

Keil uVision3是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,使用接近于传统c语言的语法来开发,与汇编相比,C语言在功能上、结构性、可读性、可维护性上有明显的优势,因而易学易用,而且大大的提高了工作效率和项目开发周期,他还能嵌入汇编,您可以在关键的位置嵌入,使程序达到接近于汇编的工作效率。KEILC51标准C编译器为8051微控制器的软件开发提供了C语言环境,同时保留了汇编代码高效,快速的特点。C51编译器的功能不断增强, 使你可以更加贴近CPU本身,及其它的衍生产品。C51已被完全集成到uVision2的集成开发环境中,这个集成开发环境包含:编译器,汇编器,实时操作系统,项目管理器,调试器。

系统功能:

Keil C51软件提供丰富的库函数和功能强大的集成开发调试工具,全Windows界面,使您能在很短的时间内就能学会使用keil c51来开发您的单片机应用程序 。

  另外重要的一点,只要看一下编译后生成的汇编代码,就能体会到Keil C51生成的目标代码效率非常之高,多数语句生成的汇编代码很紧凑,容易理解。在开发大型软件时更能体现高级语言的优势。

3.1测试结果截图                          

加法计算                                     减法计算                                   

                   

       图3.1 加法计算结果                                     图3.2 减法计算结果

乘法计算                                     除法计算

                    

图3.3 乘法计算结果                                     图3.4 除法计算结果                          

3.2故障及处理

遇到的主要问题出现在LCD1602上,在不加芯片调试时,LCD1602只显示一排全黑,一般说明该元件是好的。(但也不一定,我那时就一直认为我的元件没坏);给15,16管脚分别接上+5v和0v,测试背光是否完好;给VEE接上电位器,检查对比度是否可调。

一般LCD易出现的现象,我在做实验的时候遇到过以下几种情况:

①状态1
上电之后,1602的第一行全黑,即16个5x7黑块

产生原因:液晶根本就没有进行初始化操作,需要检查连线或者程序。有的情况下就是整块LCD是坏的。

②状态2
屏上显示两排灰格
产生原因:程序中对液晶初始化不正常,应是部分初始化指令没有正常接收,建议按照标准初始化步骤调整程序,或者调整指令之间的延时(加大一些试试),也有可能是对比度太大,建议优先调整对比度电阻。

③状态3
显示乱码

原因是接线存在问题。

4.总结

课程设计是培养学生综合运用所学知识,发现、提出、分析和解决实际问题,锻炼实践能力的重要环节,是对学生实际工作能力的具体训练和考察过程。随着科学技术发展的日新日异,单片机已经成为当今计算机应用中空前活跃的领域, 在生活中可以说得是无处不在。因此作为电子信息工程专业的学生来说掌握单片机的开发技术是十分重要的。
    我的题目是简易计算器,对于我们这些实践中的新手来说,这是一次考验。怎么才能找到课堂所学与实际应用的最佳结合点?怎样让自己的业余更接近专业?怎样让自己的计划更具有序性,而不会忙无一用?这都是我们所要考虑和努力的。这次课程设计我学到很多很多的东西,学会了怎么样去制定计划,怎么样去实现这个计划,并掌握了在执行过程中怎么样去克服心理上的不良情绪。不仅巩固了以前所学过的知识,而且学到了很多在书本上所没有学到过的知识,掌握了一种系统的研究方法,可以进行一些简单的编程。通过这次课程设计使我懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,才能真正为社会服务,从而提高自己的实际动手能力和独立思考的能力。同时在设计的过程中发现了自己的不足之处,对以前所学过的知识理解得不够深刻,掌握得不够牢固,对单片机汇编语言掌握得不够好。

    这次课程设计通过我们小组的努力终于顺利完成了,在设计中遇到了很多编程问题,最后在老师的辛勤指导下,终于迎刃而解,在此我表示感谢!同时,对给过我帮助的所有同学和各位指导老师再次表示忠心的感谢!

5附录

5.1附录总体硬件电路原理图

5.2附录源程序

#include<reg51.h>

#define     CLEARSCREEN     LCD_write_command(0x01)

#define uint unsigned int

#define uchar unsigned char

/**************定义接口************************/

#define     LCDIO      P0

#define     KEYBOARD   P1//保留

sbit LCD1602_RS=P2^0;   

sbit LCD1602_RW=P2^1;  

sbit LCD1602_EN=P2^2;   

/************************************************/

code uchar mayuan[16]={'0','1','2','3','4','5','6','7','8','9','0','/','*','-','+','='};//不错,这个比较明了

unsigned char code keycode[]={0x11,0x21,0x41,0x81,0x12,0x22,0x42,0x82,

0x14,0x24,0x44,0x84,0x18,0x28,0x48,0x88};//键盘编码值()

int i,j,k=1,s;//

int t,t1,t2,a[];//

void delay(uchar);//延时

/**************定义函数************************/

void LCD_init(void);//初始化函数

void delay_nms(unsigned int n);//延时函数

void LCD_write_command(unsigned char command);//写入指令函数

void LCD_write_dat(unsigned char dat);//写入数据函数

void delay_10ms();

initial();

uchar keyscan();//键盘扫描函数

calc(uchar);//计算函数

uchar num,temp,key,keynum;

void main()//主函数

    LCD_init();

    delay_nms(100);

    while(1)

    {    

           initial();//有中断

           KEYBOARD =0xf0;//键盘的列值全置高电平

    }

}

/**********************************开中断***************************************/

initial()

{

EA=1;//总开关

EX0=1;//中断方式0开启

IT0=0;

}

/*******************************************************************************/

/*********************************中断函数************************************/

void inter0() interrupt 0

{

unsigned char n;

delay_10ms();//延时

if(INT0==0)//没键按下

{

EX0=0;//关中断

n=keyscan();

calc(n);

EX0=1;//开中断

KEYBOARD=0xf0;//键盘的列值全置高电平

}

}

/************************************************************************/

calc(uchar n)

{

    if(n<10)//键值小于10

           {

                  t1=t1*10+n;

                  LCD_write_command(0x00);//写命令语句

                  LCD_write_dat(mayuan[n]);//写数据函数

           }

           else

                  {

                         if(n==10){LCD_init();t1=0;t2=0,t=0;k=1;}

                                else{

                                       if(n<15){

                                              t2=t1;t1=0;j=n;

                                              LCD_write_command(0x00);

                                       LCD_write_dat(mayuan[n]);}

                                       else{

                                              LCD_write_command(0x00);

                                              LCD_write_dat(mayuan[n]);

                                       switch(j){

                                              case 11:

                                                     t=t2/t1;

                                                     break;

                                              case 12:

                                                     t=t2*t1;

                                                     break;

                                              case 13:

                                                     t=t2-t1;

                                                     break;

                                              case 14:

                                                     t=t2+t1;

                                                     break;

                                                     }

                                              if(t<=9){ LCD_write_command(0x00);

                                              LCD_write_dat(t+48);}

                                              if(t>9)

                                                     {

                                                            while(t>9)

                                                            {

                                                                   s=t%10;

                                                                   t=t/10;

                                                                   a[k]=s;

                                                                   k++;

                                                            }

                                                            if(t<=9){

                                                                   LCD_write_command(0x00);

                                                            LCD_write_dat(t+48);}

                                                            for(i=k-1;i>=1;i--)

                                                            {

                                                                   LCD_write_command(0x00);

                                                                   LCD_write_dat(a[i]+48);

                                                            }

                                                     }

                                              }

                                       }

                                }

                         }

/*****************************************键盘扫描函数************************************/

uchar keyscan()//键盘扫描

{

KEYBOARD=0xf0;//键盘的列值全置高电平

delay_10ms();//延时

if(KEYBOARD!=0xf0)//有键按下

{

temp=KEYBOARD;//保存键盘此刻的键植

delay_10ms();//延时

if(KEYBOARD==temp)//再次确认键盘是否被按下

{

uchar i;

KEYBOARD=0x0f;//键盘的行值全置高电平

delay_10ms();//10MS时间延时

keynum=temp | KEYBOARD;//保存键盘的行值

while(KEYBOARD!=0x0f);//松手检测

for(i=0;i<16;i++)

if(keycode[i]==~keynum)

return (i);

}

}

return -1;

}

/******************************************************************************/

/********** 延时**********************/

void delay_nms(unsigned int n)     

{

       unsigned int i=0,j=0;

       for (i=n;i>0;i--)

       for (j=0;j<10;j++); 

}

void delay_10ms()//10MS延时

{

unsigned char i,j;

for(i=0;i<10;i++)

for(j=0;j<120;j++);

}

/**************************************/

/**************写指令函数********************************/ 

void LCD_write_command(unsigned char command)

{

      LCDIO=command;

      LCD1602_RS=0;  

      LCD1602_RW=0;

      LCD1602_EN=0;

      LCD1602_EN=1;

      delay_nms(10);

}

/***************************************************/

/****************写数据函数************************/

void LCD_write_dat(unsigned char dat)

{

LCDIO=dat;

LCD1602_RS=1;

LCD1602_RW=0;

LCD1602_EN=0;

delay_nms(1);

LCD1602_EN=1;

}

/****************************************************/

/************初始化函数****************/

void LCD_init(void)

{

CLEARSCREEN;//clear screen

LCD_write_command(0x38);//set 8 bit data transmission mode

LCD_write_command(0x0c);//open display (enable lcd display)

LCD_write_command(0x80);//set lcd first display address

CLEARSCREEN;//clear screen

}

/****************************************************/

6.3附录C  元器件清单

表C1 元器件清单

参考文献

[1]李建忠.单片机原理及应用[M]西安:西安电子科技大学出版社,20##年2月,第二版

[2]阎石.数字电子技术基础[M]高等教育出版社,20##年3月,第五版

[3]zlttaogede.LCD1602[J]百度文库,20##年7月27日

相关推荐