单片机实现的简易计算器源代码2005暑期生产实习单片机实现的简易计算器总结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)/1112.3+5.4=/0.1+77等号后直接按/,则将前面的运算结果作为第一个操作数1/0=E错误显示9.不足使用3字节的浮点数表示,不可避免的带来了数表示的不精确,加上有效数字比较少,因此计算结果很容易产生误差,尤其是进行连续多次运算后,结果和精度较高的科学计算器的误差会很快达到0.01以上,当然这个差距和所测试的用例也有关系,4位有效数字导致了数字123456只能表示为123400,最后两位有效数字被摒弃了。同时,虽然纯整数可以进行较为高精度的运算,实现也较为容易,但是考虑到要和浮点数混合在一起处理,如果在算法上分别考虑整数和浮点数,整个程序框架代码将会膨胀不少,因此将其简化为统一作为浮点数对待。10.源代码2000行左右(含注释、空行),其中浮点程序库约900行。其余为键盘输入扫描、液晶输出显示和按键处理程序。文件大小47.2KB-=-=-=-=-=-=-=-=-=-=-=-=SOURCECODE=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-;;;;显示程序符号定义;;COMEQU45HDATEQU46HCW_ADDEQU5FFCHCR_ADDEQU5FFDHDW_ADDEQU5FFEHDR_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为显示区域与记录输入数字所用,RAWINPNTBBIT10H;小数点位指示(位地址,POINTBIT)POSBBIT11H;位置位,POSB=1表示创建BCD低位,POSB=0表示创建BCD高位DPBBIT12H;大于1的浮点数MAKENUM时,指示小数点是否已经加入;04H-08H,ARBITRARYUSEBYTE2BIT14H;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:EQUALSIGNPRESSEDSTATEQU20HDCOUNTEQU21H;数字位数计数(DIGITCOUNT),只是RAWIN中有效字节INPUTEQU2AH;键盘输入暂存RAWPTREQU2BH;显示缓冲区指针NUMPTREQU2CH;当前组建数字的指针TEMP1EQU2DH;临时存储,一般用于临时保存R0,R1TEMP2EQU2EH;以切换寄存器组,UNUNSED...07.25.NIGHT;-=-=2.IRAM=-=-;30H-33H为第一个操作数;34H-37H为第二个操作数;38H-3FH为显示区域;48H-4FH为临时存储区域;结果则存储在第一个操作数位置NUM1EQU30HNUM2EQU34HRAWINEQU38HTEMPEQU48H;-=-=-=3.REGISTERS=-=-=-;键盘扫描使用寄存器组0,浮点程序使用寄存器组2;其余数字组合部分用寄存器组1;测试程序使用寄存器组3;ASCIITABLE;'.'-2EH;'+'-2BH;'-'-2DH;'*'-2AH;'/'-2FH;'='-3DH;////////////////////////////////////////////////////////////////////;///;///THE[MAIN]PROGRAM;///ZEROX@2005.7.14;////////////////////////////////////////////////////////////////////ORG0000HLJMPMAINORG0030HMAIN:;全局初始化MOVSP,#60H;堆栈MOVIE,#00H;禁止所有中断;寄存器组00CLRRS1CLRRS0;工作区IRAM(20H-5FH)默认全为0INIT20TO5F:MOVR0,#20H;STARTAT20HMOVR7,#40H;64BYTESTOZEROLOOP20TO5F:MOV@R0,#00HINCR0DJNZR7,LOOP20TO5F;---------------------------------SETBSTAT.0;初始状态为等号状态MOVR7,#00HMOVSCON,#00H;串行工作方式0;-------------------------------------;;DISPLAYINIT;-------------------------------------LCALLLCDINITMOVCOM,#06HLCALLPR1MOVCOM,#0C0HLCALLPR1MAIN_LOOP:;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;键盘输入;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;获取键盘输入,使用寄存器组00CLRRS1CLRRS0;获取输入MOVA,#0F0HWAITKEY:NOPCJNEA,#0F0H,WAITKEY_OKLCALLKEYSJMPWAITKEYWAITKEY_OK:MOVA,R7MOVINPUT,A;保存键盘输入到INPUT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;按键响应(内部处理);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;处理键盘输入,使用寄存器组01CLRRS1SETBRS0LCALLKEYPRESSED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;显示;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;LCALLDISPLAYSJMPMAIN_LOOP;========================================================;==;==SUBROUTINES;==;========================================================KEYPRESSED:;键盘输入保存在A中,同时也保存在INPUT中ANLA,#0F0H;屏闭低4位字节JNZNONDIGIT;高位非零,不是数字;=========================================;按键为数字;否则按下的是数字,添加到显示缓冲区MOVA,INPUT;取回数字,高位已经是0;如果之前处于“等号”状态,则此为NUM1JBSTAT.0,NEWNUM1;如果之前处于运算符状态,则此为NUM2JBSTAT.3,NEWNUM2;如果处于第一个数字状态JBSTAT.1,INNUM1;如果处于第二个数字状态JBSTAT.2,INNUM2;否则出错!!SETBSTAT.7;ERRORBITRET;KEYPRESSED直接结束;--------------------------NEWNUM1:ANLSTAT,#0F0H;操作状态清零(低4位)SETBSTAT.1;计算器状态改为NUM1;同时清除浮点运算状态CLRSTAT.6;STAT.6-FLOATINGPOINTSJMPNEWNUMNEWNUM2:ANLSTAT,#0F0H;操作状态清零(低4位)SETBSTAT.2;计算器状态改为NUM2SJMPNEWNUMNEWNUM:;准备开始一个新的操作数,首先清除显示缓冲区MOVRAWPTR,#RAWIN;指向开始;清除小数点标志位CLRPNTBMOVDCOUNT,#00H;数字个数清零;判断数字是否为0,0则忽略JZIGNORE0;非零数字,保存MOVRAWIN,A;此时RAWPTR单元的值,也就是地址;就是RAWININCRAWPTR;数字位数增1INCDCOUNTIGNORE0:RET;--------------------------INNUM1:INNUM2:MOVR2,DCOUNTCJNER2,#08H,INNUM_OK;数字个数已经达到最大值,忽略本次输入RETINNUM_OK:MOVR0,RAWPTR;使用R0间接寻址MOV@R0,AINCRAWPTRINCDCOUNTRET;=========================================;按键非数字NONDIGIT:MOVA,INPUT;恢复AINCA;'.'用0FFH表示,加1后为0JZDECPNT;DECIMALPOINTPRESSEDDECA;否则不是小数点,减一恢复之;非数字的情况:;1.加,减,乘,除:高4位应该分别为0001,0010,0011,0100;2.小数点:代码为0FFH,前面已经考虑;3.等号:10000000(80H);首先检查是否是等号(最高位为1)JBACC.7,KEYEQU;否则作为运算符对待LJMPKEYOP;---------------------------------ERRORND:;ERROROFNON-DIGIT;出错…………SETBSTAT.7LJMPEXIT;=======================================================DECPNT:;根据计算器状态进行操作JBSTAT.1,DP1JBSTAT.2,DP2JBSTAT.3,DP3JBSTAT.0,DP0;ERRORSETBSTAT.7LCALLEXITDP1:DP2:;在数字输入状态下下按下了小数点,如果之前已经按过小数点;则忽略此次输入,计算器状态字无需修改JBPNTB,DP_DONE;小数点已经按下;否则,这是本次操作数输入第一次按下小数点;首先设置小数点已经按下标志位SETBPNTB;否则添加小数点到输入区,也就是显示区;首先判断第一个数字是不是0MOVR0,RAWPTR;获取指针用于比较;如果当前输入位置不是开始(