⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 19计算器.asm

📁 学习单片机的程序与电路
💻 ASM
📖 第 1 页 / 共 2 页
字号:
		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 + -