51计算器.docx

上传人:b****4 文档编号:26821251 上传时间:2023-06-23 格式:DOCX 页数:45 大小:36.63KB
下载 相关 举报
51计算器.docx_第1页
第1页 / 共45页
51计算器.docx_第2页
第2页 / 共45页
51计算器.docx_第3页
第3页 / 共45页
51计算器.docx_第4页
第4页 / 共45页
51计算器.docx_第5页
第5页 / 共45页
点击查看更多>>
下载资源
资源描述

51计算器.docx

《51计算器.docx》由会员分享,可在线阅读,更多相关《51计算器.docx(45页珍藏版)》请在冰豆网上搜索。

51计算器.docx

51计算器

51单片机实现的简易计算器

1.4X4键盘输入,点阵字符型液晶显示。

2.由于所采用的浮点程序库的限制(MCU平台只找到这个……),浮点运算采用3字节二进制补码表示,有效数字6位。

对于输入输出,采用3字节BCD码浮点数格式,有效数字只有4位,因此最终有效数字只有4位。

3.可进行连续输入,例如:

1.23+4.56*8.23/234.8,但是运算结果为从左到右,这也是8位简易计算器的方式。

4.可进行错误判断,溢出、除零等错误将显示一个字符E。

5.由于键盘只有16个按键,安排如下:

+---------------+

|7|8|9|+|

|4|5|6|-|

|1|2|3|*|

|0|.|=|/|

+---------------+

6.按键的缺少导致取消了一些特殊函数,即开根号,三角函数(sin,cos,tan,ctg)的实现,由于这些函数在浮点程序库中均已提供,如果硬件允许,在原来的框架上添加这些附加功能是很容易的(可以看作和+,-,*,/等价的按键操作,调用不同的子程序进行运算即可)

7.按两次=等于清灵。

因为按键实在太少,才采用了这个做法。

8.相应举例:

按键结果说明

--------------------------------------

123+=123按下等号而没有第二个操作数,保留第一个操作数并认为此次运算结束(等号的功能)

123+321/1114.0等价于(123+321)/111

2.3+5.4=/0.1+77等号后直接按/,则将前面的运算结果作为第一个操作数

1/0=E错误显示

9.不足

使用3字节的浮点数表示,不可避免的带来了数表示的不精确,加上有效数字比较少,因此计算结果很容易产生误差,尤其是进行连续多次运算后,结果和精度较高的科学计算器的误差会很快达到0.01以上,当然这个差距和所测试的用例也有关系,4位有效数字导致了数字123456只能表示为123400,最后两位有效数字被摒弃了。

同时,虽然纯整数可以进行较为高精度的运算,实现也较为容易,但是考虑到要和浮点数混合在一起处理,如果在算法上分别考虑整数和浮点数,整个程序框架代码将会膨胀不少,因此将其简化为统一作为浮点数对待。

10.源代码

2000行左右(含注释、空行),其中浮点程序库约900行。

其余为键盘输入扫描、液晶输出显示和按键处理程序。

文件大小47.2KB

-=-=-=-=-=-=-=-=-=-=-=-=SOURCECODE=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

;;

;;显示程序符号定义

;;

COMEQU45H

DATEQU46H

CW_ADDEQU5FFCH

CR_ADDEQU5FFDH

DW_ADDEQU5FFEH

DR_ADDEQU5FFFH

;子程序说明:

;寄存器工作组使用

;WAITKEY,00

;KEYPRESSED,MAKENUM,RES2RAW等子程序,01

;FLOATINGLIB,10

;CALCULATE使用01,当调用浮点程序库时10

;显示子程序,11

;======================================================================

;工作区使用注意:

;-=-=1.位寻址区=-=-=-

;20H-21H两个字用作位状态(位地址00H-0FH)

;23H-27H;NOTUSE!

ESP.23H

;28H-2FH为显示区域与记录输入数字所用,RAWIN

PNTBBIT10H;小数点位指示(位地址,POINTBIT)

POSBBIT11H;位置位,POSB=1表示创建BCD低位,POSB=0表示创建BCD高位

DPBBIT12H;大于1的浮点数MAKENUM时,指示小数点是否已经加入

;04H-08H,ARBITRARYUSE

BYTE2BIT14H;SEEBYTE2USAGE(CTRL+F,FINDIT.)

;STAT保存整个计算器的运行状态!

;BITASSIGNMENT:

;.7:

ERROR

;.6:

FLOAT

;.5&.4:

OPERATOR

;VALUEMEANING:

;00:

ADD

;01:

SUB

;10:

MUL

;11:

DIV

;.3:

OPERATORPRESSED

;.2:

CONSTRUCTINGNUM2

;.1:

CONSTRUCTINGNUM1

;.0:

EQUALSIGNPRESSED

STATEQU20H

DCOUNTEQU21H;数字位数计数(DIGITCOUNT),只是RAWIN中有效字节

INPUTEQU2AH;键盘输入暂存

RAWPTREQU2BH;显示缓冲区指针

NUMPTREQU2CH;当前组建数字的指针

TEMP1EQU2DH;临时存储,一般用于临时保存R0,R1

TEMP2EQU2EH;以切换寄存器组,UNUNSED...07.25.NIGHT

;-=-=2.IRAM=-=-

;30H-33H为第一个操作数

;34H-37H为第二个操作数

;38H-3FH为显示区域

;48H-4FH为临时存储区域

;结果则存储在第一个操作数位置

NUM1EQU30H

NUM2EQU34H

RAWINEQU38H

TEMPEQU48H

;-=-=-=3.REGISTERS=-=-=-

;键盘扫描使用寄存器组0,浮点程序使用寄存器组2

;其余数字组合部分用寄存器组1

;测试程序使用寄存器组3

;ASCIITABLE

;'.'->2EH

;'+'->2BH

;'-'->2DH

;'*'->2AH

;'/'->2FH

;'='->3DH

;/////////////////////////////////////////////////////////////////////;///;///THE[MAIN]PROGRAM

;///ZEROX@2005.7.14

;////////////////////////////////////////////////////////////////////ORG0000H

LJMPMAIN

ORG0030H

MAIN:

;全局初始化

MOVSP,#60H;堆栈

MOVIE,#00H;禁止所有中断

;寄存器组00

CLRRS1

CLRRS0

;工作区IRAM(20H-5FH)默认全为0

INIT20TO5F:

MOVR0,#20H;STARTAT20H

MOVR7,#40H;64BYTESTOZERO

LOOP20TO5F:

MOV@R0,#00H

INCR0

DJNZR7,LOOP20TO5F

;---------------------------------

SETBSTAT.0;初始状态为等号状态

MOVR7,#00H

MOVSCON,#00H;串行工作方式0

;-------------------------------------

;;DISPLAYINIT

;-------------------------------------

LCALLLCDINIT

MOVCOM,#06H

LCALLPR1

MOVCOM,#0C0H

LCALLPR1

MAIN_LOOP:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;

;;键盘输入

;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;获取键盘输入,使用寄存器组00

CLRRS1

CLRRS0

;获取输入

MOVA,#0F0H

WAITKEY:

NOP

CJNEA,#0F0H,WAITKEY_OK

LCALLKEY

SJMPWAITKEY

WAITKEY_OK:

MOVA,R7

MOVINPUT,A;保存键盘输入到INPUT

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;

;;按键响应(内部处理)

;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;处理键盘输入,使用寄存器组01

CLRRS1

SETBRS0

LCALLKEYPRESSED

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;

;;显示

;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

LCALLDISPLAY

SJMPMAIN_LOOP

;========================================================

;==

;==SUBROUTINES

;==

;========================================================

KEYPRESSED:

;键盘输入保存在A中,同时也保存在INPUT中

ANLA,#0F0H;屏闭低4位字节

JNZNONDIGIT;高位非零,不是数字

;=========================================

;按键为数字

;否则按下的是数字,添加到显示缓冲区

MOVA,INPUT;取回数字,高位已经是0

;如果之前处于“等号”状态,则此为NUM1

JBSTAT.0,NEWNUM1

;如果之前处于运算符状态,则此为NUM2

JBSTAT.3,NEWNUM2

;如果处于第一个数字状态

JBSTAT.1,INNUM1

;如果处于第二个数字状态

JBSTAT.2,INNUM2

;否则出错!

SETBSTAT.7;ERRORBIT

RET;KEYPRESSED直接结束

;--------------------------

NEWNUM1:

ANLSTAT,#0F0H;操作状态清零(低4位)

SETBSTAT.1;计算器状态改为NUM1

;同时清除浮点运算状态

CLRSTAT.6;STAT.6->FLOATINGPOINT

SJMPNEWNUM

NEWNUM2:

ANLSTAT,#0F0H;操作状态清零(低4位)

SETBSTAT.2;计算器状态改为NUM2

SJMPNEWNUM

NEWNUM:

;准备开始一个新的操作数,首先清除显示缓冲区

MOVRAWPTR,#RAWIN;指向开始

;清除小数点标志位

CLRPNTB

MOVDCOUNT,#00H;数字个数清零

;判断数字是否为0,0则忽略

JZIGNORE0

;非零数字,保存

MOVRAWIN,A;此时RAWPTR单元的值,也就是地址

;就是RAWIN

INCRAWPTR

;数字位数增1

INCDCOUNT

IGNORE0:

RET

;--------------------------

INNUM1:

INNUM2:

MOVR2,DCOUNT

CJNER2,#08H,INNUM_OK

;数字个数已经达到最大值,忽略本次输入

RET

INNUM_OK:

MOVR0,RAWPTR;使用R0间接寻址

MOV@R0,A

INCRAWPTR

INCDCOUNT

RET

;=========================================

;按键非数字

NONDIGIT:

MOVA,INPUT;恢复A

INCA;'.'用0FFH表示,加1后为0

JZDECPNT;DECIMALPOINTPRESSED

DECA;否则不是小数点,减一恢复之

;非数字的情况:

;1.加,减,乘,除:

高4位应该分别为0001,0010,0011,0100

;2.小数点:

代码为0FFH,前面已经考虑

;3.等号:

10000000(80H)

;首先检查是否是等号(最高位为1)

JBACC.7,KEYEQU

;否则作为运算符对待

LJMPKEYOP

;---------------------------------

ERRORND:

;ERROROFNON-DIGIT

;出错…………

SETBSTAT.7

LJMPEXIT

;=======================================================

DECPNT:

;根据计算器状态进行操作

JBSTAT.1,DP1

JBSTAT.2,DP2

JBSTAT.3,DP3

JBSTAT.0,DP0

;ERROR

SETBSTAT.7

LCALLEXIT

DP1:

DP2:

;在数字输入状态下下按下了小数点,如果之前已经按过小数点

;则忽略此次输入,计算器状态字无需修改

JBPNTB,DP_DONE;小数点已经按下

;否则,这是本次操作数输入第一次按下小数点

;首先设置小数点已经按下标志位

SETBPNTB

;否则添加小数点到输入区,也就是显示区

;首先判断第一个数字是不是0

MOVR0,RAWPTR;获取指针用于比较

;如果当前输入位置不是开始(前面已有非零数字存储),直接添加小数点

CJNER0,#RAWIN,DP_ADD

;否则,RAWPTR还是指向RAWIN位置,第一个数字设置为0,

;后再添加小数点

MOVR0,RAWPTR;用R0间接寻址

MOV@R0,#00H

INCRAWPTR

INCDCOUNT

DP_ADD:

MOVR0,RAWPTR;R0间接寻址

MOV@R0,#0FFH;DECIMALPOINT

INCRAWPTR

INCDCOUNT

DP_DONE:

RET

;--------------------

DP0:

;之前的状态为等号,按下小数点后因该开始第一个操作数输入

;设置状态

ANLSTAT,#0F0H

SETBSTAT.1

SJMPDP_NEW

;--------------------

DP3:

;之前处于操作符状态,按下小数点则应该开始第二个操作数输入

;设置状态

ANLSTAT,#0F0H

SETBSTAT.2

;新的操作数开始

SJMPDP_NEW

;--------------------

DP_NEW:

;小数点开始的新的操作数,添加'0''.'两个输入

;初始化

MOVRAWPTR,#RAWIN

MOVDCOUNT,#00H

CLRPNTB

MOVRAWIN,#00H;第一个数字,0

INCRAWPTR

INCDCOUNT

MOVR0,RAWPTR;使用R0间接寻址来存储小数点

MOV@R0,#0FFH;小数点使用0FFH表示

INCRAWPTR

INCDCOUNT

RET

;=======================================================

KEYEQU:

;保存原来的状态

MOVB,STAT

;设置现在的状态为EQU

ANLSTAT,#0F0H;清楚低4位状态

SETBSTAT.0;EQUSTATBIT

;根据原来的状态采取相应的操作

JBB.1,EQU1;原来处于第一个数的输入状态

JBB.2,EQU2;原来处于第二个数的输入状态(NORMAL)

JBB.3,EQU3;原来处于操作符状态

JBB.0,EQU0;原来处于等号状态

;ERROR

SETBSTAT.7

LJMPEXIT

EQU1:

;在第一个数的状态下按了等号,那么第一个数不需要进行计算

;直接作为结果显示,实际上RAWIN就是当前的操作数的显示格式

;因此只需要将第一个数转换成浮点数存储于NUM1

SETBRS0

CLRRS1

MOVR0,#RAWIN;SOURCE

MOVR1,#NUM1;DESTINATION

LCALLMAKENUM;NOTE:

MAKENUM!

!

!

RET

EQU2:

;在第二个数的状态下按了等号,这是最普通的操作

;首先转换操作数二到NUM2位置,然后计算结果

;并将结果转化为RAWIN形式,供DISPLAY显示

MOVR0,#RAWIN

MOVR1,#NUM2;DESTINATION

LCALLMAKENUM;NOTE:

MAKENUM..

;计算结果,结果放在NUM1

LCALLCALCULATE;NOTE:

CALCULATE!

!

!

;结果转换为RAWIN,即从NUM1到RAWIN

LCALLRES2RAW;NOTE:

RES2RAW

NOP

RET

EQU3:

;原来状态为操作符,然后直接按了等号

;本程序采取的措施为:

等1号覆盖前面的操作符

;因此不需要采取任何措施,直接同按下了第一个

;操作数后直接按等号相同,由于按下操作符的时候

;已经处理了第一个操作数,因此这里直接返回

RET

EQU0:

;SYSTEMRESET

;原来状态为等号,然后又按了等号

;第一次按等号的时候已经处理好,这里只需返回

;07.24修改,连续两次等号相当于清0

;首先清除错误状态位

CLRSTAT.7

MOVDCOUNT,#00H;DCOUNT设置为0,显示就为0

RET

;========================================================

;操作符处理,注意:

前面已经判断不是等号

KEYOP:

;保存操作符号:

给定的是10H,20H,30H,40H

;转换为00H,10H,20H,30H.即,减去10H

;DEBUGHERE

CLRC

SUBBA,#10H

;INVARIANT:

除了4,5位,其他位不可能为1

KEYOP_NE:

;KEYOPERATOR,NOERROR

;如果是第一个数之后按的运算符

JBSTAT.1,KOP1

;如果是第二个数之后按的运算符

JBSTAT.2,KOP2

;如果是一个运算符之后按的运算符

JBSTAT.3,KOP3

;如果是按了等号后按的运算符

JBSTAT.0,KOP0

;ERROR

SETBSTAT.7

LJMPEXIT

;------------------

KO_NE_DONE:

;KEYOPERATOR,NOTEQUAL,DONE

;完成相应的操作后,更新STAT到当前状态

;取回INPUT,并减去10H,成为STAT要求的操作符表示

MOVA,INPUT

CLRC

SUBBA,#10H

;运算符信息保存在STAT的4,5位

;先将4,5位清0

ANLSTAT,#0CFH;#11001111B

ORLSTAT,A;设置4,5位

;设置新的计算器状态

ANLSTAT,#0F0H;清除状态(低4位)

SETBSTAT.3;操作符号状态

RET;KEYPRESSED返回

;--------

KOP1:

;如果按了第一个数字之后按了操作符

;则首先将当前显示缓冲区里的数字

;拼合为3字节浮点数

;保存在NUM1位置

;RAWIN保持不变,因此计算器显示的仍然为

;第一个操作数

MOVR0,#RAWIN;需要进行拼凑的数字

MOVR1,#NUM1;目的

LCALLMAKENUM

SJMPKO_NE_DONE

KOP2:

;如果按了第二个数字之后按了操作符,

;首先计算前面的结果,然后结果作为

;第一个数,并设置状态为操作符

;显示区域的数据为前面操作的结果

;即:

需要将3字节的浮点数结果转化

;为可以显示的RAWIN格式。

;创建第二个操作数

MOVR0,#RAWIN

MOVR1,#NUM2

LCALLMAKENUM

;执行计算

LCALLCALCULATE

;结果默认已经存储于到NUM1位置

;但是需要将其转换为RAWIN形式用于DISPLAY子程序的显示

LCALLRES2RAW;NOTE:

RES2RAW

SJMPKO_NE_DONE

KOP3:

;按了一个操作符后又按了另一个操作符,则直接忽略原来的

;前面已经设置了操作符状态,此处无需进行任何操作

SJMPKO_NE_DONE

KOP0:

;按了等号之后按的操作符,则运算结果直接作为第一个

;操作数,因为按等号的时候已经进行了结果运算和显示

;所需要的准备工作(将浮点数转换为RAWIN形式)

;因此这里不需要再作其他工作

SJMPKO_NE_DONE

;=======================================================

EXIT:

SJMP$

;=======================================================

;=======================================================

MAKENUM:

;NOTEE!

!

!

;[R0]为RAWIN

;[R1]为目标,NUM1ORNUM2

;先决条件:

见前面

;后决条件:

NUM1中为二进制浮点数(3字节,补码形式)

;转换结果,RAWIN形式的数字被转换为3字节二进制浮点数

MOVA,R0

MOVR3,A;保存源位置

MOVA,R1

MOVR4,A;保存目的位置

MOVR2,#00H;小数点位置

;保存DCOUNT,子

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 医药卫生 > 基础医学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1