![]() |
||||
![]() |
||||
Dynamic subroutinesThere's nothing mysterious about dynamic subroutines. Basically they are quite the same as the subroutines we saw on the previous page. The only difference is that we can change their behaviour by sending some parameters to them. Wouldn't it be nice if we had a delay routine that could be used for several purposes, with varying delay times? That is easy enough, we simply pass a parameter to the subroutine instructing it how long it should delay. Here's a program that does that: |
|
;------------------------------------------------------------------------
;
; LESSON3C.ASM
;
; A Kitt scanner, with a dynamic subroutine
;
;------------------------------------------------------------------------
.IN INIT01 Initialize the assembler
;------------------------------------------------------------------------
LXI SP,00000H Initialize stack pointer
MVI D,00011111B Initialize pattern
MVI E,11111111B
MOV H,E
MOV L,E
WALKR CALL OUTPUT Output both bit patterns and delay
MVI B,25 Delay 25 * 5 ms
CALL DELAY
MOV A,L See if we have to change direction
ANI 01000000B
JZ GOLEFT We must if b6 is a 0!
GORIGHT STC Set the carry
MOV A,H Rotate entire pattern, including
RAR the extra carry byte
MOV H,A
MOV A,D
RAR
MOV D,A
MOV A,E
RAR
MOV E,A
MOV A,L
RAR
MOV L,A
JMP WALKR Always jump back to WALKR
;------------------------------------------------------------------------
WALKL CALL OUTPUT Output both bit patterns and delay
MVI B,25 Delay 25 * 5 ms
CALL DELAY
MOV A,H See if we have to change direction
ANI 000000010B
JZ GORIGHT We must if b1 is a 0!
GOLEFT STC Set the carry
MOV A,L Rotate entire pattern, including
RAL the extra carry byte
MOV L,A
MOV A,E
RAL
MOV E,A
MOV A,D
RAL
MOV D,A
MOV A,H
RAL
MOV H,A
JMP WALKL Always jump back to WALKL
;------------------------------------------------------------------------
; Delay B * 5 ms
; No registers are affected
;------------------------------------------------------------------------
DELAY PUSH PSW Save affected registers to the stack
PUSH B (AF and BC)
DELAY1 MVI C,250 Load inner loop counter
DELAY2 NOP Begin of inner loop
NOP
NOP
NOP
NOP
JMP $+3
NOP
NOP
NOP
NOP
DCR C Decrement inner loop counter
JNZ DELAY2 Repeat until loop counter = 0
DCR B Decrement outer loop counter
JNZ DELAY1 Repeat until loop counter = 0
POP B Restore affected registers from the
POP PSW stack (in reverse order!)
RET Return to calling program
;------------------------------------------------------------------------
OUTPUT MOV A,E Output the bit pattern to port A
OUT PORTA
MOV A,D Output the bit pattern to port B
OUT PORTB
RET Return to calling program
|
||
|
What I've done in this program is to load the B register with the desired delay time (measured in 5 ms intervals) prior to calling the DELAY routine. This way you can use the same DELAY routine for a variety of delay times, from 5 ms until more than on second.
This dynamic subroutine only requires one parameter, others may need two, 4, or even more.
It is fine for subroutines with a limited number of parameters pass them using the internal registers of the 8085.
I have taken the liberty to make some minor changes to the DELAY routine itself, mainly to demonstrate the strength of the stack.
If you look a bit closer you see that I've changed the inner loop of the delay routine.
This has nothing to do with making the subroutine dynamic, I only wanted to double the inner loop to approximately 5 ms.
Doubling the time required me to add 30 clock pulses to the inner loop.
This could not be done by adding just NOP instructions, because a NOP takes 4 clock pulses to execute.
That is why I used 5 extra NOPs, totaling to 20 clock pulses, followed by a JMP $+3 instruction which takes another 10 clock pulses.
|
|
A new INIT program
Our include program INIT01.ASM has lasted a couple of experiments.
Do you still remember that it is still there, and absolutely essential!
If it weren't there we would have to initialize the assembler, the I/O constants and the 8255 in each and every experiment over and over again.
INIT01.ASM does that all for us, without us worrying about it.
|
|
;------------------------------------------------------------------------
;
; INIT02.ASM
;
; Initialise experiments with the basic I/O board and define DELAY
;
;------------------------------------------------------------------------
.CR 8085 The processor we're using
.CP 1,9600,N,8,1 SITCOM is connected to COM1
.TF COM1:,INT Send generated code to COM1
;------------------------------------------------------------------------
;
; Constants declarations
;
;------------------------------------------------------------------------
PORTA .EQ 000H Port A on the 8255
PORTB .EQ 001H Port B on the 8255
PORTC .EQ 002H Port C on the 8255
CONTROL .EQ 003H Control register of the 8255
;------------------------------------------------------------------------
;
; Initialize the 8255
;
;------------------------------------------------------------------------
RESET JMP START Skip the subroutine definitions
;------------------------------------------------------------------------
; Delay B * 5 ms
; No registers are affected
;------------------------------------------------------------------------
DELAY PUSH PSW Save affected registers to the stack
PUSH B (AF and BC)
DELAY1 MVI C,250 Load inner loop counter
DELAY2 NOP Begin of inner loop
NOP
NOP
NOP
NOP
JMP $+3
NOP
NOP
NOP
NOP
DCR C Decrement inner loop counter
JNZ DELAY2 Repeat until loop counter = 0
DCR B Decrement outer loop counter
JNZ DELAY1 Repeat until loop counter = 0
POP B Restore affected registers from the
POP PSW stack (in reverse order!)
RET Return to calling program
;------------------------------------------------------------------------
; Here's the new start of the program
;------------------------------------------------------------------------
START MVI A,10001001B Select outputs for Ports A and B
OUT CONTROL of the 8255, Port C are inputs
LXI SP,00000H Initialize the stack
|
||
|
Basically INIT02.ASM is quite similar to INIT01.ASM.
The assembler is initialized, the I/O addresses are defined and the 8255 is initialized.
I have also added a line to initialize the stack, as we will be needing that in almost every program that follows.
Our DELAY subroutine is now constantly assembled in all subsequent lessons, ready for us to use it with any delay time we desire from 5 ms, up until 1.275 seconds. |
|
Binary counting demo
As a bonus, to test our new INIT02.ASM prgoram, I add a small program that counts from 0 up to 65535 in binary.
|
|
;------------------------------------------------------------------------
;
; LESSON3D.ASM
;
; Binary counting demo
;
;------------------------------------------------------------------------
.IN INIT02 Initialize the assembler
;------------------------------------------------------------------------
LXI D,00000H Initialize counting value
BINCOUNT MOV A,D Get Most significant byte
CMA Invert all bits
OUT PORTB Before outputting it to port B
MOV A,E Do the same for the Least significant
CMA byte
OUT PORTA
MVI B,50 Delay 50 * 5 ms
CALL DELAY
INX D Increment the 16-bit register BC
JMP BINCOUNT Always jump back to BINCOUNT
|
||
|
First of all, be careful to use INIT02 this time as init file, otherwise you won't have the necessary DELAY routine.
Short program, isn't it?
It starts by initializing a 16-bit register DE.
Feel free to change the delay time if you don't like the counting speed. Or you can make the program count backwards, by replacing the INX D instruction by a DCX D instruction.
Experiment tips: |
|
| Continue To Lesson 4 - Selective output | |
| [Home] [Latest News] [Essentials] [Hardware] [The Build] [Programs] [Projects] [Downloads] | |||