8051 Jump and Call Opcodes ,Calls and Subroutines, Interrupts and Returns,With Problems on Jump and Call

Calls and Subroutines

The life of a microcontroller would be very tranquil if all programs could run with no thought as to what is going on in the real world outside. However, a microcontroller is specifically intended to interact with the real world and to react, very quickly, to events that require program attention to correct or control.

A program that does not have to deal unexpectedly with the world outside of the microcontroller could be written using jumps to alter program flow as external conditions require. This sort of program can determine external conditions by moving data from the port pins to a location and jumping on the conditions of the port pin data. This technique is called "polling" and requires that the program does not have to respond to external condi­tions quickly. (Quickly means in microseconds; slowly means in milliseconds.)

Another method of changing program execution is using "interrupt" signals on cer­tain external pins or internal registers to automatically cause a branch to a smaller program that deals with the specific situation. When the event that caused the interruption has been dealt with, the program resumes at the point in the program where the interruption took place. Interrupt action can also be generated using software instructions named calls.

Call instructions may be included explicitly in the program as mnemonics or im­plicitly included using hardware interrupts. In both cases, the call is used to execute a smaller, stand-alone program, which is termed a routine or, more often, a subroutine.

Subroutines

A subroutine is a program that may be used many times in the execution of a larger pro­gram. The subroutine could be written into the body of the main program everywhere it is needed, resulting in the fastest possible code execution. Using a subroutine in this manner has several serious drawbacks.

Common practice when writing a large program is to divide the total task among many programmers in order to speed completion. The entire program can be broken into smaller parts and each programmer given a part to write and debug. The main program

can then call each of the parts, or subroutines. that have been developed and tested by each individual of the team.

Even if the program is written by one individual, it is more efficient to write an oft-used routine once and then call it many times as needed. Also, when writing a program, the programmer does the main part first. Calls to subroutines, which will be written later, enable the larger task to be defined before the programmer becomes bogged down in the details of the application.

Finally, it is quite common to buy "libraries" of common subroutines that can be called by a main program. Again, buying libraries leads to faster program development.

Calls and the Stack

A call, whether hardware or software initiated, causes a jump to the address where the called subroutine is located. At the end of the subroutine the program resumes operation at the opcode address immediately following the call. As calls can be located anywhere in the program address space and used many times, there must be an automatic means of storing the address of the instruction following the call so that program execution can continue after the subroutine has executed.

The stack area of internal RAM is used to automatically store the address, called the return address, of the instruction found immediately after the call. The stack pointer regis­ter holds the address of the last space used on the stack. It stores the return address above this space, adjusting itself upward as the return address is stored. The terms "stack" and "stack pointer" are often used interchangeably to designate the top of the stack area in RAM that is pointed to by the stack pointer.

Figure 6.2 diagrams the following sequence of events:

1. A call opcode occurs in the program software, or an interrupt is generated in the ardware circuitry.

2. The return address of the next instruction after the call instruction or interrupt is found in the program counter.

3. The return address bytes are pushed on the stack, low byte first.

4. The stack pointer is incremented for each push on the stack.

5. The subroutine address is placed in the program counter.

6. The subroutine is executed.

7. A RET (return) opcode is encountered at the end of the subroutine.

FIGURE 6.2 Storing and Retrieving the Return Address

clip_image002

8. Two pop operations restore the return address to the PC from the stack area in internal RAM.

9. The stack pointer is decremented for each address byte pop.

All of these steps are automatically handled by the 8051 hardware. It is the responsi­bility of the programmer to ensure that the suhroutine ends in a RET instruction and that the stack does not grow up into data areas that are used by the program.

Calls and Returns

Mnemonic

Operation

ACALL sadd

Call the subroutine located on the same page as the address of the opcode immediately following the ACALL instruction: push the address of the instruction immediately after the call on the stack

LCALL Ladd

Call the subroutine located anywhere in program memory space; push the address of the instruction immediately following the call on the stack

RET

Pop two bytes from the stack into the program counter

Note that no Hags are affected unless the stack pointer has been allowed to erroneously reach the address of the PSW special-function register.

Interrupts and Returns

As mentioned previously, an interrupt is a hardware-generated call. Just as a call opcode can be located within a program to automatically access a subroutine, certain pins on the 805 l can cause a call when external electrical signals on them go to a low state. Internal operations of the timers and the serial port can also cause an interrupt call to take place.

The subroutines called by an interrupt are located at fixed hardware addresses dis­cussed in Chapter 2. The following table shows the interrupt subroutine addresses.

INTERRUPT

ADDRESS (HEX) CALLED

IE0

0003

TF0

0008

IE1

0013

TF1

0018

SERIAL

0023

When an interrupt call takes place, hardware interrupt disable Hip-Hops are set to pre­vent another interrupt of the same priority level from taking place until an interrupt return instruction has been executed in the interrupt subroutine. The action of the interrupt rou­tine is shown in the table below.

Mnemonic

Operation

RETI

Pop two bytes from the stack into the program counter and reset the interrupt enable Hip-Hops

Note that the only difference between the RET and RETI instructions is the enabling of the interrupt logic when RETI is used. RET is used at the ends of subroutines called by an opcode. RETI is used by subroutines called by an interrupt.

The following program example use a call to a subroutine.

ADDRESS

MNEMONIC

COMMENT

MAIN:

MOV 8lh,#30h

:set the stack pointer to 30h in RAM

 

LCALL SUB

: push address of N0P; PC = #SUB; SP

 

NOP

:return from SUB to this opcode

 

……

 
 

……

 

SUB:

MOV A,#45h

;SUB loads A with 45h and returns

 

RET

;pop return address to PC; SP = 30h

CAUTION

Set the stack pointer above any area of RAM used for additional register banks or data memory. The stack may only be 128 bytes maximum; which limits the number of successive calls with no returns to 64.

Using RETI at the end of a software called subroutine may enable the interrupt logic erroneously. To jump out of a subroutine (not recommended), adjust the stack for the two return address bytes by POPing it twice or by moving data to the stack pointer to reset it to its original value.

Use the LCALL instruction if your subroutines are normally placed at the end of your program.

In the following example of an interrupt call to a routine, timer 0 is used in mode 0 to overflow and set the timer 0 interrupt flag. When the interrupt is generated, the program vectors to the interrupt routine, resets the timer 0 interrupt flag, stops the timer, and returns.

ADDRESS

MNEMONIC

COMMENT

 

.ORG 0000h

;begin program at 0000

 

AJMP OVER

;jump over interrupt subroutine

 

.0RG 000Bh

;put timer 0 interrupt subroutine here

 

CLR 8Ch

;stop timer0; set TR0 = 0

 

RETI

;return and enable interrupt structure

 

.

 
 

.

 

OVER:

MOV OA8h,#82h

;enable the timer 0 interrupt in the IE

MOV 89h,#00h

;set timer operation,mode 0

MOV 8Ah,#00h

;clear TLO

MOV 8Ch, #00h

;clear THO

SET 8Ch

;start timer 0; set TRO = 1

;the program will continue on and be interrupted when the timer has ;timed out

CAUTION

The programmer must enable any interrupt by setting the appropriate enabling bits in the IE register.

Example Problems

We now have all of the tools needed to write powerful, compact programs. The addition of the decision jump and call opcodes permits the program to alter its operation as it runs.

Ø EXAMPLE PROBLEM 6. 1

Place any number in internal RAM location 3Ch and increment it until the number equals 2Ah.

• Thoughts on the Problem The number can be incremented and then tested to see whether it equals 2Ah. If it does, then the program is over: if not, then loop back and decrement the number again.

Three methods can be used to accomplish this task.

•Method 1:

ADDRESS

MNEMONIC

COMMENT

ONE:

CLR C

;this program will use SUBB to detect equality

 

MOV A, #2Ah

;put the target number in A

 

SUBB A,3Ch

:subtract the contents of 3Ch: C is cleared

 

JZ DONE

;if A = 00h. then the contents of 3Ch = 2Ah

 

INC 3Ch

;if A is not zero. then loop until it is

 

SJMP ONE

;loop to try again

DONE:

NOP

;when finished. jump here and continue

COMMENT

As there is no compare instruction for the 8051, the SUBB instruction is used to compare A against a number. The SUBB instruction subtracts the C flag also. so the C flag has to be cleared before the SUBB instruction is used.

• Method 2:

ADDRESS

MNEMONIC

COMMENT

TWO:

INC 3Ch

:incrementing 3Ch first saves a jump later

 

MOV A,#2Ah

;this program will use X0R to detect equality

 

XRL A,3Ch

;X0R with the contents of 3Ch: if equal. A = 00h

 

JNZ TWO

;this jump is the reverse of program one

 

NOP

;finished when the jump is false

COMMENT

Many times if the loop is begun with the action that is to be repeated until the loop is satisfied. only one jump, which repeats the loop, is needed.

• Method 3:

ADDRESS

MNEMONIC

COMMENT

THREE:

INC 3Ch

;begin by incrementing the direct address

 

MOV A,#2Ah

;this program uses the very efficient CJNE

 

CJNE A.3Ch,THREE

;jump if A and (3Ch) are not equal

 

NOP

;all done

COMMENT

CJNE combines a compare and a jump into one compact instruction.

EXAMPLE PROBLEM 6.2

The number A6h is placed somewhere in external RAM between locations 0100h and 0200h. Find the address of that location and put that address in R6 (LSB) and R7 (MSB).

• Thoughts on the Problem The DPTR is used to point to the bytes in external memory, and CJNE is used to compare and jump until a match is found.

ADDRESS

MNEMONIC

COMMENT

 

MOV 20h,#0A6h

;load 20h with the number to be found

 

MOV DPTR, #00F’Fh

;start the DPTR below the first address

MOR:

INC DPTR

;increment first and save a jump

 

MOVX A. @DPTR

;get a number from external memory to A

 

CJNE A,20h,MOR

;compare the number against (20h) and

   

;loop to MOR if not equal

 

MOV R7,83h

;move DPH byte to R7

 

MOV R6,82h

;move DPL byte to R6; finished

COMMENT

This program might loop forever unless we know the number will be found; a check to see whether the DPTR has exceeded 0200h can be included to leave the loop if the number is not found before DPTR = 0201 h.

EXAMPLE PROBLEM 6.3

Find the address of the first two internal RAM locations between 20h and 60h which con­tain consecutive numbers. If so, set the carry flag to 1, else clear the flag.

• Thoughts on the Problem A check for end of memory will be included as a Called routine, and CJNE and a pointing register will be used to search memory.

ADDRESS

MNEMONIC

COMMENT

 

MOV 8lh. #65h

;set the stack above memory area

 

MOV R0,#20h

;load RO with address of memory start

NXT:

MOV A,@R0

;get first number

 

INC A

;increment and compare to next number

 

MOV lF’h,A

:store incremented number at lF’h

 

INC R0

;point to next number

 

CALL DUN

;see if RO greater than 60h

 

JNC THRU

;OUN returns C = 0 if over 60h

 

MOV A,@RO

;get next number

 

CJNE A, lF’h. NXT SETB 0D7h

;if not equal then look at next pair

THRU:

SJMP THRU

; set the carry to l: finished

DUN:

PUSH A

;jump here if beyond 60h

 

CLR C

;save A on the stack

 

MOV A. #6lh

;clear the carry

 

XRL A.R0

;use XOR as a compare

 

JNZ BCK

:A will be 0 if equal

 

RET

;if not 0 then continue

BCK:

POP A

;A 0, signal calling routine

 

CPL C

;get A back

 

RET

;A not 0, set C to indicate not done

COMMENT

set the stack pointer to put the stack out of the memory area in use.

Summary OF 8051 Jump and Call Opcodes

Jumps

Jumps alter program flow by replacing the PC counter contents with the address of the jump address. Jumps have the following ranges:

Relative: up to PC+ 127 bytes, PC -128 bytes away from the PC Absolute short: anywhere on a 2K-byte page

Absolute long: anywhere in program memory

Jump opcodes can test an individual bit, or a byte. to check for conditions that make the program jump to a new program address. The bit jumps are shown in the following table:

INSTRUCTION TYPE

RESULT

JC radd

Jump relative if carry flag set to 1

JNC radd

Jump relative if carry flag cleared to 0

JB b,radd

Jump relative if addressable bit set to 1

JNB b,radd

Jump relative if addressable bit cleared to 0

JBC b,radd

Jump relative if addressable bit set to 1 and clear bit to 0

Byte jumps are shown in the following table:

INSTRUCTION TYPE

RESULT

CJNE destination,source,address

Compare destination and source; jump to address if not equal

DJNZ destination.address

Decrement destination by one; jump to address if the result is not zero

JZ radd

Jump A = 00h to relative address

JNZ radd

Jump A > 00h to relative address

Unconditional jumps make no test and are always made. They are shown in the fol­lowing table:

INSTRUCTION TYPE

RESULT

JMP (riA+DPTR

Jump to 16-bit address formed by adding A to the DPTR

AJMP sadd

Jump to absolute short address

UMP ladd

Jump to absolute long address

SJMP radd

Jump to relative address

NOP

Do nothing and go to next Opcode

Call and Return

Software calls may use short- and long-range addressing; returns are to any long-range address in memory. Interrupts are calls forced by hardware action and call subroutines located at predefined addresses in program memory. The following table shows calls and returns:

INSTRUCTION TYPE

RESULT

ACALL sadd

Call the routine located at absolute short address

LCALL ladd

Call the routine located at absolute long address

RET

Return to anywhere in the program at the address found on the top two bytes of the stack

RETI

Return from a routine called by a hardware interrupt and reset the interrupt logic

Problems

Write programs for each of the following problems using as few lines of code as you can. Place comments on each line of code.

I. Put a random number in RJ and increment it until it equals EI h.

2. Put a random number in address 20h and increment it until it equals a random number put in R5.

3. Put a random number in RJ and decrement it until it equals Eth.

4. Put a random number in address 20h (LSB) and 21 h (MSB) and decrement them as if they were a single 16-bit counter until they equal random numbers in R2 (LSB) and RJ (MSB).

5. Random unsigned numbers are placed in registers R0 to R4. Find the largest number and put it in R6.

6. Repeat Problem 3, but find the smallest number.

7. If the lower nibble of any number placed in A is larger than the upper nibble. set the C flag to one; otherwise clear it.

8. Count the number of ones in any number in register B and put the count in R5.

9. Count the number of zeroes in any number in register RJ and put the count in R5.

10. If the signed number placed in R7 is negative, set the carry flag to I; otherwise clear it.

11. Increment the DPTR from any initialized value to ABCDh.

12. Decrement the DPTR from any initialized value to 0033h.

13. Use R4 (LSB) and R5 (MSB) as a single 16-bit counter, and decrement the pair until they equal 0000h.

14. Get the contents of the PC to the DPTR. IS. Get the contents of the DPTR to the PC.

16. Get any two bytes you wish to the PC.

17. Write a simple subroutine. call it, and jump back to the calling program after djusting the stack pointer.

18. Put one random number in R2 and another in R5. Increment R2 and decrement R5 ntil they are equal.

19. Fill external memory locations 100h to 200h with the number AAh.

20. Transfer the data in internal RAM locations 10h to 20h to internal RAM locations 30h to 40h.

21. Set every third byte in internal RAM from address 20h to 7Fh to zero.

22. Count the number of bytes in external RAM locations 100h to 200h that are greater than the random unsigned number in R3 and Jess than the random unsigned number in R4. Use registers R6 (LSB) and R7 (MSB) to hold the count.

23. Assuming the crystal frequency is 10 megahertz, write a program that will use timer 1 to interrupt the program after a delay of 2 ms.

24. Put the address of every internal RAM byte from 50h to 70h in the address; for instance, internal RAM location 6Dh would contain 6Dh.

25. Put the byte AAh in all internal RAM locations from 20h to 40h, then read them back and set the carry flag to I if any byte read back is not AAh.

Leave a comment

Your email address will not be published. Required fields are marked *