One of the SITCOM training computer prototypes
 SITCOM 85 Training Computer
 
 

A first attempt to flash the LEDs

First of all we need to know how to switch the LEDs, which are connected to both ports A and B, on and off.

To begin with we must select ports A and B to be outputs. This is done by writing 089H to the 8255's control register. Or better said we write 10001001B to it, which is exactly the same value, but this time we can more clearly see what bits are set to "1", and what bits are set to "0". If you compare this pattern with the bit-map of the control register on the previous page, you'll see that ports A and B are both selected to be outputs, while the entire port C is selected as inputs. This suits our purpose very well, as we have connected 8 push buttons to port C (we won't be using these in lesson 1 though).

Because most TTL outputs can drive more current when low, we have connected the LEDs with their cathodes to the I/O ports (through a series resistor), and their anodes to the +5V rail. This means that a LED is ON when the output is "0". It goes without saying that the LED will be OFF when the output is "1", being the only other option left.

Type the next program in your favourite text editor, save it, press the Boot button on Sitcom and assemble it using the DOS instruction SBASM LESSON1A. Or you can download all example programs of lesson 1 from the lesson1.zip file.

 
   

;------------------------------------------------------------------------
;
; LESSON1A.ASM
;
; This program will light all LEDs connected to an odd bit number on
; ports A and B.
;
;------------------------------------------------------------------------

            .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

;------------------------------------------------------------------------
;
; Light all odd LEDs
;
;------------------------------------------------------------------------

START       MVI   A,10001001B      Select outputs for Ports A and B
            OUT   CONTROL          of the 8255, Port C are inputs

            MVI   A,10101010B      Load the accumulator with bit pattern
			
            OUT   PORTA            Output the bit pattern to port A
            OUT   PORTB            Output the bit pattern to port B

.4EVER      JMP   .4EVER           The processor can't do "nothing"
 
 

What have we done here? We've seen most of the program before. Remember that lines beginning with a semicolon (;) are simply comments, intended for human eyes only. Sitcom will never ever see any of them, as they are discarded by the assembler.

The first 3 lines of code tell the assembler that we're using an 8085 processer, and we want the generated code sent to Comm port 1 at 9600 baud. Remember that you'll have to adapt these lines if your sitcom is connected to a different Comm port.

We have seen the next 4 lines of code too. These lines tell the assembler to use the numbers 0, 1, 2 and 3 whenever it encounters the names PORTA, PORTB, PORTC and CONTROL respectively.

At the line with the label START we see the first real instruction for the processor. By the way, this instruction is put at address 00000H in our program memory.
The MVI instruction tells the processor to move a constant value immediately into one of its registers. In our case it will load the Accu with the value 10001001B, which is exactly the pattern we've seen before telling the 8255 to set ports A and B to be outputs, and port C will become an input port. This value is then copied to the 8255 by the instruction OUT CONTROL. Remember that the word CONTROL will be replaced by the assembler with the value 003H.
Next we load a new immediate value to the Accu, this time it's the output pattern for the LEDs. Remember that a LED will be on when its corresponding bit is "0". Then this pattern is copied to ports A and B by two subsequent OUT instructions.

But what is that JMP .4EVER thing doing there? You'll have to know that a microprocessor is a real workaholic, it just can't sit still. Therefore we have to tell it to run around in circles if we have nothing else for it to do. You will only see something like this in example programs, because in real life a microprocessor is controlling some automated system. Such a system will constantly need to be controlled, for as long as it is switched on.

Feel free to experiment a little with this program, creating other light patterns on the LEDs. You may even try to show a different pattern on the LEDs of port A and B. If you want to do that you'll need an other MVI instruction just after the OUT PORTA instruction.

But the LEDs are not flashing? Now what?

 
   

;------------------------------------------------------------------------
;
; LESSON1B.ASM
;
; This program will flash all LEDs together on ports A and B (or doesn't
; it?).
;
;------------------------------------------------------------------------

            .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

;------------------------------------------------------------------------
;
; Flash the LEDs	
;
;------------------------------------------------------------------------
	
START       MVI   A,10001001B      Select outputs for Ports A and B
            OUT   CONTROL          of the 8255, Port C are inputs

            MVI   A,00000000B      Load the accumulator with bit pattern

FLASH       OUT   PORTA            Output the bit pattern to port A
            OUT   PORTB            Output the bit pattern to port B

            CMA                    Complement all bits in the Accu
            JMP   FLASH            Repeat for ever			
 
 

Change the program to reflect the program above and assemble it. Now the LEDs are flashing.

Wait a minute! My LEDs are constantly on, they are not flashing at all!
Let us see what's wrong here. We'll skip the initialization code, the error can't be in there because that has worked before. We start at the line preceding the line with the label FLASH. There a pattern is loaded into the Accu, which will be sent to the output ports. A pattern of all 0's will light all LEDs. This can be true, because all LEDs appear to be on. The pattern is copied to the output ports, the way it is supposed to by the two OUT instructions. Nothing's wrong there.
Now we see a new instruction, CMA, which complements the bits in the Accu. Complementing means that every "1" bit will become a "0", and every "0" will become a "1". Easy enough, the pattern 00000000H will become 11111111H now, and the LEDs should be off when we output that pattern. We will output that pattern soon, because we jump back to the label FLASH, where the pattern is sent to the output indeed.
Then we encounter the CMA instruction again, changing the pattern back to 00000000H. This process continues indefinitely.

I don't see nothing wrong in this program. Do you? Then why don't my LEDs flash?
They DO flash! Only you're too slow to see it. They flash at an enormous rate, too fast for our eyes to see. Our eyes will not see flashes above approximately 20Hz, while the program running at full speed will flash the LEDs at 44,117Hz!
If you don't believe that your LEDs are really flashing you can verify it by connecting a logic probe, an oscilloscope or a frequency counter to any of the outputs and you'll see for yourself.

 
 

A waste of time

How do we slow down the processor? We can't stop it temporarily, for it can't do just "nothing" (at least not with our current knowledge). The only thing we can do is make the processor do some useless things that only consume some time.
Every instructions takes a certain amount of time. You can have a look at the instruction set of the 8085 to find out how much time all possible instructions take. These times are measured in micro seconds, so it is obvious that we need a whole lot of instructions to slow down the processor from approximately 44kHz down to let's say 1Hz.
Putting all these instructions one after the other is not a serious option. Creating a loop is a far better solution. We let the processor execute the loop a certain amount of times, during which it does absolutely nothing useful. Here's a loop that will do this:

 
   

            MVI   C,255            Load register C with maximum number

DELAY       DCR   C                Decrement register C (subtract 1)
            JNZ   DELAY            Jump back while C is not 0 yet
 
 

Let's see how much time we've wasted with this loop? According to the instruction table a MVI instruction takes 7 clock pulses to execute, a DCR instruction takes 4 clock pulses and a JNZ instruction takes 10 clock pulses (when the condition is true). Only the DCR and JNZ instructions will be repeated 255 times. The MVI instruction is only executed once.
This gives the grand total of 7 + (4 + 10) * 255 = 3577 clock pulses. Each clock pulse is one period of the clock frequency, which is half the frequency of the 6MHz crystal, which lasts 0.333 micro seconds. Multiplying these two values results in a total waste of time of 3577 * 0.333 = 1.2 mili seconds.

Wow! We've counted down from 255 to 0 in about 1.2 mili seconds! Thus it is hardly enough to last half a second.
How do we increase the time now? One way is to make the loop last longer is simply achieved by adding more instructions inside the loop. A very suitable instruction for this purpose is the NOP instruction. It is the No OPeration instruction, and does nothing but waste 4 clock pulses.
Adding 4 NOP instructions to the loop, and changing the loop count to 250, we can make the loop last about 2.5 mili seconds.

 
   

            MVI   C,250            Load register C with loop counter

DELAY       NOP                    Waste 250 * 4 clock pulses
            NOP                    Another 1000 clock pulses wasted
            NOP                    And yet another 1000 down the drain
            NOP                    Do I have to repeat myself again?
            DCR   C                This also lasts a 1000 clock pulses
            JNZ   DELAY            This one lasts 250 * 10 clock pulses!
 
 

The loop in the program fragment above lasts a total of 7500 clock pulses. Multiplied with 0.333 micro seconds this will take approximately 2.5 mili seconds.

This is a lot longer than the 11.333 micro seconds it takes when no delay loop is implemented. But it still is not long enough to obtain a flashing rate of 1Hz. Adding more NOP instructions will add 4 * 250 * 0.333 = 333 micro seconds per NOP, which is still not really an option if we want a delay of 0.5 seconds.
We can repeat our loop trick again, creating a loop within a loop. The next program fragment shows what I mean:

 
   

            MVI   B,200            Load outer loop counter

DELAY1      MVI   C,250            Load inner loop counter

DELAY2      NOP                    Begin of inner loop
            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
 
 

The inner loop is the same as the loop in our previous example. The line containing label DELAY1 loads the inner loop counter, while the next lines until the first JNZ instruction are the actual inner loop. We know from the previous description that this loop takes about 2.5 mili seconds to execute. So executing this inner loop a total of 200 times will waste about half a second of our life. That is exactly what we're doing here. The outer loop counter B is initialized to 200, and then the inner loop is started. After finishing this inner loop the outer loop counter is decremented and we'll start all over again if the counter is not 0 yet (happens 200 times).

With this knowledge we can write the new complete program which flashes all LEDs at a rate of 1Hz.

 
   

;------------------------------------------------------------------------
;
; LESSON1C.ASM
;
; This program will flash all LEDs together on ports A and B at 1 Hz
;
;------------------------------------------------------------------------

            .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

;------------------------------------------------------------------------
;
; Flash the LEDs	
;
;------------------------------------------------------------------------
	
START       MVI   A,10001001B      Select outputs for Ports A and B
            OUT   CONTROL          of the 8255, Port C are inputs

            MVI   A,00000000B      Load the accumulator with bit pattern

FLASH       OUT   PORTA            Output the bit pattern to port A
            OUT   PORTB            Output the bit pattern to port B

            MVI   B,200            Load outer loop counter

DELAY1      MVI   C,250            Load inner loop counter

DELAY2      NOP                    Begin of inner loop
            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

            CMA                    Complement all bits in the Accu
            JMP   FLASH            Repeat for ever			
 
 

Now we have covered all the secrets about the FLASH1D program we have seen before. You can now experiment a little with this program. You may wish to flash other patterns on the LEDs, or you may change the flashing frequency or the duty cycle (the ratio between LEDs on and LEDs off time).
You may even wish to flash different patterns on both output ports, which is not as simple as it may seem! TIP: You can use 2 intermediate registers to hold the temporary pattern of both output ports. Or you can read each output port latch and write the inverted bits back.

This concludes the first Sitcom lesson. Lesson 2 will show some more flashing LED tricks. I hope to meet you there.

 
  Continue with Lesson 2 - Some more flashing LEDs
 
  [Home] [Latest News] [Essentials] [Hardware] [The Build] [Programs] [Projects] [Downloads]
 
  Made in the UK