📄 calc.asm
字号:
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 + -