Exercise 1
Push and Pop
Build your program a piece at a time. Stop at every "Check registers" to be sure all your preceding work is correct. At the end you should have:
.
| A | 0x1E |
| B | 0x09 |
| C | 0x11 |
| D | 0x19 |
1. Load A with 0x04.
2. Load B with 0x05.
3. Check registers.
4. Add B to A.
5. Check registers.
6. Store A in register D.
7. Add 0x08 to A.
8. Check registers.
9. Store A in register E (DE now has the last two things you wanted to save.)
10. Push DE onto the stack.
11. Check registers - check Stack.
12. Add 0x14 to B ( This is tricky - it might take several lines of code!)
13. Check registers - check Stack.
14. Store B in H.
15. Push HL to the stack. (L has garbage, but never mind.)
16. Add 0x05 to B
17. Store B in A.
18. Check registers - check Stack.
19. Pop the stack into HL. (Remember the stack is LIFO)
20. Put H into D.
21. Pop the stack into BC.
Check registers - they should be showing the desired results.
Exercise 2
Count to 55h
Lets build a counter which counts up to 0x55. Maybe our only purpose is to kill time, but never mind.
Lets start with a labeled NOP. Maybe we call it "start: NOP". In front of "start", we need to initialize register A. Maybe something like "LD A, 0x00". Every time through the loop, we want to increment A - "INC A". Then we want to compare what we got with a constant, say 0x55. (CP 0x55). That command does several things, depending on whether A is less than - or greater than - 0x55. (Look it up.)
Now, we want to do one of two things:
Jump back to statement "start" and continue incrementing A, or
Pass on out of the counter.
You need a conditional jump like JP f, label. The fact, "f", is either true or false. When A has incremented up to 0x55, the compare operation is going to change the Z flag Either JP Z start or JP NZ start is going to be what you want.
Play around with it. Check registers, etc. See if you can write a program which increments register A up to 0x55, and then quits. You have a delay. You could have a longer delay if you counted up to 0xFF, couldnt you? If you put this a subroutine, you could call it over and over, if you needed to kill even more time.
Note: Along with your code and register displays, please hand in an estimate of how much time your program burns by counting up to 0x55.
Microprocessors
Exercise 3
Navigating in Assembly
A. Write assembly code which multiplies whatever is in the accumulator (register A) by ten, without using the MUL command. Remember that SLA (shift left) is the same as multiplying by 2 - combine shift and add operations. Use 8-bit registers. There are several good solutions. Try to come up with two or three different algorithms, and pick the one with the fewest clock cycles. Polish up your program, and call it a subroutine. Let the input be A and the output be A. Appropriate comments will really help.
B. Insert the main part of your program in front of your subroutine. We want to multiply 2 * 10, 14* 10, 26*10, and two others of your choosing. (If one of the multiplications that I requested is inappropriate, then ignore it and perform three multiplications of your choosing. Explain why I messed up.)
If you got part A, the rest should be easy. Load your first input into the accumulator and jump program control down to your subroutine. Before starting the second computation, I recommend pushing your output onto the stack. (push af). Do the rest of the computations .
Prepare to close out. Your last solution is in A. Pop your earlier solutions off of the stack, and store them in the available registers.
pop hl
ld b,h
pop hl
ld c,h
etc.
When your program completes, you should have and 2*10, 14*10, .. in registers E, D, C, B, A. (Of course everything is actually in hex.) Print this page, and print your code to hand in with your exercise.
It works! ________
Microprocessors
Exercise 4
Divide X by 10 - two ways
We want to do an integer divide on an 8 bit constant. The brute force method would be to multiply by 0.1. What is 0.1 in binary? Lets use 16 bit registers, with the binary point between the eight bit halves. This limits us to inputs smaller than 128 (hex 80) because MUL is a signed operation. Hex 80 is interpreted as a negative number.
A. Brute force.
Put 0.1 in C and clear B.
Put X in D and clear E
Multiply
Where is the answer?
When working with the least significant bit, things are somewhat arbitrary. Successive Approximation truncates - it leads to a digital representation that is a fraction of a bit too small. The SA representation and SA + 1 are equally valid. Lets use SA + 1, so that the next exercise works with eight bits.
B. Shift and accumulate (Dont program this. SRA is limited to 8 bits. Think about it, but go with the program you wrote in A.)
Put X in D and clear E.
Clear HL for accumulation.
Shift DE right. This is ½ X. ½ is > 1/10 so dont accumulate.
Shift DE right. This is 1/4 X. 1/4 is > 1/10 so dont accumulate.
Shift DE right. This is 1/8 X. 1/8 is > 1/10 so dont accumulate.
Shift DE right. This is 1/16 X. 1/16 is < 1/10 so accumulate.
Shift DE right. This is 1/32 X. 3/32 is < 1/10 so accumulate.
Shift DE right. This is 1/64 X. 7/64 is > 1/10 so dont accumulate.
Etc.
Where is the answer?
It works! ________
INSTRUCTOR
Microprocessors
Exercise 5
The Puzzle
1. Think of a number greater than 1 and less than 10.
2. Multiply your number by 9. (Your number) x 9 = N. Now in decimal, N is a two digit number, (n1,n0). Rabbit wants N in hex, of course. Load N into one of Rabbits registers.
3. Figure out a way to solve for the decimal digits, n1 and n0. This is the hard part - work this out first. You can make good use of the subroutines, MULTEN and DIVTEN, that you have written in earlier exercises.
4. Calculate the sum of n1 and n0. Hex or decimal - its all the same.
5. Subtract 5 from what you got.. Rabbits part of the exercise ends here - Print your code and the registers and hand it in - show the instructor what you got.
6. Associate your final number with the letters of the alphabet. A=1, B=2, etc.
7. Think of a country that begins with your letter.
8. Look at the last letter in your countrys name - think of an animal that begins with that letter.
9. Hippety Hop. Here comes Rabbits cousin.
It works! ________
INSTRUCTOR
Microprocessors
Exercise 6
Light the lights
Write an assembly language program which turns on an LED. We need to use the RAM, rather than FLASH, so go to OPTIONS/COMPILER. Change the BIOS MEMORY SETTING to CODE AND BIOS IN RAM. The LEDs are in parallel with Port A which, by default, is an input port. We can fix that by setting the Slave Port Control Register (SPCR), which is located at 0x24. (Rabbit has macros which interpret the IO port mnemonics.)
LD HL,SPCR ; Puts 0x24 into HL
We load SPCR with 0x84 to make Port A an output port. Use 0x80 to make Port A an input port. Write 0x84 and 0x80 in binary. Which bit in SPCR are we toggling to switch Port A from input to output and back?
ioi LD (HL),0x84 ; Puts 0x84 into address 0x24
The LEDs are active low - they turn on when they see a zero. If we set Port A (PADR) to 0xFF, all the lights should be off. (PADR is located at 0x30.) 0xFE should set pin 0 to zero and LED1 should light up. Port pins are typically numbered (7, 6, 5, 4, 3, 2, 1, 0)
1. Turn on LED 3 only. Print your program.
2. Turn on LED2 only. Print your program.
3. Turn on LED2 and LED3. Print your program.
It works! ________
INSTRUCTOR
Microprocessors
Exercise 7
Blink the lights in C
Write a C language program which blinks LEDs. Open up SAMPLES/JACKRAB/DEMOJR1.C. SAVE AS this code to a floppy. You can use the C hard drive if you promise to delete it later. Name it something different, maybe MYPROG. Compile and execute your program. See LED3 blinking? It is off longer than it is on, isnt it.
Study the C code - the delay loops are quite analogous to the delay routine that you wrote in assembly language in Exercise 2. Study the system subroutine calls: With the cursor on a subroutine call, ctrl-h should give you a description of that subroutine. In this exercise we want to modify an existing program to make do something a bit different.
Change the delays so that LED3 is on as long as it was off. Make the on-time and the off-time the same. Print your program.
Change the program so that it is LED2, instead of LED3, that is blinking. Print your program.
Change the program so that LED2 and LED3 alternate - one or the other is always on.. Its LED2 on/LED3 off, LED2 off/LED3 on, LED2 on/LED3 off, etc. Print your program.
Up until now, we have always been plugged into a serial port of a desktop computer. The Rabbit is an embedded system - it's time it should stand on its own.
Unplug the program jack from the Rabbit. This moves the Rabbit from Program Mode to Run Mode.
Press Reset if necessary.
Repeat the above for several of programs that you have written. You can make the Rabbit perform without a big computer.
Microprocessors
Exercise 8
More blink the lights in C
(this time drive the stepper motors)
In the previous exercise, we blinked various combinations of LEDs at various cadences. Lets try for a combination that would drive a stepper motor.
The four LEDs are in parallel with pins 0, 1, 2, 3 of Port A. When we light up LED 1, we are also sending a zero to pin 0 of Port A. When LED 2 is dark, we are sending +5 volts to pin 1 of Port A, etc. Imagine the pins of Port A to be energizing (by way of a transistor switch driver) the coils of a stepper motor. The coils are traditionally named something like A, B,`A,`B , and they are connected to PA0, PA1, PA2, PA3:
Consider the following sequence of lights in an endless loop:
Coils energized |
PA3 |
PA2 |
PA1 |
PA0 |
A B |
1 |
1 |
0 |
0 |
`A B |
1 |
0 |
0 |
1 |
`A`B |
0 |
0 |
1 |
1 |
A`B |
0 |
1 |
1 |
0 |
The stepper motor should rotate counterclockwise. Actually, one cycle of the above sequence causes the stepper motor to rotate through 1.8° .
A. Write a program to make the LEDs flash through the sequence shown above in an endless loop. Choose delays that make the sequence easy to observe (even though that would make a stepper motor rotate painfully slow).
B. Alter your program to make the sequence repeat 100 times, and then stop. If a stepper motor were connected to Port A, what would happen?
Microprocessors
Exercise 9
This time interrupt that stepper motor
The notion of the "interrupt" is quite fundamental to embedded systems. In the last exercise we produced a sequence to drive a stepper motor, and we put it in an endless loop. Let's now use an interrupt to turn the motor off and on using switch #1 on the Jackrabbit board.
Start with SAMPLES/JACKRAB/DEMOJR3.C. We should be getting good at modifying other people's code:
Scrap the first task - we will provide our own flashing lights.
Task 2 is pretty much like what we want. Button 1 is debounced and used to toggle a virtual switch (vswitch).
(a) Scrap task ! - Keep task 2. Devise your own tests to convince yourself that your interrupt is working. For instance, pick a light to be on when vswitch is on and off when vswitch is off. Sounds like we need an IF statement following Task 2, doesn't it?
(b) Insert your light-flashing code from the last exercise. The lights should flash only when vswitch is on. The interrupt should start the lights flashing immediately when the button is pressed - to turn the lights off, you will have to hold down the button until the lights finish a sequence. Be patient!
Congratulations - you have just written your first "interrupt handler".