基于单片机简易计算器的设计正文

更新时间:2023-06-08 15:23:01 阅读量: 实用文档 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

51单片机简易计算器的课程设计

摘 要

近年来随着科技的飞速发展,单片机的应用正在不断深入,同时带动传统控制检测技术日益更新。在实时检测和自动控制的单片机应用系统中,单片机往往作为一个核心部件来使用,但仅单片机方面的知识是不够的,还应根据具体硬件结构、软硬件结合,来加以完善。

计算机在人们的日常生活中是比较常见的电子产品之一。可是它还在发展之中,以后必将出现功能更加强大的计算机,基于这样的理念,本次设计是用AT89S51单片机、LCD显示器、控制按键为元件来设计的计算器。利用此设计熟悉单片机微控制器及C语言编程,对其片资源及各个I/O端口的功能和基本用途的了解。掌握Microsoft Visual C++ 6.0应用程序开发环境,常用的LCD显示器的使用方法和一般键盘的使用方法。

关键词:51单片机;LCD ;控制按键

51单片机简易计算器的课程设计

目 录

1 AT89C51单片机功能概述 ........................................................................................ 1

1.1 单片机系统概述....................................................................................... 1 1.2 AT89C51功能概述 ...................................................................................... 1

1.2.1 引脚功能说明 ....................................................................................... 1

2 Keil软件知识 ......................................................................................................... 3

2.1 Keil编译器软件简介 ................................................................................... 3

2.1.1 使用Keil软件建立一个工程 .............................................................. 4 2.1.2 使用Debug进行调试 .......................................................................... 8

3 系统总体方案设计 ................................................................................................. 10

3.1 具体设计 ...................................................................................................... 10 3.2系统方案图 ................................................................................................... 10 3.3计算器软件程序要完成以下模块的设计 ................................................... 11 4 总体程序框图.......................................................................................................... 11

4.1系统总体框图设计 ....................................................................................... 11 4.2 算数运算程序设计 ...................................................................................... 13 4.3 程序源代码( C语言 ) ........................................................................... 14 5 联机调试.................................................................................................................. 19 参考文献...................................................................................................................... 20 附录1 计算器仿真图 ................................................................................................ 21 附录2 系统程序......................................................................................................... 22

51单片机简易计算器的课程设计

单片机课程设计

III

51单片机简易计算器的课程设计

1 AT89C51单片机功能概述

1.1 单片机系统概述

随着材料科学、工艺技术、计算机技术的发展与进步,电路系统向着集成度极高的方向发展。CPU的生产制造技术,也朝着综合性、技术性、实用性发展。如CPU的运算位数从4位、8位 到32位机的发展,运算速度从8 MHz、32 MHz 到1.6 GHz。可以说是日新月异的发展着。其中单片机在控制系统中的应用是越来越普遍了。单片机控制系统是以单片机(CPU)为核心部件,扩展一些外部接口和设备,组成单片机工业控制机,主要用于工业过程控制。要进行单片机系统设计首先必须具有一定的硬件基础知识;其次,需要具有一定的软件设计能力,能够根据系统的要求,灵活地设计出所需要的程序;第三,具有综合运用知识的能力。最后,还必须掌握生产过程的工艺性能及被测参数的测量方法,以及被控对象的动、静态特性,有时甚至要求给出被控对象的数学模型。

1.2 AT89C51功能概述

AT89C51是美国ATMEL公司生产的低电压,高性能CMOS 8位单片机,片内含4K bytes的可反复擦写的只读程序存储器PEROM和128bytes的随机存取数据存储器,器件采用公司的高密度,非易失性存储技术生产,兼容标准MCS-51指令系统,片内置通用8位中央处理器和FLASH存储单元,功能强大。此单片机可为您提供许多高性价比的应用场合。

AT89C51提供以下标准功能:4K字节FLASH闪速存储器,128字节内部RAM,32个I/O口线,两个16位定时/计数器,一个向量两级中断结构,一个全双工串行通讯口,内置一个精密比较器,片内振荡器及时钟电路,同时AT89C51可降至0Hz的静态逻辑操作,并支持两种软件可选的工作模式,空闲方式停止CPU的工作,但允许RAM,定时计数器,串行通信及中断系统继续工作。掉电方式保存RAM中的内容,但振荡器停止工作,并禁止其它所有部件工作直到下一个硬件复位。

1.2.1 引脚功能说明

MCS-51是标准的40脚双列直插式集成电路芯片,引脚排列请参见图2.1:

51单片机简易计算器的课程设计

图2.1 AT89C51的引脚图 VCC:电源电压; GND:地;

P0口:P0口是一组8位漏极开路型双向I/O口,也即地址/数据总线复用口。作为输出口用时,每位能吸收电流的方式驱动8个TTL逻辑门电路,对端口写1可作为高阻抗输入端用。 在访问外部数据存储器或程序存储器时,这组口线分时转换地址(低8位)和数据总线复用,在访问期间激活内部上拉电阻。

在FLASH编程时,P0口接受指令字节,而在程序效验时,输出指令字节,效验时,要求外接上拉电阻。

P1口:P1口是一个带有内部上拉电阻的8位双向I/O口,P1的输出缓冲级可驱动 (吸收或输出电流)4个TTL逻辑门电路。对端口写1,通过内部的上拉电阻把端口拉到高电平,此时可作输入口。作输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉底时会输出一个电流。

FLASH编程和程序效验期间,P1接收低8位地址。

P2口:P2口是一个带有内部上拉电阻的8位双向I/O口,P2的输出缓冲级可驱动 (吸收或输出电流)4个TTL逻辑们电路。对端口写1,通过内部的上拉电阻把端口拉到高电平,此时可作输入口。作输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉底时会输出一个电流。

在访问外部程序存储器或16位地址的外部数据存储器(例如执行MOVX@DPTR指令)时,P2口送出高8位地址数据。在访问8位地址的外部数据存储器(如执行MOVX@RI)时,P2口线上的内容(也即特殊功能寄存器(SFR)区中R2寄存器的内容),在整个访问期间不改变。

FLASH编程或效验时,P2亦接收高位地址和其它控制信号。

P3口:P3口是一个带有内部上拉电阻的8位双向I/O口,P3的输出缓冲级可驱动 (吸收或输出电流)4个TTL逻辑们电路。对端口写1,通过内部的上拉电阻把端口拉到高电平,此时可作输入口。作输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉底时会输

51单片机简易计算器的课程设计

出一个电流。

P3口除了作为一般的I/O口线外,更重要的用途是他的第二个功能,如下表所示: 表1

P3口还接收一些用于FLASH闪速存储器编程和程序效验的控制信号。

RST:复位输入。其引脚一旦变成两个机器周期以上的高电平,所有的I/O口都将复位到1状态,当振荡器正在工作时,持续两个机器周期以上高电平便可完成复位,每个机器周期为12个振荡时钟周期。

EA/VPP:外部访问允许,欲使CPU仅访问外部程序存储器(0000H—FFFFH),EA端必须保持低电平接地,需注意的是:如果加密位LB1被编程,复位是内部会锁存EA端状态。 如EA端为高电平(接VCC端),CPU则执行内部程序存储器中的指令。 FLASH存储器编程时,该引脚加上+12V的编程允许电源VPP,当然这必须是该器件是使用12V编程电压VPP。

XTAL1:振荡器反相放大器的及内部时钟发生器的输入端。 XTAL2:振荡器反相放大器输出端

2 Keil软件知识

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

2.1 Keil编译器软件简介

Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,与汇编相比,C语言在功能上、结构性、可读性、可维护性上有明显的优势,因而易学易用。用过汇编语言后再使用C来开发,体会更加深刻。Keil C51软件提供丰富的库函数和功能强大的集成开发调试工具,全Windows界面。另外重要的一点,只要看一下编译后生成的汇编代

51单片机简易计算器的课程设计

码,就能体会到Keil C51生成的目标代码效率非常之高,多数语句生成的汇编代码很紧凑,容易理解。在开发大型软件时更能体现高级语言的优势。下面详细介绍Keil C51开发系统各部分功能和使用。

图2.1 C51工具包整体结构图

Keil C51单片机软件开发系统的整体结构C51工具包的整体结构,如图3.1所示,其中uVision与Ishell分别是C51 for Windows和for DOS的集成开发环境(IDE),可以完成编辑、编译、连接、调试、仿真等整个开发流程。开发人员可用IDE 本身或其它编辑器编辑C 或汇编源文件。然后分别由C51及A51编译器编译生成目标文件(.OBJ)。目标文件可由LIB51创建生成库文件,也可以与库文件一起经L51连接定位生成绝对目标文件(.ABS)。ABS文件由OH51转换成标准的Hex文件,以供调试器dScope51或tScope51使用进行源代码级调试,也可由仿真器使用直接对目标板进行调试,也可以直接写入程序存贮器如EPROM 中。

2.1.1 使用Keil软件建立一个工程

Keil是目前进行51单片机开发最常用的编译软件。关于Keil的使用,有很多的资料介绍,这里只介绍其整个编译过程,在最短时间内开始使用Easy 51DP-2开发板。对于Keil更详细的介绍,可以参考一些专门书籍资料。在Keil里,每一个完整的程序,都是以一个工程的形式建立的。一个工程里可以有一个或多个*.c文件和*.h文件,但只可以有一个main()函数。一般的做法是将包含main()函数的C文件加入到工程中,其他文件以#include头文件的形式加到这个C文件里。这样,在编译的时候,其他的文件会被自动的导入到工程里来。

打开Keil软件后,出现(图3.2)所示界面。当然,如果Keil在上次关闭时有打开的工程,再一次打开时它会自动加载上一次的工程文件。

51单片机简易计算器的课程设计

图2.2 Keil软件主界面

首先点击Project->New Project…(Project->Open Project…为打开一个已经存在的工程),如图3.3所示。

图2.3 Keil软件打开新工程界面

点开后,在出现的对话框中选择工程存在路径,单击“保存”后,出现(如图3.4所示)界面。在此界面上选择电路板上所用的单片机型号:Atmel AT89S51(或者是AT89S52,视开发板上具体型号而定),单击“确定”。

51单片机简易计算器的课程设计

图2.4 选择电路板上所用的单片机型号

设置完成后,软件会提示“是否将8051上电初始化程序添加入工程?”如图3.5所示,这个一般选择“否”。(关于STARTUP.A51的相关内容可查阅相应资料)

图2.5 是否将8051上电初始化程序添加入工程

这样,就建立了一个空的51工程。

接下来的事,就是在这个工程里面加入自己的程序代码。点击

,或者

File->New,便建立了一个空的文本框。现在,就可以开始在里面输入你的代码了。

保存时注意:如果是用C语言写的程序,则将文本保存成*.c,如果是用汇编写的程序,则将文本存成*.asm。

到目前为步,我们已经建立了一个工程,也写了一个程序代码。但现在还不能开始编译。因为还没有将程序代码添加到工程里面去。

51单片机简易计算器的课程设计

下一步就是将写完的程序添加到工程里面,如图3.6所示,在左边Project Workspace里的Source Group 1上右击,选择Add Files to Group ’Source Group 1’。在打开的对话框中,选择刚存的文件路径和对应的扩展名。这样,程序就添加进了这个工程。

图2.6 添加文件到工程中

下一步,就开始编译刚输入进去的代码。点击工具栏中的Keil会打出下面的提示:

Build target 'Target 1' assembling led.asm... linking...

Program Size: data=8.0 xdata=0 code=100 "first" - 0 Error(s), 0 Warning(s).

按钮。接着,

其中“"first" - 0 Error(s), 0 Warning(s).”说明现在的工程编译通过,0个错误和0个警告。建立工程的时候,默认是不生成HEX文件的,得在编译做如下设置:单击

,或者在Project Workspace里Target 1上右击,选择“Options for Target

‘Target 1’”。出现如图3.7所示对话框,选择“Output”按图示,将箭头所指的多选框勾上,点“确定”。

51单片机简易计算器的课程设计

现在再点击

重新编译,系统提示:“creating hex file from "first"...”。便

会在工程所在文件夹里生成HEX文件。

图2.7 生成HEX文件

2.1.2 使用Debug进行调试

Keil有很强大的调试功能,可以显示C程序的反汇编代码、可以计算代码运行的时间、可以显示程序中某一变量的值 能用好这个调试工具对编写单片机程序会有很大的帮助。同样的,在这里,只对Debug进行简单应用介绍,更详细的使用方法可以参看相关书籍资料。

51单片机简易计算器的课程设计

图2.8 调试前设置窗口

首先,单击,弹出如图3.8所示对话框,在Target页面上设置对应的晶

,进入调试界面(如图3.9所

振频率。其他不用作修改。设置完成后,单击示)。

图2..9 Keil调试界面

51单片机简易计算器的课程设计

点击

中对应的工具按钮则可以开始调试。

另外,“View”下的三个工具在调试中会经常用到如.图3.10所示,“Disassembly Window”显示C文件的反汇编程序;“Watch & Call Stack Window”可以显示程序中某一变量的值;“Memory Window”可以显示内存中某一地址的值。

3 系统总体方案设计

3.1 具体设计

根据功能和指标要求,本系统选用MCS-51系列单片机为主控机。通过扩展必要的外围接口电路,实现对计算器的设计。具体设计如下:

1.1 四则运算:

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

1.2 键盘:

另外键盘包括数字键(0~9)、符号键(+、-、×、÷)、清除键和等号键,故只需要16 个按键即可,设计中采用集成的计算键盘。

1.3 执行过程:

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

1.4 错误提示:

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

3.2系统方案图

51单片机简易计算器的课程设计

3.3计算器软件程序要完成以下模块的设计

1、 2、 3、 4、

键盘输入检测模块 LCD显示模块; 算术运算模块

错误处理及提示模块。

4 总体程序框图

4.1系统总体框图设计

51单片机简易计算器的课程设计

单片机课程设计

开始

初始化参数

初始化 LCD 显示

Y 有键输 读取键码

N 数字键 清零键 功能键

输入数值

状态清零

根据上次功能键和 输入的数据计算结

本次功能 键?

结果送显示缓 冲 等待数值输入

结果送显示缓 冲 等待数值输入

结果送

显示缓 冲 数值送显示缓冲 等待数值输入

LCD 显示

12

51单片机简易计算器的课程设计

4.2 算数运算程序设计

51单片机简易计算器的课程设计

4.3 程序源代码( C语言 )

#include <intrins.h> #include <reg51.h> #include "calc.h"

//变量声明

static data LONG lvalue; static data LONG rvalue; static data CHAR currtoken; static data CHAR lasttoken; static data CHAR lastpress;

static xdata CHAR outputbuffer[MAX_DISPLAY_CHAR];

VOID main (VOID)

//初始化变量并且初始化 LCD 驱动. { lvalue = 0; rvalue = 0; currtoken = '='; lasttoken = '0';

initialise(); // 初始化 LCD calc_output(OK); calc_evaluate(); }

VOID calc_evaluate() { CHAR data key; INT data i;

CHAR xdata number[MAX_DISPLAY_CHAR]; CHAR xdata *bufferptr;

// 使用前清缓冲器.

for (i = 0; i <= MAX_DISPLAY_CHAR; i++) { number[i] = ' '; }

bufferptr = number;

for (;;)

{ key = calc_getkey(); if (calc_testkey(key))

//键盘检测数字写入缓存然后输出到屏幕LCD. // 限制结果数字的范围或结果为负数.

{ if (bufferptr != &number[MAX_DISPLAY_CHAR - 2]) { *bufferptr = key;

calc_display(number); bufferptr++;

51单片机简易计算器的课程设计

} } else

// 键盘运算符传送到操作函数.

// 如果刚开始或者刚取消则指到lvalue // 否则指到 rvalue. {

//发送到 value.

if (lasttoken == '0')

{ lvalue = calc_asciidec (number);} else

{ rvalue = calc_asciidec (number);}

//清数字缓存器.

bufferptr = number;

for (i = 0;i <= MAX_DISPLAY_CHAR; i++) { number[i] = ' '; }

//继续运行处理器. currtoken = key;

if (currtoken == 'C')

{ calc_opfunctions(currtoken); } else

{ calc_opfunctions(lasttoken); }

//清除输出缓存为了下个运行程序 .

for (i = 0;i <= MAX_DISPLAY_CHAR;i++) { outputbuffer[i] = ' ';}

bufferptr = number; // 暂时运行等于程序.

if (currtoken != 0x3D) lasttoken = currtoken; }

lastpress = key; } }

VOID calc_opfunctions (CHAR token) // Lvalue保存着结果 检测结果运行. { CHAR data result; switch(token) // 加.

{ case '+' : if ((currtoken == '=' ) || ((lastpress >= 0x30) &&

51单片机简易计算器的课程设计

(lastpress <=0x39)))

{ lvalue += rvalue;

result = calc_chkerror(lvalue); } else

{ result = SLEEP; } break; // 减.

case '-' : if ((currtoken == '=' ) || ((lastpress >= 0x30) && (lastpress <=0x39)))

{ lvalue -= rvalue;

result = calc_chkerror(lvalue); } else

{ result = SLEEP;} break; // 乘.

case '*' : if ((currtoken == '=' ) || ((lastpress >= 0x30) && (lastpress <=0x39)))

{ lvalue *= rvalue;

result = calc_chkerror(lvalue); } else

{ result = SLEEP;} break; // 除.

case '/' : if ((currtoken == '=' ) || ((lastpress >= 0x30) && (lastpress <=0x39)))

{ if (rvalue)

{ lvalue /= rvalue;

result = calc_chkerror(lvalue); } else

{ result = ERROR;} } else

{ result = SLEEP;} break; // 清.

case 'C' : lvalue = 0; rvalue = 0;

currtoken = '0'; lasttoken = '0'; result = OK; break;

default : result = SLEEP;

}

51单片机简易计算器的课程设计

calc_output(result); }

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

***** 实用路径 *****

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

INT calc_chkerror (LONG num)

// 检查数字范围是 99999999 and -99999999.

{ if ((num >= -9999999) && (num <= 9999999)) return OK; else

return ERROR; }

VOID calc_output (INT status) // 根据函数的位置输出.

// *Sleep*用在大的取消或开始后的第一次按键. { switch (status)

{ case OK : calc_display(calc_decascii(lvalue)); break; case SLEEP : break; case ERROR : calc_display("Exception "); break; default : calc_display("Exception "); break; } }

LONG calc_asciidec (CHAR *buffer) //转换 ASCII码成数. { LONG data value; LONG data digit; value = 0;

while (*buffer != ' ')

{ digit = *buffer - 48; value = value*10 + digit; buffer++; }

return value; }

51单片机简易计算器的课程设计

CHAR *calc_decascii (LONG num)

// 运行将一个浮点数转换成 ASCII 码. { LONG data temp = num;

CHAR xdata *arrayptr = &outputbuffer[MAX_DISPLAY_CHAR]; LONG data divisor = 10; LONG data result;

CHAR data remainder,asciival; INT data i;

// 如果计算结果是0的话在缓存嵌入0并且结束. if (!temp)

{ *arrayptr = 48; goto done; }

//处理负数. if (temp < 0)

{ outputbuffer[0] = '-'; temp -= 2*temp; }

for (i=0 ; i < sizeof(outputbuffer) ; i++) { remainder = temp % divisor; result = temp / divisor;

// 运行到最后嵌入到缓存.

if ((!remainder) && (!result)) { *arrayptr = ' ';}

else

{ asciival = remainder + 48; *arrayptr = asciival; }

temp /= 10;

// 给负号留个位子.

if (arrayptr != &outputbuffer[1]) arrayptr--; }

done: return outputbuffer; }

本文来源:https://www.bwwdw.com/article/gef1.html

Top