SETB STAT.7 ; ERROR BIT RET ; KEYPRESSED 直接结束 ; -------------------------- NEWNUM1:
ANL STAT, #0F0H ; 操作状态清零(低4位) SETB STAT.1 ; 计算器状态改为 NUM1 ; 同时清除浮点运算状态
CLR STAT.6 ; STAT.6 -> FLOATING POINT SJMP NEWNUM NEWNUM2:
ANL STAT, #0F0H ; 操作状态清零(低4位) SETB STAT.2 ; 计算器状态改为 NUM2 SJMP NEWNUM NEWNUM:
; 准备开始一个新的操作数,首先清除显示缓冲区 MOV RAWPTR, #RAWIN ; 指向开始 ; 清除小数点标志位 CLR PNTB
MOV DCOUNT, #00H ; 数字个数清零 ; 判断数字是否为0,0则忽略 JZ IGNORE0 ; 非零数字,保存
MOV RAWIN, A ; 此时RAWPTR单元的值,也就是地址 ; 就是RAWIN INC RAWPTR ; 数字位数增 1 INC DCOUNT IGNORE0: RET
; -------------------------- INNUM1: INNUM2:
MOV R2, DCOUNT
CJNE R2, #08H, INNUM_OK
; 数字个数已经达到最大值,忽略本次输入 RET INNUM_OK:
MOV R0, RAWPTR ; 使用R0间接寻址 MOV @R0, A INC RAWPTR INC DCOUNT RET
; ========================================= ; 按键非数字 NONDIGIT:
MOV A, INPUT ; 恢复A
INC A ; '.' 用 0FFH 表示,加1后为0 JZ DECPNT ; DECIMAL POINT PRESSED DEC A ; 否则不是小数点,减一恢复之
; 非数字的情况:
; 1. 加, 减, 乘, 除: 高4位应该分别为 0001, 0010, 0011, 0100 ; 2. 小数点: 代码为 0FFH, 前面已经考虑 ; 3. 等号: 1000 0000 (80H)
; 首先检查是否是等号 (最高位为1) JB ACC.7, KEYEQU
; 否则作为运算符对待 LJMP KEYOP
; ---------------------------------
ERRORND:; ERROR OF NON-DIGIT ; 出错………… SETB STAT.7 LJMP EXIT
; ======================================================= DECPNT:
; 根据计算器状态进行操作 JB STAT.1, DP1 JB STAT.2, DP2 JB STAT.3, DP3 JB STAT.0, DP0 ; ERROR SETB STAT.7 LCALL EXIT DP1: DP2:
; 在数字输入状态下下按下了小数点,如果之前已经按过小数点 ; 则忽略此次输入,计算器状态字无需修改
JB PNTB, DP_DONE ; 小数点已经按下 ; 否则,这是本次操作数输入第一次按下小数点 ; 首先设置小数点已经按下标志位 SETB PNTB
; 否则添加小数点到输入区,也就是显示区 ; 首先判断第一个数字是不是0 MOV R0, RAWPTR ; 获取指针用于比较
; 如果当前输入位置不是开始(前面已有非零数字存储),直接添加小数点 CJNE R0, #RAWIN, DP_ADD
; 否则,RAWPTR还是指向RAWIN位置,第一个数字设置为0, ; 后再添加小数点
MOV R0, RAWPTR ; 用R0间接寻址 MOV @R0, #00H
INC RAWPTR INC DCOUNT DP_ADD:
MOV R0, RAWPTR ; R0间接寻址 MOV @R0, #0FFH ; DECIMAL POINT INC RAWPTR INC DCOUNT DP_DONE: RET
; -------------------- DP0:
; 之前的状态为等号,按下小数点后因该开始第一个操作数输入 ; 设置状态 ANL STAT, #0F0H SETB STAT.1 SJMP DP_NEW ; -------------------- DP3:
; 之前处于操作符状态,按下小数点则应该开始第二个操作数输入 ; 设置状态 ANL STAT, #0F0H SETB STAT.2 ; 新的操作数开始 SJMP DP_NEW ; -------------------- DP_NEW:
; 小数点开始的新的操作数,添加'0' '.' 两个输入 ; 初始化
MOV RAWPTR, #RAWIN MOV DCOUNT, #00H CLR PNTB
MOV RAWIN, #00H ; 第一个数字,0 INC RAWPTR INC DCOUNT
MOV R0, RAWPTR ; 使用R0间接寻址来存储小数点 MOV @R0, #0FFH ; 小数点使用0FFH表示 INC RAWPTR INC DCOUNT RET
; ======================================================= KEYEQU: ; 保存原来的状态 MOV B, STAT
; 设置现在的状态为EQU
ANL STAT, #0F0H ; 清楚低4位状态 SETB STAT.0 ; EQU STAT BIT ; 根据原来的状态采取相应的操作
JB B.1, EQU1 ; 原来处于第一个数的输入状态
JB B.2, EQU2 ; 原来处于第二个数的输入状态 (NORMAL) JB B.3, EQU3 ; 原来处于操作符状态 JB B.0, EQU0 ; 原来处于等号状态 ; ERROR SETB STAT.7 LJMP EXIT EQU1:
; 在第一个数的状态下按了等号,那么第一个数不需要进行计算 ; 直接作为结果显示,实际上RAWIN就是当前的操作数的显示格式 ; 因此只需要将第一个数转换成浮点数存储于NUM1 SETB RS0 CLR RS1
MOV R0, #RAWIN ; SOURCE MOV R1, #NUM1 ; DESTINATION LCALL MAKENUM ; NOTE: MAKENUM!!! RET EQU2:
; 在第二个数的状态下按了等号,这是最普通的操作 ; 首先转换操作数二到NUM2位置,然后计算结果 ; 并将结果转化为RAWIN形式,供DISPLAY显示 MOV R0, #RAWIN
MOV R1, #NUM2 ; DESTINATION
LCALL MAKENUM ; NOTE: MAKENUM.. ; 计算结果,结果放在NUM1
LCALL CALCULATE ; NOTE: CALCULATE!!! ; 结果转换为RAWIN,即从NUM1到RAWIN LCALL RES2RAW ; NOTE: RES2RAW NOP RET EQU3:
; 原来状态为操作符,然后直接按了等号
; 本程序采取的措施为:等1号覆盖前面的操作符 ; 因此不需要采取任何措施,直接同按下了第一个 ; 操作数后直接按等号相同,由于按下操作符的时候 ; 已经处理了第一个操作数,因此这里直接返回 RET
EQU0: ; SYSTEM RESET
; 原来状态为等号,然后又按了等号
; 第一次按等号的时候已经处理好,这里只需返回 ; 07.24 修改,连续两次等号相当于清0 ; 首先清除错误状态位 CLR STAT.7
MOV DCOUNT, #00H ; DCOUNT设置为0,显示就为0 RET
; ======================================================== ; 操作符处理,注意:前面已经判断不是等号 KEYOP:
; 保存操作符号: 给定的是 10H, 20H, 30H, 40H ; 转换为 00H, 10H, 20H, 30H. 即,减去 10H ;DEBUGHERE CLR C SUBB A, #10H
; INVARIANT: 除了4, 5位,其他位不可能为1 KEYOP_NE: ; KEY OPERATOR, NO ERROR
; 如果是第一个数之后按的运算符 JB STAT.1, KOP1
; 如果是第二个数之后按的运算符 JB STAT.2, KOP2
; 如果是一个运算符之后按的运算符 JB STAT.3, KOP3
; 如果是按了等号后按的运算符 JB STAT.0, KOP0 ; ERROR