📄 19计算器.asm
字号:
BANK0_REG EQU 00H ;选择第0组寄存器
BANK1_REG EQU 08H ;选择第1组寄存器
BANK2_REG EQU 10H ;选择第2组寄存器
BANK3_REG EQU 18H ;选择第3组寄存器
LED_MAX_BITS EQU 06H ;LED最大位数
MAX_DATA_LEN EQU 6 ;计算数字长度
;键盘按键值的定义
K0 EQU 00H
K1 EQU 01H
K2 EQU 02H
K3 EQU 03H
K4 EQU 04H
K5 EQU 05H
K6 EQU 06H
K7 EQU 07H
K8 EQU 08H
K9 EQU 09H
K_CLR EQU 0AH
K_DEL EQU 0BH
K_ADD EQU 0CH
K_SUB EQU 0DH
K_ENT EQU 0EH
K_ESC EQU 0FH
KEY_ROWS EQU 4 ;键盘行数
KEY_COLS EQU 4 ;键盘列数
KEY_ROW_MASK EQU 0FH ;行值屏蔽码
;------------------------------------------------------------------------------
LED_SDA EQU P3.0
LED_SCL EQU P3.1
K_DIGIT_FLAG EQU 00H
K_CLR_FLAG EQU 01H
K_DEL_FLAG EQU 02H
K_ADD_FLAG EQU 03H
K_SUB_FLAG EQU 04H
K_ENT_FLAG EQU 05H
K_ESC_FLAG EQU 06H
FR_FLAG EQU 07H
KEY_ROW EQU 27H
KEY_COL EQU 28H
PUB1_LEN EQU 29H
PUB2_LEN EQU 2AH ;公共缓冲区2长度1B
KEY_LEN EQU 2BH ;键盘缓冲区长度 1B
DIS_LEN EQU 2BH
CAL_FLAG EQU 2CH
PUB1_BUF EQU 50H ;公共缓冲区1 16B
PUB2_BUF EQU 60H ;公共缓冲区2 16B
PUB3_BUF EQU 70H ;公共缓冲区3 16B
KEY_BUF EQU 80H ;键盘缓冲区 16B
LED_DIS_BUF EQU KEY_BUF
;-----------------------------------------------------------------
ORG 0000H
LJMP START
START:
CLR EA
MOV SP,#0DFH
MOV PSW,#BANK0_REG
MOV R0,#20H
MOV R7,#0DFH-20H
LCALL PUB_CLEAR_RAM1 ;清0RAM单元
MOV KEY_LEN,#1
LCALL LED_DISP_DATA ;显示初始0
;-----------------------------------------------------------------
CAL_FUN:
MOV CAL_FLAG,#0 ;把计算标志清零
;-----------------------------------------------------------------
CAL_INPUT_NUM1:
LCALL KEY_GET_DATA ;调用数字输入子程序
JB K_ADD_FLAG,CAL_NUM1_ADD
JB K_SUB_FLAG,CAL_NUM1_SUB
JB K_ENT_FLAG,CAL_NUM1_ENT
SJMP START
CAL_NUM1_ADD:
JNB FR_FLAG,CAL_NUM1_ADD_A
MOV A,CAL_FLAG
CJNE A,#0EH,CAL_NUM1_ADD_A
MOV R0,#PUB3_BUF ;将计算结果作为第一个操作数
MOV R1,#PUB1_BUF
MOV R7,#MAX_DATA_LEN/2
LCALL PUB_MOV_RAM11
MOV CAL_FLAG,#01H
SJMP CAL_INPUT_NUM2
CAL_NUM1_ADD_A:
MOV CAL_FLAG,#01H
SJMP CAL_NUM1_END
;----------------------------------------------
CAL_NUM1_SUB:
JNB FR_FLAG,CAL_NUM1_SUB_A
MOV A,CAL_FLAG
CJNE A,#0EH,CAL_NUM1_SUB_A
MOV R0,#PUB3_BUF ;将计算结果作为第一个操作数
MOV R1,#PUB1_BUF
MOV R7,#MAX_DATA_LEN/2
LCALL PUB_MOV_RAM11
MOV CAL_FLAG,#02H
SJMP CAL_INPUT_NUM2
CAL_NUM1_SUB_A:
MOV CAL_FLAG,#02H
SJMP CAL_NUM1_END
CAL_NUM1_ENT:
CAL_NUM1_END:
MOV R1,#PUB1_BUF
LCALL PUB_SHORT_BCD
;-----------------------------------------------------------------
CAL_INPUT_NUM2: ;输入第二个数
LCALL KEY_GET_DATA ;调用数字输入子程序
JB K_ADD_FLAG,CAL_NUM2_ADD
JB K_SUB_FLAG,CAL_NUM2_SUB
JB K_ENT_FLAG,CAL_NUM2_ENT
SJMP START
CAL_NUM2_ADD:
JNB FR_FLAG,CAL_NUM2_ADD_A ;判断是否未输入数字而直接按K_ADD键
MOV CAL_FLAG,#01H
SJMP CAL_INPUT_NUM2 ;若是,则修正计算标识 并重新输入第二个数字
CAL_NUM2_ADD_A:
MOV R1,#PUB2_BUF
LCALL PUB_SHORT_BCD
LCALL CALCULATE
MOV R0,#PUB3_BUF ;将计算结果作为第一个操作数
MOV R1,#PUB1_BUF
MOV R7,#MAX_DATA_LEN/2
LCALL PUB_MOV_RAM11
MOV CAL_FLAG,#01H
SJMP CAL_INPUT_NUM2
;----------------------------------------------
CAL_NUM2_SUB:
JNB FR_FLAG,CAL_NUM2_SUB_A ;判断是否未输入数字而直接按K_SUB键
MOV CAL_FLAG,#02H
SJMP CAL_INPUT_NUM2 ;若是,则修正计算标识 并重新输入第二个数字
CAL_NUM2_SUB_A:
MOV R1,#PUB2_BUF
LCALL PUB_SHORT_BCD
LCALL CALCULATE
MOV R0,#PUB3_BUF ;将计算结果作为第一个操作数
MOV R1,#PUB1_BUF
MOV R7,#MAX_DATA_LEN/2
LCALL PUB_MOV_RAM11
MOV CAL_FLAG,#02H
SJMP CAL_INPUT_NUM2
CAL_NUM2_ENT:
MOV R1,#PUB2_BUF
LCALL PUB_SHORT_BCD
LCALL CALCULATE
MOV CAL_FLAG,#0EH
LJMP CAL_INPUT_NUM1
;-----------------------------------------------------------------
;-------------------------------------------
;进行计算操作
;入口: PUB1_BUF 第一个操作数(3字节压缩BCD)
; PUB2_BUF 第二个操作数(3字节压缩BCD)
; CAL_FLAG 计算标识(01:加法/02:减法)
;出口: PUB3_BUF 计算结果(3字节压缩BCD)
;-------------------------------------------
CALCULATE:
PUSH ACC
MOV A,CAL_FLAG
CJNE A,#01H,CALCULATE_SUB
LCALL FUN_ADDITION
JC CALCULATE_ERR
SJMP CALCULATE_DIS
CALCULATE_SUB:
LCALL FUN_SUBTRATION
JC CALCULATE_ERR
CALCULATE_DIS:
MOV R0,#PUB3_BUF
MOV R7,#MAX_DATA_LEN/2
LCALL PUB_LONG_BCD
MOV R0,#KEY_BUF
MOV R7,#MAX_DATA_LEN
CAL_D_R_A:
MOV A,@R0
JNZ CAL_D_R_B
INC R0
DJNZ R7,CAL_D_R_A
MOV KEY_LEN,#1
SJMP CAL_D_R_C
CAL_D_R_B:
MOV A,#MAX_DATA_LEN
MOV KEY_LEN,R7
MOV R1,#KEY_BUF
LCALL PUB_MOV_RAM11 ;去掉前导0
CAL_D_R_C:
LCALL LED_DISP_DATA
POP ACC
RET
CALCULATE_ERR:
MOV R0,#KEY_BUF
MOV @R0,#0EH
MOV KEY_LEN,#1
LCALL LED_DISP_DATA ;显示'E'提示错误
CALCULATE_ERR_A:
LCALL KEY_SCAN ;等待按K_ESC键返回
JNB K_ESC_FLAG,CALCULATE_ERR_A
POP ACC
LJMP START
;-----------------------------------------------------------------
;数字串输入程序
;最长6位整数
;出口: K_ESC_FLAG
; K_ENT_FLAG(KEY_BUF开始的6B右对齐左补0)
; K_ADD_FLAG
; K_SUB_FLAG
;------------------------------------------------------------------
KEY_GET_DATA:
SETB FR_FLAG ;初始化'有效数字'标志位
MOV R0,#KEY_BUF
MOV R7,#MAX_DATA_LEN
LCALL PUB_CLEAR_RAM1
MOV KEY_LEN,#0
KEY_G_D_SCAN:
LCALL KEY_SCAN
JB K_DIGIT_FLAG,KEY_G_D_DIG
JB K_DEL_FLAG,KEY_G_D_DEL
JB K_CLR_FLAG,KEY_G_D_CLR
JB K_ADD_FLAG,KEY_G_D_ADD
JB K_SUB_FLAG,KEY_G_D_SUB
JB K_ENT_FLAG,KEY_G_D_ENT
JNB K_ESC_FLAG,KEY_G_D_SCAN
LJMP KEY_G_D_EXIT ;ESC 键退出
;-----------------------------------------------------------
KEY_G_D_ADD:
LJMP KEY_G_D_RETURN
;-----------------------------------------------------------
KEY_G_D_SUB:
LJMP KEY_G_D_RETURN
;-----------------------------------------------------------
KEY_G_D_CLR:
SETB FR_FLAG ;初始化'有效数字'标志位
MOV R0,#KEY_BUF
MOV R7,#MAX_DATA_LEN
LCALL PUB_CLEAR_RAM1
MOV KEY_LEN,#1
LCALL LED_DISP_DATA
MOV KEY_LEN,#0
SJMP KEY_G_D_SCAN
;-----------------------------------------------------------
KEY_G_D_ENT:
MOV A,KEY_LEN
JZ KEY_G_D_SCAN
MOV A,CAL_FLAG
JZ KEY_G_D_SCAN
LJMP KEY_G_D_RETURN
;-----------------------------------------------------------
KEY_G_D_DEL:
MOV A,KEY_LEN
JZ KEY_G_D_CLR
DEC KEY_LEN ;整数部分的删除
MOV A,#KEY_BUF
ADD A,KEY_LEN
MOV R0,A
MOV @R0,#0
MOV A,KEY_LEN
JZ KEY_G_D_CLR ;KEY_LEN=0 重新开始输入过程
LJMP KEY_G_D_DISP
;-----------------------------------------------------------
KEY_G_D_DIG:
MOV B,A
MOV A,KEY_LEN
XRL A,#MAX_DATA_LEN ;已经输入MAX_DATA_LEN位整数
JZ KEY_G_D_SCAN ;是,则不在响应输入数字
JNB FR_FLAG,KEY_G_D_DIG_B ;已经输入有效数字了吗
MOV A,B
JZ KEY_G_D_DIG_A
CLR FR_FLAG
KEY_G_D_DIG_A:
MOV KEY_LEN,#0 ;未输入有效数字 且当前键值为0
KEY_G_D_DIG_B:
MOV A,#KEY_BUF
ADD A,KEY_LEN
MOV R0,A
MOV @R0,B
INC KEY_LEN ;输入的不是第一个有效数字
LJMP KEY_G_D_DISP
;-----------------------------------------------------------
KEY_G_D_RETURN:
MOV A,KEY_LEN
JZ KEY_G_D_EXIT ;未输入任何数字,直接按ENTER的判断
MOV R1,#KEY_BUF+MAX_DATA_LEN-1
MOV R0,#KEY_BUF
MOV R7,KEY_LEN
LCALL PUB_MOV_RAM_R ;右对齐
MOV R0,#KEY_BUF
MOV A,#MAX_DATA_LEN
CLR C
SUBB A,KEY_LEN
MOV R7,A
LCALL PUB_CLEAR_RAM1
;-----------------------------------------------------------
KEY_G_D_EXIT:
MOV KEY_LEN,#MAX_DATA_LEN
RET
KEY_G_D_DISP:
LCALL LED_DISP_DATA
LJMP KEY_G_D_SCAN
;---------------------------------------------------------------------------
;--------------------------------------------
;数字加子程序
;出口:C=1溢出
;--------------------------------------------
FUN_ADDITION:
PUSH DPH
PUSH DPL
MOV R0,#PUB1_BUF+MAX_DATA_LEN/2-1
MOV R1,#PUB2_BUF+MAX_DATA_LEN/2-1
MOV DPH,#PUB3_BUF+MAX_DATA_LEN/2-1
CLR C
MOV R7,#MAX_DATA_LEN/2
LOOPADD:
MOV A,@R1
ADDC A,@R0 ;两数相加
DA A ;调整相加结果,并送到r0中
MOV DPL,R1
MOV R1,DPH
MOV @R1,A
MOV R1,DPL
DEC R0
DEC R1
DEC DPH
DJNZ R7,LOOPADD
POP DPL
POP DPH
RET
;--------------------------------------------
;12字节相减子程序
;借位标志C=1有借位
;--------------------------------------------
FUN_SUBTRATION:
PUSH DPH
PUSH DPL
MOV R0,#PUB1_BUF+MAX_DATA_LEN/2-1
MOV R1,#PUB2_BUF+MAX_DATA_LEN/2-1
MOV DPH,#PUB3_BUF+MAX_DATA_LEN/2-1
CLR C ;清除借位标志
MOV R7,#MAX_DATA_LEN/2
LOOPSUB:
MOV A,#9AH
SUBB A,@R1
ADD A,@R0
DA A
MOV DPL,R1
MOV R1,DPH
MOV @R1,A
MOV R1,DPL
CPL C
DEC R0
DEC R1
DEC DPH
DJNZ R7,LOOPSUB
POP DPL
POP DPH
RET
;----------------------------------
;非压缩BCD转换成压缩BCD
;入口:
; KEY_BUF :源地址(默认)
; KEY_LEN :待转换数据长度
; R1 :目标地址(前256B)
;出口:
; R7:目标数据长度
;----------------------------------
PUB_SHORT_BCD:
PUSH KEY_LEN
MOV R0,#KEY_BUF
MOV A,KEY_LEN
JNB ACC.0,PUB_SHORT_BCD1_A ;长度为偶数时跳至PUB_SHORT_BCD1_A
MOV A,@R0
ANL A,#0FH ;长度为奇数时先转化第一字节
MOV @R1,A
INC R0
INC R1
DEC KEY_LEN
MOV A,KEY_LEN
JZ PUB_SHORT_BCD1_C
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -