|  | ||||
|  | ||||
| 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] | |||
|  | |||