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

📄 calc.asm

📁 实现简单的计算器功能,方便又实用,简单易懂,仅供参考
💻 ASM
📖 第 1 页 / 共 4 页
字号:

 
keycodes:	db 	ON,  '7','8','9', '*', '/'
		db	SGN, '4','5','6', '-', MRC
		db	PCT, '1','2','3', 0,   MSUB
		db	SQR, '0','.','=', '+', MADD


;-----------------------------------------------------------------------------------------
; WAITKEY - Wait for a keypress, lift the key and display it on screen.
;-----------------------------------------------------------------------------------------

waitkey:	push DPH			; Preserve DPTR
		push DPL			;

		call initialize			; Initialise the keybuffer and the LCD display screen.
wk_keyscan: 	call keyscan			; Wait for key press
	 	jnz wk_wrchar		        ; Handle a pressed key
 		push DPH			; don't allow DPTR to be changed
		push DPL
		mov DPTR,#10			; Time delay to wait
 		call wtms			; Wait set time
		pop DPL
		pop DPH
		jmp wk_keyscan			; Check again


wk_wrchar:	call keytest			; Test the type of key pressed
		mov R5,opcodeflag
		cjne R5,#0,wk_ophandle		; Test whether key pressed is a digit or an operator.
		
;*DIGIT PRESS*:
		call statuscheck		; Determine whether this is the first digit pressed since an op press. 
		call storedigit			; Store the digit and inc bufferctr along the buffer.
		call bufferoutput		; Output the number to the LCD display.
		jmp wk_keyscan			; loop back to scan for next entry.


;*OPERATOR PRESS*:

wk_ophandle:	call getmode			; Determine at which buffer the DPTR addresses.
		call handleop			; Deal with the operator logic. 
		jmp wk_keyscan			; loop back and start again.

wk_done:	pop DPL				; Restore DPTR
		pop DPH	
		ret


;============================================
;********** KEYPRESS FUNCTIONS **************
;============================================


;-----------------------------------------------------------------------------------------
; KEYSCAN - Function to return current keypad state in A.
;-----------------------------------------------------------------------------------------


keyscan:	push DPH
		push DPL
		
		mov R0,#keyflags 		; R0 addresses the key toggle bytes
		mov R1,#KEY_ROW1		; R1 address the keyboard row address
		mov R2,#4			; R2 counts rows
ksrow:		mov P2,R1			; Set row address to port P2
		nop
		mov A,P1			; Read column data from port P1
		mov R3,#6			; R3 counts keys per row
		anl A,#3Fh
ks0:		rrc A				; Move next bit into carry
		mov R4,A			; R4 preserves the row data
		jc ks1				; Jump if key not pressed
		mov A,@R0			; Test if key already pressed
		mov @R0,#1			; Flag pressed anyway
		jz ksnew			; Jump if key newly pressed
		jmp ks2
ks1:		mov @R0,#0			; Flag key as not pressed
ks2:		inc R0				; Loop for next key in this row
		mov A,R4
		djnz R3,ks0

		mov A,R1			; Jiggle R1 to address next row
		rl A 
		mov R1,A
		djnz R2,ksrow

		clr A				; Return zero - no (new) key press.
		jmp ksend

						
ksnew:		mov DPTR,#keycodes		; We've found a new key since last time:
		mov A,R0			; The key flag address (ordinal) is in R0
		clr C
		subb A,#keyflags
		movc A,@A+DPTR
		mov digitcode,A			; digitcode now holds the ascii value of the key in (in hex)		
ksend:		mov P2,#0FFh
		pop DPL
		pop DPH
		ret


;--------------------------------------------------------------------------------------------------------
; KEYTEST - Function to test which type of key is pressed. digitcode holds the key information.
; 	    The digit range holding ascii 0 -> 9 is 030h -> 039h.
;	    Opcodeflag designated as the flag for *key type*.  
;---------------------------------------------------------------------------------------------------------

keytest:	mov R4,digitcode 	

		cjne R4,#030h,kt_testlower	; Test lower boundary of the *digit range*. carry is set if < 030h
		jmp kt_isdigit			; key is 030h so is a digit
kt_testlower:	jc kt_decimalpt			; Test the carry flag - if set then key is not a digit so goto op tests. 
		cjne R4,#039h,kt_testupper	; Test upper boundary of *digit range*. carry is set if < 039h	
		jmp kt_isdigit			; key is 039h so is digit.
kt_testupper:	jc kt_isdigit			; if carry set then within *digit range* so jump to kt_isdigit
kt_decimalpt:	cjne R4,#2Eh,kt_addtest		; allow decimal points.
		jmp kt_isdigit

kt_addtest:	cjne R4,#02Bh,kt_subtest	; Test the key info against ascii '+'
		mov opcodeflag,#1		; Key is the addition operator.					
		jmp kt_done
kt_subtest:     cjne R4,#02Dh,kt_multest	; Test the key against ascii '-'
		mov opcodeflag,#2		; Key is the subtraction operator.
		jmp kt_done
kt_multest:	cjne R4,#02Ah,kt_divtest	; Test the key against ascii '*'
		mov opcodeflag,#3		; Key is the multiply operator.
		jmp kt_done
kt_divtest:    	cjne R4,#02Fh,kt_cancel		; Test the key against ascii '/'
		mov opcodeflag,#4		; Key is the divide operator.
		jmp kt_done
kt_cancel:	cjne R4,#ON,kt_equals		; Test the key against the assigned value for the cancel button.
		mov opcodeflag,#5		; Key is the Cancel operator
		jmp kt_done
kt_equals:      cjne R4,#03Dh,kt_sign		; Test the key against ascii '='
		mov opcodeflag,#6		; Key is the equals operator.
		jmp kt_done
kt_sign:	cjne R4,#SGN,kt_mrc		; Test the key against ascii '=' 
		mov opcodeflag,#7               ; Key is the Sign operator.    
		jmp kt_done
kt_mrc:		cjne R4,#MRC,kt_mplus		; Test the key against ascii '=' 
		mov opcodeflag,#8               ; Key is the MRC operator.    
		jmp kt_done
kt_mplus:	cjne R4,#MADD,kt_msub		; Test the key against ascii '=' 
		mov opcodeflag,#9               ; Key is the M+ operator.    
		jmp kt_done
kt_msub:	cjne R4,#MSUB,kt_pcnt		; Test the key against ascii '=' 
		mov opcodeflag,#10              ; Key is the M- operator.    
		jmp kt_done
kt_pcnt:	cjne R4,#PCT,kt_sqr		; Test the key against ascii '=' 
		mov opcodeflag,#11              ; Key is the Percentage operator.    
		jmp kt_done
kt_sqr:		cjne R4,#SQR,kt_done
		mov opcodeflag,#12
		jmp kt_done
kt_isdigit:	mov opcodeflag,#0		; Key is a digit.
		jmp kt_done
kt_done:	ret


						
;======================================================
;************* OPERATOR FUNCTIONS *********************
;======================================================

;---------------------------------------------------------------------------------
;HANDLEOP - Subroutine to test whether the operator is arithmetic or not
;	    and to call the appropriate function handlers.
; 	    If opcodeflag < =4 then arithmetic op else functional op.
;---------------------------------------------------------------------------------
handleop:       clr c				; Clear the carry flag before a cjne instruction
		mov A,opcodeflag
		cjne A,#4,ho_testcarry		; Test operator against 4	
		jmp ho_arithmcall		; if 4 then arithmetic so jump

ho_testcarry:	jc ho_arithmcall		; if less than 4 then arithmetic 
      		call functionops		; otherwise call function ops.
		mov arithopflag,#00h		; If a functional op then clear arithopflag
		jmp ho_done	

ho_arithmcall:  call arithmeticop
ho_done:	ret


;=========================================
;********* ARITHMETIC OPERATORS **********
;=========================================


;---------------------------------------------------------------------------------
;ARITHMETICOP - Subroutine to handle the operator logic for arithmetic operations
;	        *opcodehex* is stored, *oldopcode* is retrieved.
;---------------------------------------------------------------------------------

arithmeticop:	push DPH			; Preserve the Datapointer.
		push DPL
		mov mode,#1			; DPTR addresses the Keybuffer.
		call getmode			
		
		clr c
		mov R5,arithopflag		; Test for consecutive Arithmetic Operator presses
		cjne R5,#1,ao_equalscheck	; If consecutive just store the op.
		jmp ao_store

ao_equalscheck:	clr c
		mov R5,equalsflag		; If *equ* - *arithmetic op* just store the op
		cjne R5,#1,ao_percentcheck	; The equals operation stores the result.
		jmp ao_store

ao_percentcheck:clr c
		mov R5,pctopflag     		; If *pct* - *arithmetic op* just store the op
                cjne R5,#1,ao_statuscheck         ; The percent operation stores the result.     
		jmp ao_store           

ao_statuscheck:	mov R5,status
		cjne R5,#1,ao_normalinput	; Test for *MRC*  - *aritmetic op* sequence
		mov mode,#1			 	
		mov R5,memcounter		; Memcounter holds the length of the number in the Memorybuffer.
		mov bufferctr,R5
		mov digitcode,#0		; Terminate the number.
		call storedigit
		mov mode,#1
		call inputnum			; Input the number.
		mov copyfrom,#1				 
		mov copyto,#3	
		call buffercopy			; Copy the number into the oldnumbuffer.
		jmp ao_store

ao_normalinput:	mov mode,#1			; Test for *digit* - *arithmetic op* sequence
		mov digitcode,#0		 
		call storedigit			; Terminate the number.
		mov mode,#1
		call inputnum			; Input the number.
		mov copyfrom,#1				 
		mov copyto,#3	
		call buffercopy			; Copy the number.

ao_countcheck:	inc opcounter			; opcounter holds the number of operations.
		mov R5,opcounter
		cjne R5,#1,ao_retrieve
		jmp ao_store			; if this is first op nothing to retrieve/output so goto ao_store

ao_retrieve:	mov mode,#1
		call getmode
		call retrieveop			; retrieve the op, execute the opereration 
						; and output the result to the Keybuffer and to the LCD display.
		mov mode,#1
		call inputnum			; Put the result back on the stack.
ao_store:   	call storeop			; store the op type in *opcodehex*

ao_setflags:	mov memopflag,#00h		; Clear/Set the appropriate flags.
		mov equalsflag,#00h
		mov pctopflag,#00h
		mov arithopflag,#01h		
		
ao_done:	mov status,#01h			; set status to indicate that an operator has been pressed.
		call resetsign
		pop DPL
		pop DPH
		ret

;---------------------------------------------------------------------------------
;STOREOP- Subroutine to store the operator. We store *opcodehex*. 
;---------------------------------------------------------------------------------

storeop:	mov R5,opcodeflag	
so_addition:	cjne R5,#1,so_subtract		; If Addition assign code		
		mov opcodehex,#02Bh
so_subtract:	cjne R5,#2,so_multiply		; If Subtraction assign code
		mov opcodehex,#02Dh
so_multiply:	cjne R5,#3,so_divide		; If Multiplication assign code
		mov opcodehex,#02Ah
so_divide:	cjne R5,#4,so_done		; If Division assign code
		mov opcodehex,#02Fh

so_done:	mov A,opcodehex			; Moves the op type into *oldopcode*.
		mov oldopcode,A			; This means on next op press oldopcode is the
						; old code and opcodehex is the new code.       
		ret	

;---------------------------------------------------------------------------------
;RETRIEVEOP - Subroutine to retrieve the operator. We retrieve *oldopcode*.
;---------------------------------------------------------------------------------

retrieveop:	mov R7,oldopcode		; use R7 locally here for the cjne
		clr A
		mov bufferctr,#00h
ro_addition:	cjne R7,#02Bh,ro_subtract	; Test for addition
		call floating_add		; Perform the operation
		call errorcheck			; Check for errors
		jmp ro_output
ro_subtract:	cjne R7,#02Dh,ro_multiply	; Test for subtraction
		call floating_sub		; Perform the operation
		call errorcheck                 ; Check for errors     
		jmp ro_output
ro_multiply:	cjne R7,#02Ah,ro_divide		; Test for multiplication
		call floating_mul		; Perform the operation
		call errorcheck                 ; Check for errors     
		jmp ro_output
ro_divide:	cjne R7,#02Fh,ro_output		; Test for division
		call floating_div		; Perform the operation
		call errorcheck                 ; Check for errors     
		jmp ro_output

ro_output:	mov R5,errorflag
		cjne R5,#0,ro_clear		; Test for errors.
		mov mode,#1			; No error so output result.
		call getmode
		call bufferclear
		mov bufferctr,#00h
		call floating_point_output	; output result both to LCD and to keybuffer.
		call bufferoutput
		jmp ro_done

ro_clear:	mov status,#1			; If an error occurs we clear everything 
		call cancelop			; ready to start again.
ro_done:	ret	



;===================================
;***** FUNCTION OPERATORS **********
;===================================


;---------------------------------------------------------------------------------
;FUNCTIONOPS - Subroutine to handle the non arithmetic operations.
; 	       Determine which functional op is pressed and the call the appropriate subroutine.	
;---------------------------------------------------------------------------------

functionops: 	mov R5,opcodeflag
fo_cancel:	cjne R5,#5,fo_equal
		call cancelop
		jmp fo_done
fo_equal:	cjne R5,#6,fo_signop
		call equalop
		jmp fo_done	
fo_signop:	cjne R5,#7,fo_mrc
		call signop
		jmp fo_done
fo_mrc:		cjne R5,#8,fo_memplus
		call memrecall
		jmp fo_done
fo_memplus:	cjne R5,#9,fo_memsub
		call memplus
fo_memsub:	cjne R5,#10,fo_pcnt
		call memsub		
fo_pcnt:	cjne R5,#11,fo_sqr
		call percentop
fo_sqr:		cjne R5,#12,fo_done
		call banner
		call cancelop
fo_done:	ret

;---------------------------------------------------------------------------------
;CANCELOP - Subroutine to handle the cancel operation.
;---------------------------------------------------------------------------------

cancelop:	push DPH			; Preserve the Datapointer. 
	 	push DPL
		
		mov R5,status			; Test for full or partial clear.
		cjne R5,#0,co_totalclear	

co_partclear:	mov mode,#1			; Partial Clear - Lose num2 and display num1
		call getmode			; This is Sequence:*num1*-*arithop*-*num2*-*cancel*
		call clearscreen		; Scrap the second number ( isn't on the stack here )  
		mov bufferctr,#00h		; Clear before FPO so we know the *size* of the resulting number.
		mov mode,#1
		call getmode		
		call floating_point_output	; Output the first number to the Keybuffer.	
		call bufferoutput		; Output the first number to the LCD Display.
		call inputnum			; Put the first number back on the stack.
		jmp co_setflags
	

co_totalclear:	mov mode,#1			; Total Clear  - Clear the stack and the Keybuffer.
		call getmode
		call floating_point_output	; Output the contents of the stack.	
		call clearscreen		; Clear the screen.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -