Professional Documents
Culture Documents
Address Sing
Address Sing
a different location. There are many instructions in the 8051 to achieve this. This chapter covers
the control transfer instructions available in 8051 Assembly language. In the first section we
discuss instructions used for looping, as well as instructions for conditional and unconditional
jumps. In the second section we examine CALL instructions and their uses. In the third section,
time delay subroutines are described for both the traditional 8051 and its newer generation.
Example 3-1
In the program in Example 3-1, the R2 register is used as a counter. The counter is first set to 10.
In each iteration the instruction DJNZ decrements R2 and checks its value. If R2 is not zero, it
jumps to the target address associated with the label “AGAIN”. This.looping action continues
until R2 becomes zero. After R2 becomes zero, it falls through the loop and executes the
instruction immediately below it, in this case the “MOV R5 , A” instruction.
Notice in the DJNZ instruction that the registers can be any of RO – R7. The counter can also be
a RAM location as we will see in Chapter 5.
Example 3-2
What is the maximum number of times that the loop in Example 3-1 can be repeated?
Solution:
Since R2 holds the count and R2 is an 8-bit register, it can hold a maximum of FFH (255
decimal); therefore, the loop can be repeated a maximum of 256 times.
Loop inside a loop
As shown in Example 3-2, the maximum count is 256. What happens if we want to repeat an
action more times than 256? To do that, we use a loop inside a loop, which is called a nested
loop. In a nested loop, we use two registers to hold the count. See Example 3-3.
Example 3-3
Write a program to (a) load the accumulator with the value 55H, and (b) complement the ACC
700 times.
Solution:
Since 700 is larger than 255 (the maximum capacity of any register), we use two registers to hold
the count. The following code shows how to use R2 and R3 for the count.
In this program, R2 is used to keep the inner loop count. In the instruction “DJNZ R2 , AGAIN”,
whenever R2 becomes 0 it falls through and “DJNZ R3 , NEXT” is executed. This instruction
forces the CPU to load R2 with the count 70 and the inner loop starts again. This process will
continue until R3 becomes zero and the outer loop is finished.
JZ (jump if A = 0)
In this instruction the content of register A is checked. If it is zero, it jumps to the target
address. For example, look at the following code.
OVER:
Table 3-1: 8051 Conditional Jump Instructions
In this program,. if either RO or Rl is zero, it jumps to the label OVER. Notice that the JZ
instruction can be used only for register A. It can only check to see whether the accumulator is
zero, and it does not apply to any other register. More importantly, you don’t have to perform an
arithmetic instruction such as decrement to use the JNZ instruction. See Example 3-4.
Example 3-4
Solution:
First notice that the JZ and JNC instructions both jump forward. The target address for a forward
jump is calculated by adding the PC of the following instruction to the second byte of the short
jump instruction, which is called the relative address. In line 4 the instruction “JZ NEXT” has
opcode of 60 and operand of 03 at the addresses of 0004 and 0005. The 03 is the relative address,
relative to the address of the next instruction INC RO, which is 0006. By adding 0006 to 3, the
target address of the label NEXT, which is 0009, is generated. In the same way for line 9, the
“JNC OVER” instruction has opcode and operand of 50 and 05 where 50 is the opcode and 05
the relative address. Therefore, 05 is added to GOOD, the address of instruction “CLR A”,
giving 12H, the address of label OVER.
Example 3-7
Verify the calculation of backward jumps in Example 3-6.
Solution:
In that program list, “JNC AGAIN” has opcode 50 and relative address F2H. When the relative
address of F2H is added to 15H, the address of the instruction below the jump, we have 15H +
F2H = 07 (the carry is dropped). Notice that 07 is the address of label AGAIN. Look also at
‘.’SJMP HERE”, which has 80 and FE for the opcode and relative address, respectively. The PC
of the following instruction, 0017H, is added to FEH, the relative address, to get 0015H, address
of the HERE label (17H + FEH = 15H). Notice that FEH is -2 and 17H + (-2) = 15H. For further
discussion of the addition of negative numbers, see Chapter 6.
Jump backward target address calculation
While in the case of a forward jump, the displacement value is a positive number between 0 to
127 (00 to 7F in hex), for the backward jump the displacement is a negative value of 0 to -128 as
explained in Example 3-7.
It must be emphasized that regardless of whether the SJMP is a forward or backward jump, for
any short jump the address of the target address can never be more than -128 to +127 bytes from
the address associated with the instruction below the SJMP. If any attempt is made to violate this
rule, the assembler will generate an error stating the jump is out of range.
OR
Logical OR Function
Inputs Output
X Y X OR Y
ORL destination,source ;dest = dest OR source
The destination and source operands are ORed, and the result is placed in the destination. The
ORL instruction can be used to set certain bits of an operand to 1. The destination is normally the
accumulator. The source operand can be a register, in memory, or immediate. See Appendix A
for more on the addressing modes supported by this instruction. The ORL instruction for byte-
size operands has no effect on any of the flags. See Example 6-18.
XOR
XRL destination,source ;dest = dest XOR source
This instruction will perform the XOR operation on the two operands, and place the result in the
destination. The destination is
normally the accumulator. The source operand can Logical XQR Function be a register, in
memory, or immediate. See Appendix A.I for the addressing modes of this instruction. The XRL
instruction for byte-size operands has no effect on any of the flags. See Examples 6-19 and 6-20.
XRL can also be used to see if two registers have the same value. “XRL A, Rl” will exclusive-or
register A and register Rl, and put the result in A. If both registers have the same value, 00 is
placed in A. Then we can use the JZ instruction to make a deci
Example 6-21
Read and test PI to see whether it has the value 45H. If it does, send 99H to P2; otherwise, it
stays’ cleared.
In the program in Example 6-21 notice the use of the JNZ instruction. JNZ and JZ test the
contents of the accumulator only. In other words, there is no such thing as a zero flag in the
8051.
Another widely used application of XRL is to toggle bits of an operand. For example, to
toggle bit 2 of register A, we could use the
following code. This code causes D2 of register A to change to the opposite value, while all the
other bits remain unchanged.
CPL A (complement accumulator)
This instruction complements the contents of register A. The complement action changes the Os
to Is and the 1 s to Os. This is also called 1 s complement.
meriting a byte, the data must be in register A. Although the CPL instruction cannot be used to
complement RO-R7, it does work on PO-P3 ports. See Appendix A to see which addressing
mode is available for the CPL instruction.
Compare instruction
The 8051 has an instruction for the compare operation. It has the following syntax.
CJNE destination,source,relative address
In the 8051, the actions of comparing and jumping are combined into a single instruction called
CJNE (compare and jump if not equal). The CJNE instruction compares two operands, and
jumps if they are not equal. In addition, it changes the CY flag to indicate if the destination
operand is larger or smaller. It is important to notice that the operands themselves remain
unchanged. For example, after the execution of the instruction “CJNE A, #67H, NEXT”, register
A still has its original value. This instruction compares register A with value 67H and jumps to
the target address NEXT only if register A has a value other than 67H.
Example 6-23
Examine the following code, then answer the following questions.
Solution:
In CJNE, the destination operand can be in the accumulator or in one of the Rn registers. The
source operand can be in a register, in memory, or immediate. See Appendix A for the
addressing modes of this instruction. This instruction affects the carry flag only. CY is changed
as shown in Table 6-3.
Example 6-24
Write code to determine if register A contains the value 99H. If so, make Rl = FFH; otherwise,
make Rl = 0.
The following shows how the comparison works for all possible conditions.
Notice in the CJNE instruction that any Rn register can be compared with an immediate value.
There is no need for register A to be involved. Also notice that CY is always checked for cases
of greater or less than, but only after it is determined that they are not equal. See Examples 6-25
through 6-27.
Example 6-25
Assume that PI is an input port connected to a temperature sensor. Write a program to read the
temperature and test it for the value 75. According to the test results, place the temperature value
into the registers indicated by the following.
Example 6-26
Write a program to monitor PI continuously for the value 63H. It should stop monitoring only if
PI = 63H.
Example 6-27
Assume internal RAM memory locations 40H – 44H contain the daily temperature for five days,
as shown below. Search to see if any of the values equals 65. If value 65 does exist in the table,
give its location to R4; otherwise, make R4 = 0.
40H=(76) 41H=(79) 42H=(69) 43H=(65) 44H=(62)
The compare instruction is really a subtraction, except that the values of the operands do not
change. Flags are changed according to the execution of the SUBB instruction. It must be
emphasized again that in the CJNE instruction, the operands are not affected, regardless of the
result of the comparison. Only the CY flag is affected. This is despite the fact that CJNE uses the
subtract operation to set or reset the CY flag.
The CPU can access data in various ways. The data could be in a register, or in memory, or be
provided as an immediate value. These various ways of accessing data are called addressing
modes. In this chapter we discuss 8051/52 addressing modes in the context of some examples.
The various addressing modes of a microprocessor are determined when it is designed, and
therefore cannot be changed by the programmer. The 8051 provides a total of five distinct
addressing modes. They are as follows:
1. immediate
2. register
3. direct
4. register indirect
5. indexed
In Section 5.1 we look at immediate and register addressing modes. In Section 5.2 we cover
accessing memory using the direct, register indirect, and indexed addressing modes. Section 5.3
discusses the bit-addressability of RAM, registers, and I/O ports. In Section 5.4 we show how to
access the extra 128 bytes of RAM in the 8052.
IMMEDIATE AND REGISTER
ADDRESSING MODES
The CPU can access data in various ways. The data could be in a register, or in memory, or be
provided as an immediate value. These various ways of accessing data are called addressing
modes. In this chapter we discuss 8051/52 addressing modes in the context of some examples.
The various addressing modes of a microprocessor are determined when it is designed, and
therefore cannot be changed by the programmer. The 8051 provides a total of five distinct
addressing modes. They are as follows:
changed by the programmer. The 8051 provides a total of five distinct addressing modes. They
are as follows:
1. immediate
2. register
3. direct
4. register indirect
5. indexed
In Section 5.1 we look at immediate and register addressing modes. In Section 5.2 we cover
accessing memory using the direct, register indirect, and indexed addressing modes. Section 5.3
discusses the bit-addressability of RAM, registers, and I/O ports. In Section 5.4 we show how to
access the extra 128 bytes of RAM in the 8052.
It should be noted that the source and destination registers must match in size. In other words,
coding “MOV DPTR, A” will give an error, since the source is an 8-bit register and the
destination is a 16-bit register. See the following.
Notice that we can move data between the accumulator and Rn (for n •— 0 to 7) but movement
of data between Rn registers is not allowed. For example, the instruction “MOV R4, R7″ is
invalid.
In the first two addressing modes, the operands are either inside one of the registers or tagged
along with the instruction itself. In most programs, the data to be processed is often in some
memory location of RAM or in the code space of ROM. There are many ways to access this data.
The next section describes these different methods.
1. RAM locations 00 – 1FH are assigned to the register banks and stack.
1. RAM locations 20 – 2FH are set aside as bit-addressable space to save
single-
bit data. This is discussed in Section 5.3.
2. RAM locations 30 – 7FH are available as a place to save byte-sized data.
Although the entire 128 bytes of RAM can be accessed using direct addressing
mode, it is most often used to access RAM locations 30 – 7FH. This is due to the fact
that register bank locations are accessed by the register names of RO – R7, but there
is no such name for other RAM locations. In the direct addressing mode, the data is
in a RAM memory location whose address is known, and this address is given as a
part of the instruction. Contrast this with immediate addressing mode, in which the
operand itself is provided with the instruction. The “#” sign distinguishes between
the two modes. See the examples below, and note the absence of the “#” sign.
The above examples should reinforce the importance of the “#” sign in 8051 instructions. See the
following code.
Although it is easier to use the names RQ – R7 than their memory addresses, RAM locations 3
OH to 7FH cannot be accessed in any way other than by their addresses since they have no
names.
SFR registers and their addresses
Among the registers we have discussed so far, we have seen that RO – R7 are part of the 128
bytes of RAM memory. What about registers A, B, PSW, and DPTR? Do they also have
addresses? The answer is yes. In the 8051, registers A, B, PSW, and DPTR are part of the group
of registers commonly referred to as SFR (special function registers). There are many special
function registers and they are widely used, as we will discuss in future chapters. The SFR can
be accessed by their names (which is much easier) or by their addresses. For example, register A
has address EOH, and register B has been designated the address FOH, as shown in Table 5-1.
Notice how the following pairs of instructions mean the same thing.
Table 5-1 lists the 8051 special function registers (SFR) and their addresses. The following two
points should be noted about the SFR addresses.
1. The special function registers have addresses between 80H and FFH. These
addresses are above 80H, since the addresses 00 to 7FH are addresses of RAM
memory inside the 8051.
2. Not all the address space of 80 to FF is used by the SFR. The unused locations
80H to FFH are reserved and must not be used by the 8051 programmer.
3. Regarding direct addressing mode, notice the following two points: (a) the address value
is limited to one byte, 00 – FFH, which means this addressing mode is limited to
accessing RAM locations and registers located inside the 8051. (b) if you examine the 1st
file for an Assembly language program, you will see that the SFR registers’ names are
replaced with their addresses as listed in Table 5-1.
4.
5.
6. Stack and direct addressing mode
7. Another major use of direct addressing mode is the stack. In the 8051 family, only direct
addressing mode is allowed for pushing onto the stack. Therefore, an instruction such as
“PUSH A” is invalid. Pushing the accumulator onto the stack must be coded as “PUSH
OEOH” where OEOH is the address of register A. Similarly, pushing R3 of bank 0 is
coded as “PUSH 03″. Direct addressing mode must be used for the POP instruction as
well. For example, “POP 04″ will pop the top of the stack into R4 of bank 0.
8. Example 5-2
9. Show the code to push R5, R6, and A onto the stack and then pop them back them into
R2, R3, and B, where register B = register A, R2 = R6, and R3 = R5.
In the above program ROM locations 200H – 202H have the following contents. 200=(‘U’)
201=(‘S’) 202=(‘A”)
We start with DPTR = 200H, and A = 0. The instruction “MOVC A, @A+DPTR” moves the
contents of ROM location 200H (200H + 0 = 200H) to register A. Register A contains 55H, the
ASCII value for “U”. This is moved to RO. Next, DPTR is incremented to make DPTR = 201H.
A is set to 0 again to get the contents of the next ROM location 201H, which holds character “S”.
After this program is run, we have RO = 55H, Rl = 53H, and R2 = 41H, the ASCII values for the
characters “U”, “S” and “A”.
Example 5-7
Assuming that ROM space starting at 250H contains “America”, write a program to transfer the
bytes into RAM locations starting at 40H.
Look-up table and the MOVC instruction
The look-up table is a widely used concept in microprocessor programming. It allows access to
elements of a frequently used table with minimum operations. As an example, assume that for a
certain application we need x2
values in the range of 0 to 9. We can use a look-up table instead of calculating it. This is shown
in Example 5-8.
Example 5-8
Write a program to get the x value from PI and send x2
to P2, continuously.
In addition to being used to access program ROM, DPTR can be used to access memory
externally connected to the 8051. This is discussed in Chapter 14.
Another register used in indexed addressing mode is the program counter. This is discussed in
Appendix A.
In many of the examples above, the MOV instruction was used for the sake of clarity, even
though one can use any instruction as long as that instruction supports the addressing mode. For
example, the instruction “ADD A, @RO” would add the contents of the memory location
pointed to by RO to the contents of register A. We will see more examples of using addressing
modes with various instructions in the next few chapters.
Indexed addressing mode and MOVX instruction
As we have stated earlier, the 8051 has 64K bytes of code space under the direct control of the
Program Counter register. We just showed how to use the MOVC instruction to access a portion
of this 64K-byte code space as data memory space. In many applications the size of program
code does not leave any room to share the 64K-byte code space with data. For this reason the
8051 has another 64K bytes of memory space set aside exclusively for data storage. This data
memory space is referred to as external memory and it is accessed only by the MOVX
instruction. In other words, the 8051 has a total of 128K bytes of memory space since 64K bytes
of code added to 64K bytes of data space gives us 128K bytes. One major difference between the
code space and data space is that, unlike code space, the data space cannot be shared between
code and data. This is such an important topic that we have dedicated an entire chapter to it:
Chapter 14.
Accessing RAM Locations 30 – 7FH as scratch pad
As we have seen so far, in accessing registers RO – R7 of various banks, it is much easier to
refer to them by their RO – R7 names than by their RAM locations. The only problem is that we
have only 4 banks and very often the task of bank switching and keeping track of register bank
usage is tedious and prone to errors. For this reason in many applications we use RAM locations
30 – 7FH as scratch pad and leave addresses 8 – 1FH for stack usage. That means that we use
RO – R7 of bank 0, and if we need more registers we simply use RAM locations 30-7FH.
10.
11. Register indirect addressing mode
12. In the register indirect addressing mode, a register is used as a pointer to the data. If the
data is inside the CPU, only registers RO and Rl are used for this purpose. In other words,
R2 – R7 cannot be used to hold the address of an operand located in RAM when using
this addressing mode. When RO and Rl are used as
13.
14.
15. pointers, that is, when they hold the addresses of RAM locations, they must be
preceded by the “@” sign, as shown below.
16.
17. Notice that RO (as well as Rl) is preceded by the “@” sign. In the absence of the
“@” sign, MOV will be interpreted as an instruction moving the contents of register
RO to A, instead of the contents of the memory location pointed to by RO.
18. Example 5-3
19.
In rotate left, the 8 bits of the accumulator are rotated left one bit, and bit D7 exits from the MSB
(most significant bit) and enters into DO (least significant bit). See the code and diagram.
In RLC A, as bits are shifted from right to left they exit the MSB and enter the carry flag, and the
carry flag enters the LSB. In other words, in RCL the MSB is moved to CY (carry flag) and CY
is moved to the LSB. See the following code and diagram.
Serializing data
Serializing data is a way of sending a byte of data one bit at a time through a single pin of
microcontroller. There are two ways to transfer a byte of data serially:
1. Using the serial port. In using the serial port, programmers have very limited
control over the sequence of data transfer. The details of serial port data trans
fer are discussed in Chapter 10.
1. The second method of serializing data is to transfer data one bit at a time and
control the sequence of data and spaces in between them. In many new generations of devices
such as LCD, ADC, and ROM, the serial versions of these devices are becoming popular since
they take less space on a printed circuit board. We discuss this important topic next.
Serializing a byte of data
Serializing data is one of the most widely used applications of the rotate instruction. We showed
in Chapter 5 how the CY flag status can be moved to any pin of ports PO – P3. Using that
concept and the rotate instruction, we transfer a byte of data serially (one bit at a time).
Repeating the following sequence 8 times will transfer an entire byte, as shown in Example 6-28.
Example 6-29 shows how to bring in a byte of data serially one bit at a time. We will see how to
use these concepts in Chapter 13 for a serial ADC chip.
Example 6-28
Write a program to transfer value 41H serially (one bit at a time) via pin P2.1. Put two highs at
the start and end of the data. Send the byte LSB first.
Solution:
Example 6-29
Write a program to bring in a byte of data serially one bit at a time via pin P2.7 and save it in
register R2. The byte comes in with the LSB first.
SWAP A
Another useful instruction is the SWAP instruction. It works only on the accumulator (A). It
swaps the lower nibble and the higher nibble. In other words,
the lower 4 bits are put into the higher 4 bits, and the higher 4 bits are put into the lower 4
bits. See the diagrams below and Example 6-33.
Example 6-33
Solution: