805l Microcontroller Design, Introduction , Microcontroller Specification, Microcontroller Design and Testing the Design

Introduction

In this chapter a hardware configuration for an 805 I microcontroller, which will be used for all of the example applications in Chapters 8 and 9, is defined. Programs that check the initial prototype of the design (debugging programs) are given in this chapter, followed by several common subroutines that can be used by programs in succeeding chapters.

The design of the microcontroller begins with an identified need and a blank piece of

paper or computer screen. The evolution of the microcontroller follows these steps:

1. Define a specification.

2. Design a microcontroller system to this specification.

3. Write programs that will assist in checking the design.

4. Write several common subroutines and test them. L00

The most important step is the first one. If the application is for high-volume produc­tion (greater than 10000 units). then the task must be very carefully analyzed. A precise or "tight" specification is evolved for what will become a major investment in factory ­programmed parts. As the volume goes down for any particular application, the specifica­tions become more general as the designers attempt to write a specification that might fit a wider range of applications.

The list leaves out a few real-world steps, most notably the redesign of the micro­controller after it is discovered that the application has grown beyond the original specifi­cation or, as is more common, the application was not well underst00d in the beginning. Experienced designers learn to add a litT1e "fat" to the specification in anticipation of the inexorable need for "one more bit of I/O and one more kilobyte of memory."

A Microcontroller Specification

A typical ouT1ine for a microcontroller design might read as follows:

"A requirement exists for an intelligent controller for real-time control and data moni­toring applications. The controller is part of a networked system of identical units that are connected to a host computer through a serial data link. The controller is to be produced in low volumes, typically less than one thousand units for any particular application, and it must be low cost."

The 805l family is chosen for the following reasons:

Low part cost

Multiple vendors

Available in NMOS and CMOS technologies

Software t00ls available and inexpensive

High-level language compilers available

The first three items are very important from a production cost standpoint. The soft­ware aids available reduce first costs and enable projects to be completed in a timely manner.

The low-volume production requirement and the need for changing the program to fit particular applications establish the necessity of using external EPROM to hold the appli­cation program. In turn, ports o (AD0-AD7) and 2 (AS-Al5) must be used for inter­facing to the external ROM and will not be available for I/O.

Because one possible use of the controller will be to gather data, RAM beyond that available internally may be needed. External RAM is added for this eventuality. The immediate consequence of this decision is that port 3 bits 6 (͞W͞R) and 7 (͞R͞D) are needed for the external RAM and are not available for I/O. External memory uses the 2S-pin standard configuration, which enables memories as large as 64K to be inserted in the memory sockets.

Commercially available EPROM parts that double in size beginning at 2K bytes can be purchased. The minimum EPROM size selected is SK and the maximum size is 64K. These choices reflect the part sizes that are most readily available from vendors and parts that are now beginning to enter high-volume production.

Static RAM parts are available in 2K, SK, and 32K byte sizes; again. the RAM sizes are chosen to be SK or 32K to reflect commercial realities. The various memory sizes can be incorporated by including jumpers for the additional address lines needed by larger memories and pull up resistors to enable alternate pin uses on smaller memories.

The serial data needs can be handLED by the internal serial port circuitry. once again, two more I/O pins of port 3 are used: bits 3.0 (RXD) and 3.l (TXD). We are left with all of port l for general-purpose I/O .and port 3 pins 2-5 for general-purpose I/O. or for exter­nal interrupts and timing inputs.

Note that rapid loss of I/O. capability occurs as the alternate port functions are used and should be expected unless volumes are high enough to justify factory-programmed parts.

The handicap is not as great as it appears, however; two methods exist that are commonly used to expand the I/O. capability of any computer application: port I/O. and memory­mapped I/O.

Finally, we select a l6 megahertz crystal to take advantage of the latest high-speed devices available, and the specification is complete. To summarize, we have

80C3 l – l (ROM less) microcontroller

64K bytes of external EPROM

32K bytes of external RAM

8 general-purpose I/O lines

4 general-purpose or programmable I/O lines

1 full-duplex serial port

16 megahertz crystal clock

Now that the specification is complete, the design can be done.

A Microcontroller Design

The final design, shown in Figure 7. l, is based on the external memory circuit found in Chapter 2. Any I/O circuitry needed for a particular application will be added to the basic design as required. A design may be done in several ways; the choices made for this design are constrained by cost and the desire for flexibility.

External Memory and Memory Space Decoding

External memory is added by using port o as a data and low-order address bus, and port 2 as a high-order address bus. The data and low addresses are time multiplexed on port o. An external 373 type address latch is connected to port 0 to store the low address byte whenever external memory is accessed. The low-order address is gated into the trans­parent latch by the ALE pulse from the 805l . Port 0then becomes a bidirectional data bus during the read or write phase of a machine cycle.

RAM and ROM are addressed by entirely different control lines f ROM the 8051: PSEN for the ROM and WR or RD for the RAM. The result is that each occupies one of two parallel 64 kilobyte address spaces. The decoding problem becomes one of simply adding suitable jumpers and pullup resistors so that the user can insert the memory capacity needed. Jumpers are inserted so that the correct address line reaches the memory pin or the pin is pulLED high as required by the memory used. The jumper table in Figure 7. I for the EPROM and RAM memories that can be inserted in the memory sockets shows the jumper configuration. Figure 7 .2 graphically demonstrates the relative sizes of the internal and external memories available to the programmer.

Reset and Clock Circuits

The 8051 uses an active high reset pin. The reset input must go high for two machine cycles when power is first applied and then sink low. The simple RC circuit used here will supply system voltage (Vee) to the reset pin until the capacitor begins to charge. At a threshold of about 2.5 V, the reset input reaches a low level, and the system begins to run. Internal reset circuitry has hysteresis necessitated by the slow fall time of the RC circuit.

clip_image002

The addition of a reset button enables the user to reset the system without having to turn power off and on.

The clock circuit of Chapter 2 is added, and the design is finished.

Expanding I/O

Ports l and 3 can be used to form small control and bidirectional data buses. The data buses can interface with additional external circuits to expand I/O up to any practical number of lines.

FIGURE 7.2 8o3l Memory Sizes

clip_image004

There are many popular families of programmable port chips. The one chosen here is the popular 8255 programmable interface adaptor, which is available f ROM a number of vendors. Details on the full capabilities of the 8255 are given in Appendix D. The 8255 has an internal mode register to which control words are written by the host computer. These control words determine the actions of the 8255 ports, named A, B, and C, enab­ling them to act as input ports, output ports, or some combination of both.

Figure 7 .3 shows a circuit that adds an 8255 port expansion chip to the design. The number of ports is now three 8-bit ports for the system. The penalty paid for expanding I/O in this manner is a reduction in speed that occurs due to the overhead time needed to write control bits to ports I and 3 before the resulting I/O lines selected can be accessed. The advantage of using I/O port expansion is that the entire range of 8051 instructions can be used to access the added ports via ports I and 3.

Memory-Mapped I/O

The same programmable chip used for port expansion can also be added to the RAM memory space of the design, as shown in Figure 7 .4. The present design uses only 32K of

clip_image006

the permitted 64K of RAM address space; the upper 32K is vacant. The port chip can be addressed any time Al5 is high (8000h or above), and the 32K RAM can be addressed whenever A l5 is low (7FFFh and below). This decoding scheme requires only the addi­tion of an inverter to decode the memory space for RAM and I/O.

Should more RAM be added to the design, a comprehensive memory-decoding scheme will require the use of a programmable array-type decoder to reserve some portion of mem­ory space for the I/O port chips. Figure 7.4 shows a design that permits the addition of three memory-mapped port chips at addresses FFFoh-FFF3h, FFF4h-FFF7h, FFF8h-FFFBh. and FFFCh- FF

FFh. RAM is addressable from 0000h to FFEFh.

Memory-mapped I/O has the advantage of not using any of the 8051 ports. Disadvan­tages include the loss of memory space for RAM that is used by the I/O address space, or the addition of memory decoding chips in order to limit the RAM address space loss. Programming overhead is about the same as for port I/O because only the cumbersome MOVX instruction may be used to access the memory-mapped I/O.

For both types of I/O expansion, the cost of the system begins to mount. At some point, a conventional microprocessor, with a rich set of I/O and memory instructions. may become a more economical choice.

Paclip_image008

Part Speed

one consideration, that does not appear on the design drawings, is the selection of parts that will work at the system speeds determined by the crystal frequency. All memory parts are priced according to the nanosecond of access time. The longer the access time (the time it takes for a byte of data to be read or written from or to the device after the address is valid), the cheaper the part. For our design, Figure 7.4 shows the timing involved in reading data from the ROM and reading and writing data to the RAM. These times are totally determined by the selection of the crystal frequency, and the designer must ch00se memory parts that are fast enough to keep up with the microcontroller at the chosen fre­quency. For our example, EPROMS with maximum access times of l5o ns and RAM with access times of 400 ns must be used. These access times are representative of standard commercial types currenT1y available at the low end of the cost spectrum. These times are worst-case times; actual access times are at least 3o percent longer.

other parts, such as the ‘373 type latch can be any family from lSTT1 to HCMoS.

The speeds of these parts far exceed the speed of the 8051 .

Production Concerns

The design omits many features that would be incorporated by a design-manufacturing team. Chief among these are the inclusion of test-points, LED indicators, and other items that should he added to enhance manufacturing and field service of the microcontroller.

These concerns are well beyond the scope of this b00k, but the wise designer always ensures that the legitimate concerns of the technical, manufacturing, and service depart­ments are addressed.

Testing the Design

once the hardware has been assemb LED, it is necessary to verify that the design is correct and that the prototype is built to the design drawing. This verification of the design is done by running several small programs, beginning with the most basic program and building on the demonstrated success of each.

Crystal Test

The initial test is to ensure that both the crystal and the reset circuit are working. The 8051 is inserted in the circuit, and the ALE pulse is checked with an oscilloscope to verify that the ALE frequency is I /6 of the crystal frequency. Next, the reset button is pushed, and all ports are checked to see that they are in the high (input) state.

ROM Test

The most fundamental program test is to ensure that the microcontroller can fetch and execute programs from the EPROM. Code byte fetching can be tested by verifying that each address line of the ROM is properly wired by using a series of repeated jump instruc­tions that exercise all of the address lines. The test used here will jump to addresses that are a power of two. only one address line will be high, and all of the rest will be low. The address pattern tests for proper wiring of each address line and also checks for shorts between any two lines.

If the test is successful, the program stops at the highest possible ROM address. The address bus can then be checked with a logic probe to verify that the highest address has been reached. Correct operation is indicated by the highest order address bus bit, which will appear constant. If not, the probe will blink indicating random program fetches.

The test is run by inserting the ‘373 latch, the programmed 64K EPROM, inserting jumpers I – 3 and resetting the 8051 . The test can be stopped at any address by jumping to that address, as is done in the last statement in the following ROM test program:

ADDRESS

MNEMONIC

COMMENT

 

.org 0000h

;start at the bottom of ROM

begin:

l jmp add2

;test address lines A0 and Al

 

.org 0004h

;next jump at address 0004h (A2)

add2:

1jmp add3

;test address line A2

 

.org 0008h

;next jump at address 0008h (A3)

add3:

1jmp add4

;test address line A3

 

.org 0010h

;next jump at address 0010h (A4)

add4:

1jmp add5

;test address line A4

 

.org 0020h

;next jump at address 0020h (A5)

add5:

1jmp add5

;test address line A5

 

.org 0040h

;next jump at address 0040h (AG)

Add6:

1jmp add7

;test address line AG

 

.org 0080h

;next jump at address 0080h (A7)

Add7:

1jmp add8

;test address line A7

   

.erg 0100h

;next jump at address 0100h (AB)

add8:

1jmp add9

;test address line A8

   

.erg 0200h

;next jump at address 0200 (A9)

add9:

1jmp addl0

;test address line A9

 

.erg 0400h

;next jump at address 0400h (Alo)

Add10:

1jmp add11

;test address line Al0

   

.erg 0800h

;next jump at address 0800h (All)

Add11:

1jmp addl2

;test address line All

   

. erg 1000h

;next jump at address 1000h (Al2)

Add12:

1jmp addl3

;test address line Al2

   

.erg 2000h

;next jump at address 2000h (Al3)

addl3:

1jmp addl4

;test address line Al3

   

.erg 4000h

;last jump at address 4000h (Al4)

addl4:

1jmp addl5

;test address line Al4

   

.erg 8000h

;test address line Al5 and remain here

addl5:

. 1jmp addl5

;jump here in a l00p

   

.end

;assembler use

;This address, Al5, will remain latched while A2-Al4 will

;remain low. Ao and Al will vary as the bytes of the jump

;instruction are fetched.

 
         

Inspection of the listing for this program in Figure 7.5 shows that all the address lines are exercised.

RAM Test

once sure of the ability of the microcontroller to execute code, the RAM can be checked. A common test is to write a so-CALLED checkerboard pattern to RAM-that is, an alternating pattern of 1 and o in memory. Writing bytes of 55h or AAh will generate such a pattern.

The next program writes this pattern to external RAM, then reads the pattern back and checks each byte read back against the byte that was written. If a check fails, then the address where the failure occurred is in the DPTR register. Port l and the free bits of port 3 can then be used to indicate the contents of DPTR.

There are l4 bits available using these ports (the serial port is not in use now, so bits 3.o and 3.l are free), and l5 are needed to express a 32K address range. The program will test a range of SK bytes at a time, using l3 bits to hold the 8K address upon failure. Four versions have to be run to cover the entire RAM address space. If the test is passed, then bit l4 (port 3.5) is a l. If the test fails, then bit l4 is a o, and the other l3 bits hold the address (in the SK page) at which the failure occurred.

Interestingly, this test does not check for correct wiring of the RAM address lines. As long as all address lines end on some valid address, the test will work. A wiring check requires that a ROM be programmed with some unique pattern at each address that is a power of two and read using a check program that inspects each unique address location for a unique pattern.

The RAM test program is listed on the following page.

FIGURE 7.5 AssembLED ROM Check Program

0000

 

.org 0000h

;start at the bottom of ROM

 

0000 o20004

begin:

1jmp add2

;test address lines A0 and Al

 

0004

 

.org 0004h

;next jump at address 0004h (A2)

 

0004 020008

add2:

1jmp add3

;test address line A2

 

0008

 

.org 0008h

;next jump at address 0008h (A3)

 

0008 o200l0

add3:

1jmp add4

;test address line A3

 

00l0

 

.org 00l0h

;next jump at address 00loh (A4)

 

00l0 020020

add4:

1jmp add5

;test address line A4

 

0020

 

,org 0020h

;next jump at address 0020h (A5)

 

0020 020040

add5:

1jmp addG

;test address line A5

 

0040

 

.org 0040h

;next jump at address 0040h (AG)

 

0040 020080

addG:

1jmp add?

;test address line AG

 

0080

 

.org 0080h

;next jump at address 0080h (A7)

 

0080 020l00

add?:

1jmp add8

;test address line A7

 

0l00

 

.org 0l00h

;next jump at address 0l00h (AS)

 

0l00 020200

add8:

1jmp add9

;test address line AB

 

0200

 

.org 0200h

;next jump at address 0200h (A9)

 

o200 o2o400

add9:

1jmp addlo

;test address line A9

 

o400

 

.org o400h

;next jump at address o400h (Al0)

 

0400 020800

Addl0:

1jmp addll

;test address line Al0

 

0800

 

.org 0800h

;next jump at address 0800h (A11)

 

0800 02l000

Add11:

1jmp addl2

;test address line All

 

l000

 

.org l000h

;next jump at address l000h (Al2)

 

l000 022000

addl2:

1jmp addl3

;test address line Al2

 

2000

 

.org 2000h

;next jump at address 2000h (Al3)

 

2000 024000

addl3:

1jmp addl4

;test address line Al3

 

4000

 

.org 4000h

;last jump at address 4000h (Al4)

 

4000 028000

addl4:

1jmp addl5

;test address line Al4 and remain

 

8000

 

.org 8000h

;test address line Al5 and remain

 
     

;here

 

8000 028000

addl5:

1jmp addl5

;jump here in a l00p

 

8003

 

.end

;assembler use

 

ADDRESS

MNEMONIC

COMMENT

 
 

.equ ramstart,0000h

;set RAM test start address

 
 

.equ rmstphi,2oh

;set RAM test high stop address

 
 

.equ pattern,55h

;determine test pattern

 
 

. equ g00d. 2oh

;RAM g00d pattern P3.5 = l

 
 

. equ bad. odfh

;RAM bad pattern,P3.5 = 0

 
 

.org 0000h

;begin test program at 0000h

 
 

mov p3,#0ffh

;set Port 3 high

 
 

mov dptr,#ramstart

;initialize DPTR

 

test:

mov a,#pattern

;set pattern byte

 
 

MOVX @dptr. a

;write byte to RAM

 
 

inc dptr

;point to next RAM byte

 
 

mov a,#rmstphi

;check to see if at stop address

 
 

cjne a,dph,test

;if not then l00p until done

 
 

mov dptr,#ramstart

;start read-back test

 

check:

MOVX a,@dptr

;read byte from RAM

 
 

cjne a,#pattern.fail

;test against what was written

 
 

inc dptr

;go to next byte if tested ok

 
 

mov a,#rmstphi

;check to see if all bytes tested

 
 

cjne a,dph,check

;if not then check again

 
 

Mov p3. #g00d

;checked ok, set Port 3 to g00d

 

here:

sjmp here

;stop here

 

Fail:

Mov p3,dph

;test faiLED, get address

 
 

Anl p3,#bad

;set 3.5 to zero

 
 

mov pl,dpl

;set Port l to low address byte

 

there:

sjmp there

;stop there

 
 

end

;point to next RAM byte

 

COMMENT

Change the ramstart and rmstphi .equ hex numbers to check pages 2000h to 3FFFh, 4000h to SFFFh, and 6000h to 7FFFh.

Note that a full l6-bit check for end of memory does not have to be done due to page bounda­ries of (20)00, (40)00. (60)00, and (80)00h.

There is no haft command for the 8051; jumps in place serve to perform the halt function.

We have now tested all the external circuitry that has been added to the 8051. The remainder of the chapter is devoted to several subroutines that can be used by the applica­tion programs in Chapters 8 and 9.

 

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.

 

8051 Jump and Call Opcodes ,Introduction,The Jump and Call Program Range ,and Jumps

Introduction

The opcodes that have been examined and used in the preceding chapters may be thought of as action codes. Each instruction performs a single operation on hytes of data.

The jumps and calls discussed in this chapter are decision codes that alter the flow of the program by examining the results of the action codes and changing the contents of the program counter. A jump permanently changes the contents of the program counter if cer­tain program conditions exist. A call temporarily changes the program counter to allow another part of the program to run. These decision codes make it possible for the program­mer to let the program adapt itself, as it runs, to the conditions that exist at the time.

While it is true that computers can’t "think" (at least as of this writing), they can make decisions about events that the programmer can foresee, using the following deci­sion opcodes:

Jump on bit conditions

Compare bytes and jump if not equal

Decrement byte and jump if zero

 Jump unconditionally

Call a subroutine

Return from a subroutine

Jumps and calls may also be generically referred to as "branches," which emphasizes that two divergent paths are made possible by this type of instruction.


The Jump and Call Program Range

A jump or call instruction can replace the contents of the program counter with a new program address number that causes program execution to begin at the code located at the new address. The difference, in bytes, of this new address from the address in the program where the jump or call is located is called the range of the jump or call. For example, if a jump instruction is located at program address 0100h, and the jump causes the program counter to become 0 I 20h, then the range of the jump is 20h bytes.

Jump or call instructions may have one of three ranges: a relative range of +I 27d, -128d bytes from the instruction following the jump or call instruction; an absolute range on the same 2K byte page as the instruction following the jump or call; or a long range of any address from 0000h to FFFFh, anywhere in program memory. Figure 6.1 shows the relative range of all the jump instructions.

FIGURE 6.1 Jump Instruction Ranges

clip_image002[4]

 

Relative Range

Jumps that replace the program counter contents with a new address that is greater than the address of the instruction following the jump by I 27d or less than the address of the in­struction following the jump by I 28d are called relative jumps. They are so named because the address that is placed in the program counter is relative to the address where the jump occurs. If the absolute address of the jump instruction changes, then the jump address changes also hut remains the same distance away from the jump instruction. The address following the jump is used to calculate the relative jump because of the action of the PC. The PC is incremented to point to the next instruction before the current instruc­tion is executed. Thus, the PC is set to the following address before the jump instruction is executed, or in the vernacular: "before the jump is taken."

Relative jumping has two advantages. First, only one byte of data need be specified, either in positive format for jumps ahead in the program or in 2’s complement negative format for jumps behind. The jump address displacement byte can then be added to the PC to get the absolute address. Specifying only one byte saves program bytes and speeds up program execution. Second. the program that is written using relative jumps can be lo­cated anywhere in the program address space without re-assembling the code to generate absolute addresses.

The disadvantage of using relative addressing is the requirement that all addresses jumped be within a range of+ 127d, -128d bytes of the jump instruction. This range is not a serious problem. Most jumps form program loops over short code ranges that are within the relative address capability. Jumps are the only branch instructions that can use the relative range.

If jumps beyond the relative range are needed, then a relative jump can be done to another relative jump until the desired address is reached. This need is better handled, however. by the jumps that are covered in the next sections.

Short Absolute Range

Absolute range makes use of the concept of dividing memory into logical divisions called "pages." Program memory may be regarded as one continuous stretch of addresses from 0000h to FFFFh. Or, it may be divided into a series of pages of any convenient binary size. such as 256 bytes, 2K bytes, 4K bytes, and so on.

The 805 I program memory is arranged as 2K byte pages, giving a total of 32d (20h) pages. The hexadecimal address of each page is shown in the following table:

PAGE

ADDRESS(HEX)

PAGE

ADDRESS(HEX)

PAGE

ADDRESS(HEX)

00

0000-07FF

0B

5800-5FFF

16

B000-B7FF

01

0800-0FFF

oc

6000-67FF

17

8800-BFFF

02

1000-17FF

0D

6800-6FFF

18

C000-C7FF

03

1800-lFFF

0E

7000-77FF

19

C800-CFFF

04

2000-27FF

0F

7800-7FFF

lA

0000-07FF

05

2800-2FFF

10

8000-87FF

1B

0800-0FFF

06

3000-37FF

11

8800-8FFF

lC

E000-E7FF

07

3800-3FFF

12

9000–97FF

10

E800-EFFF

08

4000-47FF

13

9800-9FFF

lE

F0000-F7FF

09

4800-4FFF

14

A000-A7FF

1 F

F800-FFFF

0A

5000-57FF

15

A800-AFFF

 

 

Inspection of the page numbers shows that the upper five bits of the program counter hold the page number, and the lower eleven bits hold the address within each page. An absolute address is formed by taking the page number of the instruction following the branch and attaching the absolute page range address of eleven bits to it to form the 16-bit address.

Branches on page boundaries occur when the jump or call instruction finishes at X7FFh or XFFFh. The next instruction starts at X800h or X000h, which places the jump or call address on the same page as the next instruction after the jump or call. The page change presents no problem when branching ahead but could be troublesome if the branch is backwards in the program. The assembler should flag such problems as errors, so ad­justments can be made by the programmer to use a different type of range.

Absolute range addressing has the same advantages as relative addressing; fewer bytes are needed and the code is relocatable as long as the relocated code begins at the start of a page. Absolute addressing has the advantage of allowing jumps or calls over longer programming distances than does relative addressing.

long Absolute Range

Addresses that can access the entire program space from 0000h to FFFFh use long range addressing. Long-range addresses require more bytes of code to specify and are relocat­able only at the beginning of 64K byte pages. Since we are limited to a nominal ROM address range of 64K bytes, the program must be re-assembled every time a long-range address changes and these branches are not generally relocatable.

Long-range addressing has the advantage of using the entire program address space available to the 8051. It is most likely to be used in large programs.

Jumps

The ability of a program to respond quickly to changes in conditions depends largely upon the number and types of jump instructions available to the programmer. The 8051 has a rich set of jumps that can operate at the bit and byte levels. These jump opcodes are one reason the 8051 is such a powerful microcontroller.

Jumps operate by testing for conditions that are specified in the jump mnemonic. If the condition is true, then the jump is taken-that is, the program counter is altered to the address that is part of the jump instruction. If the condition is false, then the instruction immediately following the jump instruction is executed because the program counter is not altered. Keep in mind that the condition of true does not mean a binary I and that false does not mean binary 0. The condition specified by the mnemonic is either true or false.

Bit Jumps

Bit jumps all operate according to the status of the carry flag in the PSW or the status of any bit-addressable location. All bit jumps are relative to the program counter.

Jump instructions that test for bit conditions are shown in the following table:

Mnemonic

Operation

JC radd

Jump relative if the carry flag is set to 1

JNC radd

Jump relative if the carry flag is reset to 0

JB b,radd

Jump relative if addressable bit is set to 1

JNB b,radd

 Jump relative if addressable bit is reset to 0

JBC b.radd

Jump relative if addressable bit is set, and clear the addressable bit to 0

Note that no flags are affected unless the bit in JBC is a flag bit in the PSW. When the bit used in a JBC instruction is a port bit, the SFR latch for that port is read, tested, and altered.


The following program example makes use of bit jumps:

 

 

ADDRESS

 

MNEMONIC

COMMENT

LOOP:

MOV A,#l0h

 

; A = l0h

 

MOV R0, A

;R0 = l0h

ADDA:

ADD A.R0

 

;add R0  to A

 

JNC ADDA

;if the carry flag is 0. then no carry is

 

 

 ; true; jump to address ADDA; jump until A

 

 

 ;is F0h; the C flag is set to

 

 

;l on the next ADD and no carry is

 

 

 ; false: do the next instruction

 

MOV A,#l0h

;A = l0h; do program again using JNB

ADDR:

ADD A.R0

 ;add R0 to A (R0 already equals !0h)

 

JNB 0D7h.ADDR

;D7h is the bit address of the carry flag

 

JBC 0D7h,L00P

 ;the carry bit is l; the jump to L00P

 

 

;is taken. and the carry flag is cleared

 

 

;to 0

CAUTION

All jump addresses, such as ADDA and ADDR, must be within + 127d, -128d of the instruction following the jump opcode.

If the addressable bit is a flag bit and JBC is used, the flag bit will be cleared.

Do not use any label names that are also the names of registers in the 8051. These are called "reserved" words and will cause great agitation in the assembler.

Byte Jumps

Byte jumps-jump instructions that test bytes of data-behave as bit jumps. If the condi­tion that is tested is true, the jump is taken; if the condition is false.the instruction after the jump is executed. All byte jumps are relative to the program counter.

The following table lists examples of byte jumps:

Mnemonic

Operation

CJNE A,add,radd

Compare the contents of the A register with the contents of the direct address; if they are not equal, then jump to the relative address; set the carry flag to I if A is less than the contents of the direct address; otherwise, set the carry flag to 0

CJNE A,#n,radd

Compare the contents of the A register with the immediate number n; if they are not equal, then jump to the relative address; set the carry flag to I if A is less than the number; otherwise, set the carry flag to 0

CJNE Rn,#n,radd

Compare the contents of register Rn with the immediate number n; if they are not equal, then jump to the relative address; set the carry flag to I if Rn is less than the number; otherwise, set the carry flag to 0

CJNE @Rp,#n,radd

Compare the contents of the address contained in register Rp to the number n; if they are not equal, then jump to the relative address; set the carry flag to I if the contents of the address in Rp are less than the number; otherwise, set the carry flag to 0

DJNZ Rn.radd

Decrement register Rn by I and jump to the relative address if the result is not zero; no flags are affected

DJNZ add.radd

Decrement the direct address by I and jump to the relative address if the result is not O; no flags are affected unless the direct address is the PSW

JZ radd

Jump to the relative address if A is 0; the flags and the A register are not changed

JNZ radd

Jump to the relative address if A is not O; the flags and the A register are not changed


Note that if the direct address used in a DJNZ is a port, the port SFR is decremented and tested for 0.

Unconditional Jumps

Unconditional jumps do not test any bit or byte to determine whether the jump should be taken. The jump is always taken. All jump ranges are found in this group of jumps. and these are the only jumps that can jump to any location in memory.

The following table shows examples of unconditional jumps:

Mnemonic

Operation

 JMP@A+DPTR

Jump to the address formed by adding A to the DPTR; this is an unconditional jump and will always be done; the address can be anywhere in program memory; A, the DPTR, and the flags are unchanged

AJMP sadd

Jump to absolute short range address sadd; this is an unconditional jump and is always taken; no flags are affected

LJMP !add

Jump to absolute long range address ladd; this is an unconditional jump and is always taken; no flags are affected

SJMP radd

Jump to relative address radd; this is an unconditional jump and is always taken; no flags are affected

NOP

Do nothing and go to the next instruction; NOP (no operation) is used to waste time in a software timing loop; or to leave room in a program for later additions; no flags are affected

The following program example uses byte and unconditional jumps:

 

ADDRESS

MNEMONIC

COMMENT

 

.0RG 0100h

;begin program at 0100h

BGN:

MOV A,#30h

;A = 30h

 

MOV 50h,#00h

;RAM location 50h = 00h

AGN:

CJNE A,50h,AEQ

;compare A and the contents of 50h in RAM

 

SJMP NXT

;SJMP will be executed if (50h) = 30h

AEQ:

DJNZ 50h.AGN

;count RAM location 50h down until (50h)

 

NOP

;A; (50h) will reach 30h before 00h

NXT:

MOV R0,#0FFh

;R0 = FFh

DWN:

DJNZ R0.0WN

;count R0 to 00h; l00p here until done

 

MOV A.R0

;A = R0 = 00h

 

JNZ ABIG

;the jump will not be taken

 

JZ AZR0

;the jump will be taken

HERE:

NOP

;this address will not be reached

 

ORG l000h

;start this segment of program code at

 

 

;l000h

AZRO:

MOV A,#08h

;A = 0Bh (code at 1000.lh)

 

MOV DPTR, #l000h

;DPTR = l000h (code at 1002,3,4h)

 

JMP @A+DPTR

;jump to location 1008h (code at 1005h)

 

NOP

; ( code at 1006h)

 

NOP

; (code at 1007h)

ABIG:

AJMP AZRO

; (code at 1008h, all code on page 2)

 

CAUTION

DJNZ decrements first, then checks for 0. A location set to 00h and then decremented goes to FFh, then FEh, and so on, down to 00h.

CJNE does not change the contents of any register or RAM location. It can change the carry flag to 1 if the destination byte is less than the source byte.

There is no zero flag; the JZ and JNZ instructions check the contents of the A register for 0. JMP @A+ DPTR does not change A, DPTR, or any flags.

 

8051 Arithmetic Operations Subtraction, Multiplication, Division, Decimal Arithmetic ,Example Programs, AND Summary

 

Subtraction

Subtraction can be done by taking the 2’s complement of the number to be subtracted, the subtrahend, and adding it to another number, the minuend. The 8051, however, has com­mands to perform direct subtraction of two signed or unsigned numbers. Register A is the destination address for subtraction. All four addressing modes may be used for source addresses. The commands treat the carry flag as a borrow and always subtract the carry flag as part of the operation.

The following table lists the subtract mnemonics.

Mnemonic

Operation

 SUBB A,#n

Subtract immediate number n and the C flag from A; put the result in A

SUBB A,add

Subtract the contents of add and the C flag from A; put the result in A

 SUBB A,Rr

 Subtract Rr and the C flag from A; put the result in A

SUBB A,@Rp

Subtract the contents of the address in Rp and the C flag from A; put the result in A

Note that the C flag is set if a borrow is needed into bit 7 and reset otherwise. The AC flag is set if a borrow is needed into bit 3 and reset otherwise. The OV flag is set if there is a borrow into bit 7 and not bit 6 or if there is a borrow into bit 6 and not bit 7. As in the case for addition, the OV Flag is the XOR of the borrows into bit positions 7 and 6.

Unsigned and Signed Subtraction

Again, depending on what is needed, the programmer may choose to use bytes as signed or unsigned numbers. The carry flag is now thought of as a borrow flag to account for situations when a larger number is subtracted from a smaller number. The OV flag indi­cates results that must be adjusted whenever two numbers of unlike signs are subtracted and the result exceeds the planned signed magnitudes.

Unsigned Subtraction

Because the C flag is always subtracted from A along with the source byte, it must be set to 0 if the programmer does not want the flag included in the subtraction. If a multi-byte subtraction is done, the C flag is cleared for the first byte and then included in subsequent higher byte operations.

The result will be in true form, with no borrow if the source number is smaller than A, or in 2’s complement form, with a borrow if the source is larger than A. These are not signed numbers, as all eight bits are used for the magnitude. The range of numbers is from positive 255d (C = 0, A= FFh) to negative 255d (C = I, A= 0th).

The following example demonstrates subtraction of larger number from a smaller number:

015d = 0000111 lb

SUBB  100d = 01 01100100b

-085d  1 10101011b= 171d

The C flag is set to I, and the OV flag is set to 0. The 2’s complement of the result is 085d.

The reverse of the example yields the following result:

100d = 01100100b

015d = 00001111b

085d 01010101b = 085d

The C flag is set to 0, and the OV flag is set to 0. The magnitude of the result is in true form.

Signed Subtraction

As is the case for addition, two combinations of unsigned numbers are possible when sub­tracting: subtracting numbers of like and unlike signs. When numbers of like sign are subtracted, it is impossible for the result to exceed the positive or negative magnitude limits of +I 27d or – I 28d, so the magnitude and sign of the result do not need to be adjusted, as shown in the following example:

+ 100d = 01100100b    (Carry flag = 0 before SUBB)

SUBB +126d = 0111110b

-026d    11100110b = -026d

 

There is a borrow into bit positions 7 and 6; the carry flag is set to I, and the OV flag is cleared.


The following example demonstrates using two negative numbers:

-061d = 1100001 lb  (Carry flag = 0 before SUBB)

SUBB -116d = 11000011b

+055d 00110111b = +55d

There are no borrows into bit positions 6 or 7, so the OY and carry flags are cleared to zero.

An overflow is possible when subtracting numbers of opposite sign because the situa­tion becomes one of adding numbers of like signs, as can be demonstrated in the following example:

-099d = 10011101b   (Carry flag = 0 before SUBB)

SUBB + 100d = 01 01100100b

-199d 00111001b = +057d

Here, there is a borrow into bit position 6 but not into bit position 7; the OV flag is set to I, and the carry flag is cleared to 0. Because the OV flag is set to I, the result must be adjusted. In this case, the magnitude can be interpreted as the 2’s complement of 7 ld, the remainder after a carry out of l 28d from I 99d. The magnitude is correct, and the sign needs to be corrected to a 1 .

The following example shows a positive overflow:

+087d = 0101011 lb   (Carry flag = 0 before SUBB)

SUBB -052d = 11001100b

+139d    1000101 lb = -I 17d

There is a borrow from bit position 7, and no borrow from bit position 6; the OV flag and the carry flag are both set to I. Again the answer must be adjusted because the OV flag is set to one. The magnitude can be interpreted as a +01 Id, the remainder from a carry out of I 28d. The sign must be changed to a binary 0 and the OV condition dealt with.

The general rule is that if the OV flag is set to I, then complement the sign bit. The OV flag also signals that the result is greater than – I 28d or +I 27d.

Again, it must be emphasized: When an overflow occurs in a program, an error has been made in the estimation of the largest number needed to successfully operate the pro­gram. Theoretically, the program could resize every number used, but this extreme proce­dure would tend to hinder the performance of the microcontroller.

Note that for all the examples in this section, it is assumed that the carry flag = 0 before the SUBB. The carry flag must be 0 before any SUBB operation that depends upon C = 0 is done.

The following table lists examples of SUBB multiple-byte signed arithmetic operations:

Mnemonic

Operation

MOV 0D0h,#00h

 Carry flag= 0

MOV A,#3Ah

A= 3Ah

MOV 45h,#13h

Address  45h = 13h

 SUBB A,45h

A = 27h; C = 0, OV = 0

SUBB A,45h

 A = 14h; C = 0, OV = 0

 SUBB A,#80h

 A = 94h; C = 1 , OV = 1

 SUBB A,#22h

 A= 71h; C = 0, OV = 0

 SUBB A,#0FFh

 A = 72h; C = 1 , OV = 0

CAUTION

Remember to set the carry flag to zero if it is not to be included as part of the subtraction operation.

 Multiplication and Division

The 8051 has the capability to perform 8-bit integer multiplication and division using the A and B registers. Register B is used solely for these operations and has no other use except as a location in the SFR space of RAM that could be used to hold data. The A register holds one byte of data before a multiply or divide operation, and one of the result bytes after a multiply or divide operation.

Multiplication and division treat the numbers in registers A and B as unsigned. The programmer must devise ways to handle signed numbers.

Multiplication

Multiplication operations use registers A and B as both source and destination addresses for the operation. The unsigned number in register A is multiplied by the unsigned number in register B, as indicated in the following table:

Mnemonic

Operation

MULAB

Multiply A by B: put the low-order byte of the product in A, put the high-order byte in B

The OV flag will be set if Ax B > FFh. Setting the OV flag does not mean that an error has occurred. Rather, it signals that the number is larger than eight bits, and the program­mer needs to inspect register B for the high-order byte of the multiplication operation. The carry flag is always cleared to 0.

The largest possible product is FEO I h when both A and B contain FFh. Register A contains 0lh and register B contains FEh after multiplication of FFh by FFh. The OV flag is set to 1 to signal that register B contains the high-order byte of the product; the carry flag is 0.

The following table gives examples of MUL multiple-byte arithmetic operations:

Mnemonic

Operation

MOV A,#7Bh

A= 7Bh

 MOV OFOh.#02h

 B = 02h

MULAB

A = 00h and  B = F6h: OV Flag = 0

MOV A,#0FEh

A = FEh

 MULAB

A = 14h and B = F4h: OV Flag =1

CAUTION

Note there is no comma between A and 8 in the MUL mnemonic.

Division

Division operations use registers A and B as both source and destination addresses for the operation. The unsigned number in register A is divided by the unsigned number in regis­ter B, as indicated in the following table:


Mnemonic

Operation

DIV AB

Divide A by B; put the integer part of quotient in register A and the integer part of the remainder in B

The OV flag is cleared to 0 unless B holds 00h before the DIV. Then the 0V flag is set to I to show division by 0. The contents of A and B, when division by 0 is attempted, are undefined. The carry flag is always reset.

Division always results in integer quotients and remainders, as shown in the following example: clip_image002[4]

When done in hex:

clip_image004[3]

The following table lists examples of DIV multiple-byte arithmetic operations:

Mnemonic

Operation

MOV A,#0FFh

A = FFh (255d)

MOV 0F0h,#2Ch

B = 2C (44d)

DIV AB

A = 05h and B = 23h [255d = (5 x 44) + 35]

DIV AB

A = 00h and B = 05h (05d = (0 x 35) + 5]

DIV AB

A = 00h and B = 00h [00d = (0 x 5) + 0J

DIV AB

A = ?? and B = ??; OV flag is set to one

CAUTION

The original contents of B (the divisor) are lost.

Note there is no comma between A and B in the DIV mnemonic.

Decimal Arithmetic

Most 8051 applications involve adding intelligence to machines where the hexadecimal numbering system works naturally. There are instances, however, when the application involves interacting with humans, who insist on using the decimal number system. In such cases, it may be more convenient for the programmer to use the decimal number system to represent all numbers in the program.

Four bits are required to represent the decimal numbers from 0 to 9 (0000 to 1001) and the numbers are often called Binary coded decimal (BCD) numbers. Two of these BCD numbers can then be packed into a single byte of data.

The 8051 does all arithmetic operations in pure binary. When BCD numbers are being used the result will often be a non-BCD number, as shown in the following example:

clip_image006[3]

Note that to adjust the answer, an 06d needs to be added to the result.


The opcode that adjusts the result of BCD addition is the decimal adjust A for addi­tion (DA A) command, as shown in the following table:

Mnemonic

Operation

DA A

Adjust the sum of two packed BCD numbers found in A register; leave the adjusted number in A.

The C flag is set to I if the adjusted number exceeds 99BCD and set to 0 otherwise. The DA A instruction makes use of the AC flag and the binary sums of the individual binary nibbles to adjust the answer to BCD. The AC flag has no other use to the programmer and no instructions-other than a MOV or a direct bit operation to the PSW-affect the AC flag.

It is important to remember that the DA A instruction assumes the added numbers were in BCD before the addition was done. Adding hexadecimal numbers and then using DA A will not convert the sum to BCD.

The DA A opcode only works when used with ADD or ADDC opcodes and does not give correct adjustments for SUBB, MUL or DIV operations. The programmer might best consider the ADD or ADDC and DA A as a single instruction and use the pair automat­ically when doing BCD addition in the 8051.

The following table gives examples of BCD multiple-byte arithmetic operations:

Mnemonic

Operation

MOV A,#42h

A= 42BCD

 ADD A,#13h

 A= 55h; C = 0

 DA A

A= 55h; C = 0

ADD A,#17h

 A= 6Ch; C = 0

 DA A

A = 72BCD; C = 0

ADDC A,#34h

A= A6h; C = 0

DA A

A = 06BCD; C =1

ADDC A,#1 lh

A = l SBCD; C = 0

DA A

 A = !&BCD; C = 0

CAUTION

All numbers used must be in BCD form before addition. Only ADD and ADDC are adjusted to BCD by DA A.

Example Programs

The challenge of the programs presented in this section is writing them using only opcodes that have been covered to this point in the book. Experienced programmers may long for some of the opcodes to be covered in Chapter 6, but as we shall see, programs can be written without them.

EXAMPLE PROBLEM 5.1

Add the unsigned numbers found in internal RAM locations 25h, 26h, and 27h together and put the result in RAM locations 30h (MSB) and 3lh (LSB).

• Thoughts on the Problem The largest number possible is FFh + FFh = 01 FEh + FFh = 02FDh, so that two bytes will hold the largest possible number. The MSB will be set to 0 and any carry bit added to it for each byte addition.


To solve this problem, use an ADD instruction for each addition and an ADDC to the MSB for each carry which might be generated. The first ADD will adjust any carry flag which exists before the program starts.

The complete program is shown in the following table:

Mnemonic

Operation

 MOV 3Jh,#00h

Clear the MSB of the result to 0

MOV A,25h

Get the first byte to be added from location 25h

ADD A,26h

Add the second byte found in RAM location 26h

MOV R0,A

 Save the sum of the first two bytes in RO

MOV A,#00h

Clear A to 00

ADDC A,3lh

Add the carry to the MSB; carry = 0 after this operation

MOV 3lh,A

Store MSB

MOV A,R0

Get partial sum back

ADD A,27h

 Form final LSB sum

 MOV 39h,A

Store LSB

MOV A,#00h

Clear A for MSB addition

ADDC A,31h

 Form final MSB

 MOV 3lh,A

Store final MSB

COMMENT

Notice how awkward it becomes to have to use the A register for all operations. Jump instruc­tions, which will be covered in Chapter 6, require less use of A.

EXAMPLE PROBLEM 5.2

Repeat problem 5.1 using BCD numbers.

• Thoughts on the Problem The numbers in the RAM locations must be in BCD before the problem begins. The largest number possible is 99d + 99d = I 98d + 99d = 297d, so that up to two carries can be added to the MSB.

The solution to this problem is identical to that for unsigned numbers, except a DA A must be added after each ADD instruction. If more bytes were added so that the MSB could exceed 09d, then a DA A would also be necessary after the ADDC opcodes.

The complete program is shown in the following table:

Mnemonic

Operation

MOV 3lh,#00h

Clear the MSB of the result to 0

 MOV A,25h

Get the first byte to be added from location 25h

ADD A,26h

Add the second byte found in RAM location 26h

 DAA

Adjust the answer to BCD form

MOV RO,A

Save the sum of the first two bytes in RO

MOV A,#OOh

 Clear A to 00

ADDC A,3lh

Add the carry to the MSB; carry = 0 after this operation

MOV 31h,A

Store MSB

MOV A,RO

Get partial sum back

 ADD A,27h

Form final LSB sum

DAA

Adjust the final sum to BCD

MOV 30h,A

Store LSB

MOV A,#Ooh

Clear A for MSB addition

 ADDC A,3lh

Form final MSB

 MOV 31h,A

Store final MSB

COMMENT

When using BCD numbers, DA A can best be thought of as an integral part of the ADD instructions.

EXAMPLE PROBLEM 5.3

Multiply the unsigned number in register R3 by the unsigned number on port 2 and put the result in external RAM locations 10h (MSB) and 11 h (LSB).

• Thoughts on the Problem The MUL instruction uses the A and B registers; the prob­lem consists of MOV es to A and B followed by MOVes to the external RAM. The com­plete program is shown in the following table:

Mnemonic

Operation

MOV A,0A0h

Move the port 2 pin data to A

MOV 0F0h,R3

Move the data in R3 to the B register

 MULAB

Multiply the data; A has the low order result byte

MOV R0.#1 lh

 Set RO to point to external RAM location l lh

MOV@R0,A

Store the LSB in external RAM

DEC R0

Decrement R0 to point to !0h

MOV A,0F0h

Move B to A

MOV@R0,A

Store the MSB in external RAM

coMMENT

Again we see the bottleneck created by having to use the A register for all external data transfers.

More advanced programs which do signed math operations and multi-byte multiplication and division will have to wait for the development of Jump instructions in Chapter 6.

Summary OF 8051 Arithmetic Operations

The 8051 can perform all four arithmetic operations: addition, subtraction. multiplication, and division. Signed and unsigned numbers may be used in addition and subtraction; an 0Y flag is provided to signal programmer errors in estimating signed number magnitudes needed and to adjust signed number results. Multiplication and division use unsigned numbers. BCD arithmetic may be done using the DA A and ADD or ADDC instructions.

The following table lists the arithmetic mnemonics:

Mnemonic

Operation

 ADD A. source

Add the source byte to A; put the result in A and adjust the C and OY flags

ADDC A, source

Add the source byte and the carry to A; put the result in A and adjust the C and OV flags

DA A

Adjust the binary result of adding two BCD numbers in the A register to BCD and adjust the carry flag

DEC source

Subtract a I from the source; roll from 00h to FFh

DIV AB

Divide the byte in A by the byte in B; put the quotient in A and the remainder in B; set the OV flag to I if B = 00h before the division

INC source

Add a 1 to the source; roll from FFh or FFFFh to 00h or 0000h

 MULAB

Multiply the bytes in A and B; put the high-order byte of the result in B, the low-order byte in A; set the OV flag to 1 if the result is > FFh

SUBB A. source

Subtract the source byte and the carry from A; put the result in A and adjust the C and OV flags


Problems

Write programs that perform the tasks listed using only opcodes that have been discussed in this and previous chapters. Use comments on each line of code and try to use as few lines as possible. All numbers may be considered to be unsigned numbers.

l. Add the bytes in RAM locations 34h and 35h: put the result in register R5 (LSB) and R6 (MSB).

2- Add the bytes in registers R3 and R4; put the result in RAM location 4Ah (LSB) and 4Bh (MSB).

3. Add the number 84h to RAM locations l 7h and 18h.

4. Add the byte in external RAM location 02CDh to internal RAM location l9h; put the result into external RAM location 0000h (LSB) and 00C1h (MSB).

5-8. Repeat Problems 1-4, assuming the numbers are in BCD format.

9. Subtract the contents of R2 from the number F3h; put the result in external RAM loca­tion 028Bh.

10. Subtract the contents of R l from R0; put the result in R7.

11. Subtract the contents of RAM location 13h from RAM location 2Bh: put the result in RAM location 3Ch.

12. Subtract the contents of TH0 from TH I: put the result in TL0.

13. Increment the contents of RAM location 13h. 14h. and 15h using indirect addressing only.

14. Increment TLI by I Oh.

15. Increment external RAM locations 0100h and 0200h.

16. Add a l to every external RAM address from 00h to 06h.

17. Add a l to every external RAM address from 0100h to 0106h.

18. Decrement TL0. THO, TL1, and TH l.

19. Decrement external RAM locations 0l23h and 01 BDh.

20. Decrement external RAM locations 45h and 46h.

21. Multiply the data in RAM location 22h by the data in RAM location l Sh; put the result in RAM locations 19h (low byte). and lAh (high byte).

22. Square the contents of R5; put the result in R0 (high byte), and RI (low byte).

23. Divide the data in RAM location 3Eh by the number l 2h; put the quotient in R4 and the remainder in R5.

24. Divide the number in RAM location 1 Sh by the data in RAM location 16h; put the result in external RAM location 7Ch.

25. Divide the data in RAM location 13h by the data in RAM location 14h, then restore the original data in l3h by multiplying the answer by the data in 14h.

 

8051 Arithmetic Operations Flags, Incrementing and Decrementing,AND Addition

Introduction

Applications of microcontrollers often involve performing mathematical calculations on data in order to alter program flow and modify program actions. A microcontroller is not designed to be a "number cruncher," as is a general-purpose computer. The domain of the microcontroller is that of controlling events as they change (real-time control). A suffi­cient number of mathematical opcodes must be provided, however, so that calculations associated with the control of simple processes can be done, in real time, as the controlled system operates. When faced with a control problem, the programmer must know whether the 8051 has sufficient capability to expeditiously handle the required data manipulation. If it does not, a higher performance model must be chosen.

The 24 arithmetic opcodes are grouped into the following types:

Mnemonic

Operation

INC destination

Increment destination by 1

 DEC destination

 Decrement destination by 1

ADDI ADDC destination ,source

Add source to destination without/with carry (C) flag

SUBB destination.source

Subtract, with carry, source from destination

MUL   AB

 Multiply the contents of registers A and B

DIV AB

Divide the contents of register A by the contents of register B

DA A

Decimal Adjust the A register

The addressing modes for the destination and source are the same as those discussed in Chapter 3: immediate, register, direct, and indirect.

Flags

A key part of performing arithmetic operations is the ability to store certain results of those operations that affect the way in which the program operates. For example, adding together two one-byte numbers results in a one-byte partial sum, because the 8051 is and eight-bit machine. But it is possible to get a 9-bit result when adding two 8-bit numbers. The ninth bit must be stored also, so the need for a one-bit register, or carry Hag in this case, is identified. The program will then have to deal with the ninth bit, perhaps by adding it to a higher order byte in a multiple-byte addition scheme. Similar actions may have to be taken when a larger byte is subtracted from a smaller one. In this case, a borrow is necessary and must be dealt with by the program.

The 8051 has several dedicated latches, or Hags, that store results of arithmetic opera­tions. Opcodes covered in Chapter 6 are available to alter program flow based upon the state of the Hags. Not all instructions change the Hags. but many a programming error has been made by a forgetful programmer who overlooked an instruction that does change a Hag.

The 8051 has four arithmetic Hags: the carry (C), auxiliary carry (AC), overflow (OV), and parity (P).

Instructions Affecting Flags

The C. AC, and OV Hags are arithmetic Hags. They are set to I or cleared to 0 automat­ically, depending upon the outcomes of the following instructions. The following instruc­tion set includes all instructions that modify the flags and is not confined to arithmetic instructions:

INSTRUCTION MNEMONIC

FLAGS AFFECTED

ADD

C       AC         ov

ADDC

C      AC         ov

ANL C,direct

C

CJNE

C

CLR C

C=0

CPL C

C=C

DA A

C

DIV

C=O     OV

MOV C,direct

C

MUL

C=O     OV

ORL C,direct

C

RLC

C

RRC

C

SETB C

C = 1

SUBB

C         AC       OV

One should remember, however, that the flags are all stored in the PSW. Any instruc­tion that can modify a bit or a byte in that register (MOV. SETB, XCH, etc.) changes the Hags. This type of change takes conscious effort on the part of the programmer.


A Hag may be used for more than one type of result. For example, the C flag indicates a carry out of the lower byte position during addition and indicates a borrow during sub­traction. The instruction that last affects a flag determines the use of that flag.

The parity flag is affected by every instruction executed. The P flag will be set to a I if the number of I’s in the A register is odd and will be set to 0 if the number of I’s is even. All O’s in A yield a I’s count of 0, which is considered to be even. Parity check is an elementary error-checking method and is particularly valuable when checking data re­ceived via the serial port.

Incrementing and Decrementing

The simplest arithmetic operations involve adding or subtracting a binary I and a number. These simple operations become very powerful when coupled with the ability to repeat the operation-that is, to "INCrement" or "OECrement" -until a desired result is reached.’ Register, Direct, and Indirect addresses may be INCremented or DECremented. No math flags (C, AC, OV) are affected.

The following table lists the increment and decrement mnemonics.

Mnemonic

Operation

 INC A

Add a one to the A register

INC Rr

 Add a one to register Rr

INC add

Add a one to the direct address

INC@Rp

Add a one to the contents of the address in Rp

INC DPTR

 Add a one to the lti-bit DPTR

DEC A

Subtract a one from register A

DECRr

Subtract a one from register Rr

DEC add

Subtract a one from the contents of the direct address

DEC@Rp

Subtract a one from the contents of the address in register Rp

Note that increment and decrement instructions that operate on a port direct address alter the latch for that port.

The following table shows examples of increment and decrement arithmetic operations:

Mnemonic

Operation

 MOV A,#3Ah

A= 3Ah

 DEC A

 A= 39h

MOV R0,#15h

 R0= 15h

 MOV 15h,#12h

Internal RAM address 15h = 12h

INC@RO

 Internal RAM address 15h = 13h

DEC I5h

Internal RAM address 15h = 12h

INC RO

R0= 16h

MOV 16h,A

Internal RAM address 16h = 39h

INC@RO

Internal RAM address 16h = 3Ah

MOV DPTR,#12

 DPTR = 12FFh

FFh INC DPTR

DPTR = 1300h

DEC 83h

DPTR = 1200h (SFR 83h is the DPH byte)

 

CAUTION

Remember: No math flags are affected.

All 8-bit address contents overflow from Ffh to 00h.

DPTR is 16 bits; DPTR overflows from FFFFh to 0000h.

The 8-bit address contents underflow from 00h to FFh.

 There is no DEC DPTR to match the INC DPTR.

Addition

All addition is done with the A register as the destination of the result. All addressing modes may be used for the source: an immediate number, a register, a direct address, and an indirect address. Some instructions include the carry flag as an additional source of a single bit that is included in the operation at the least significant bit position.

The following table lists the addition mnemonics.

Mnemonic

Operation

ADD A.#n

Add A and the immediate number n; put the sum in A

ADD A,Rr

Add A and register Rr; put the sum in A

 ADD A,add

Add A and the address contents; put the sum in A

ADD A,@Rp

Add A and the contents of the address in Rp; put the sum in A

 

Note that the C flag is set to I if there is a carry out of bit position 7; it is cleared to 0 otherwise. The AC flag is set to 1 if there is a carry out of bit position 3; it is cleared otherwise. The OV flag is set to I if there is a carry out of bit position 7, but not bit position 6 or if there is a carry out of bit position 6 but not bit position 7, which may be expressed as the logical operation

OV = C7 XOR C6

Unsigned and Signed Addition

The programmer may decide that the numbers used in the program are to be unsigned numbers-that is, numbers that are 8-bit positive binary numbers ranging from 00h to FFh. Alternatively, the programmer may need to use both positive and negative signed numbers.

Signed numbers use bit 7 as a sign bit in the most significant byte (MSB) of the group of bytes chosen by the programmer to. represent the largest number to be needed by the program. Bits 0 to 6 of the MSB, and any other bytes, express the magnitude of the num­ber. Signed numbers use a I in bit position 7 of the MSB as a negative sign and a 0 as a positive sign. Further, all negative numbers are not in true form, but are in 2’s comple­ment form. When doing signed arithmetic. the programmer must know how large the largest number is to be-that is, how many bytes are needed for each number.

In signed form, a single byte number may range in size from 10000000b, which is – I 28d to 01111111 b, which is +I 27d. The number 00000000b is 000d and has a posi­tive sign, so there are 128d negative numbers and 128d positive numbers. The C and OV flags have been included in the 8051 to enable the programmer to use either numbering scheme.

Adding or subtracting unsigned numbers may generate a carry flag when the sum ex­ceeds FFh or a borrow flag when the minuend is less than the subtrahend. The OV flag is not used for unsigned addition and subtraction. Adding or subtracting signed numbers can

lead to carries and borrows in a similar manner, and to overflow conditions due to the actions of the sign bits.

Unsigned Addition

Unsigned numbers make use of the carry flag to detect when the result of an ADD opera­tion is a number larger than Ffb. If the carry is set to one after an ADD, then the carry can be added to a higher order byte so that the sum is not lost. For instance,

95d = 0101111 lb

189d = 10111101b

284d 1 000111 00b = 284d

The C flag is set to I to account for the carry out from the sum. The program could add the carry flag to another byte that forms the second byte of a larger number.

Signed Addition

Signed numbers may be added two ways: addition of like signed numbers and addition of unlike signed numbers. If unlike signed numbers are added, then it is not possible for the result to be larger than -128d or + 127d, and the sign of the result will always be correct. For example,

-001d 11111111b

+027d = 0001 1011b

+026d    0001 1010b = +026d

Here, there is a carry from bit 7 so the carry flag is I. There is also a carry from bit 6, and the OV flag is 0. For this condition, no action need be taken by the program to correct the sum.

If positive numbers are added, there is the possibility that the sum will exceed +I 27d, as demonstrated in the following example:

+ 100d = 01100100b

+050d = 001 10010b

+ 150d 10010110b = -106d

Ignoring the sign of the result, the magnitude is seen to be +22d which would be correct if we had some way of accounting for the + 128d, which, unfortunately, is larger than a single byte can hold. There is no carry from bit 7 and the carry flag is O; there is a carry from bit 6 so the OV flag is 1.

An example of adding two positive numbers that do not exceed the positive limit is:

+045d 00101101b

+075d = 01001011lb

+120d 01111000b = 120d

Note that there are no carries from bits 6 or 7 of the sum; the carry and OV flags are both 0.

The result of adding two negative numbers together for a sum that does not exceed the negative limit is shown in this example:

-030d = 11100010b

-050d = 11001110b

-080d  10110000b = -080d


Here, there is a carry from bit 7 and the carry flag is I; there is a carry from bit 6 and the OV flag is 0. These are the same flags as the case for adding unlike numbers; no correc­tions are needed for the sum.

When adding two negative numbers whose sum does exceed – l 28d, we have

-070d = 10111010b

-070d = 10111010b

-140d 01110100b = +116d

Or, the magnitude can be interpreted as – l 2d, which is the remainder after a carry out of – l 28d. In this example, there is a carry from bit position 7, and no carry from bit position 6, so the carry and the OV flags are set to I. The magnitude of the sum is correct; the sign bit must be changed to a I.

From these examples the programming actions needed for the C and OV flags are as follows:

FLAGS

ACTION

C

OV

0

0

None

0

1

Complement the sign

1

0

 None

1

1

Complement the sign

A general rule is that if the OV flag is set, then complement the sign. The OV flag also signals that the sum exceeds the largest positive or negative numbers thought to be needed in the program.

Multiple-Byte Signed Arithmetic

The nature of multiple-byte arithmetic for signed and unsigned numbers is distinctly different from single byte arithmetic. Using more than one byte in unsigned arithmetic means that carries or borrows are propagated from low-order to high-order bytes by the simple technique of adding the carry to the next highest byte for addition and subtracting the borrow from the next highest byte for subtraction.

Signed numbers appear to behave like unsigned numbers until the last byte is reached.

Foi a signed number, the seventh bit of the highest byte is the sign; if the sign is negative, then the entire number is in 2’s complement form.

For example, using a two-byte signed number, we have the following examples:clip_image002[4]

Note that the lowest byte of the numbers 00000 and – 32768d are exactly alike, as are the lowest bytes for+ 32767d and -00001d.

For multi-byte signed number arithmetic, then, the lower bytes are treated as un­signed numbers. All checks for overflow are done only for the highest order byte that contains the sign. An overflow at the highest order byte is not usually recoverable. The programmer has made a mistake and probably has made no provisions for a number larger than planned. Some error acknowledgment procedure, or user notification, should be in­cluded in the program if this type of mistake is a possibility.


The preceding examples show the need to add the carry Hag to higher order bytes in signed and unsigned addition operations. Opcodes that accomplish this task are similar to the ADD mnemonics: A C is appended to show that the carry bit is added to the sum in bit position 0.

The following table lists the add with carry mnemonics:

Mnemonic

Operation

ADDC A,#n

Add the contents of A, the immediate number n, and the C Hag; put the sum in A

ADDC A,add

Add the contents of A, the direct address contents, and the C Hag; put the sum in A

ADDC A,Rr A

Add the contents of A, register Rr, and the C Hag; put the sum in A

DDC A,@Rp

Add the contents of A, the contents of the indirect address in Rp, and the C flag; put the sum in A

Note that the C, AC, and OY flags behave exactly as they do for the ADD commands.

The following table shows examples of ADD and ADDC multiple-byte signed arith­metic operations:

Mnemonic

Operation

MOV A,#1Ch

A= 1Ch

MOV R5,#0Alh

 R5 = A1h

ADD A,R5

A = BDh; C = 0, OV = 0

ADD A,R5

A = 5Eh; C = 1, OV = 1

ADDC A,#10h

A = 6Fh; C = 0, OV = 0

ADDC A,#IOh

A = 7Fh; C = 0, OV = 0

CAUTION

ADDC is normally used to add a carry after the LSB addition in a multi-byte process. ADD is normally used for the LSB addition.

 

8051 Logical Operations Rotate and Swap Operations Example Programs and Summary

Rotate and Swap Operations

The ability to rotate data is useful for inspecting bits of a byte without using individual bit opcodes. The A register can be rotated one bit position to the left or right with or without including the C flag in the rotation. If the C flag is not included, then the rotation involves the eight bits of the A register. If the C flag is included, then nine bits are involved in the rotation. Including the C flag enables the programmer to construct rotate operations in­volving any number of bytes.

The SWAP instruction can be thought of as a rotation of nibbles in the A register.

Figure 4.2 diagrams the rotate and swap operations. which are given in the following table:

Mnemonic

 Operation

RL A

Rotate the A register one bit position to the left; bit A0 to bit A I, A I to A2. A2 to A3. A3 to A4, A4 to A5, A5 to A6. A6 to A 7, and A 7 to A0

RLC A

Rotate the A register and the carry flag. as a ninth bit, one bit position to the left; bit A0 to bit Al, Al to A2, A2 to A3, A3 to A4, A4 to A5. A5 to A6, A6 to A 7, A 7 to the carry flag, and the carry flag to A0

RR A

Rotate the A register one bit position to the right; bit A0 to bit A 7, A6 to A5, A5 to A4, A4 to A3, A3 to A2. A2 to Al, and At to A0

RRC A

 Rotate the A register and the carry flag, as a ninth bit, one bit position to the right; bit A0 to the carry flag. carry flag to A 7, A 7 to A6, A6 to A5, A5 to A4, A4 to A3, A3 to A2, A2 to Al, and Al to A0

SWAP A

 Interchange the nibbles of register A; put the high nibble in the low nibble position and the low nibble in the high nibble position

Note that no flags. other than the carry flag in RRC and RLC, are affected. If the carry is used as part of a rotate instruction, the state of the carry flag should be known before the rotate is done.

 

clip_image002[4]


The following table shows examples of rotate and swap operations:

Mnemonic

Operation

OY A,#OA5h

A = I0l00I0lb = A5h

RR A

 A = I I0I00I0b = D2h

RR A

A = 0l I0l00lb = 69h

RR A

A = I0I l0I00b = B4h

RR A

 A = 0I0l I0I0b = 5Ah

SWAP A

A= I0I00I0lb = A5h

CLR  C

C = 0; A = I0I00I0lb = A5h

RRC  A

C = I; A= 0I0I00I0b = 52h

RRC A

 C = 0; A = l0I0J00lb = A9h

RL A

 A= 0I0I00llb = 53h

RL A

A = I0I00l I0b = A6h

SWAP A

C = 0; A = 0l 101010b = 6Ah

RLC A

 C = 0; A = 1 I0I0l00b = D4h

RLC A

C = l; A= I0I0l000b = A8h

 SWAP A

 C = l; A= l000I0I0b = 8Ah

 

CAUTION

Know the state of the carry flag when using RRC or RRL.

 Rotation and swap operations are limited to the A register.

Example Programs on 8051 Logical Operations

The programs in this section are written using only opcodes covered to this point in the text. The challenge is to minimize the number of lines of code.

Ø  EXAMPLE PROBLEM 4. 1

Double the number in register R2, and put the result in registers R3 (high byte) and R4 (low byte).

Thoughts on the Problem The largest number in R2 is FFh; the largest result is 1 FEh. There are at least three ways to solve this problem: Use the MUL instruction (multiply, covered in Chapter 5). add R2 to itself, or shift R2 left one time. The solution that shifts R2 left is as follows:

Mnemonic

Operation

 MOY R3,#00h

Clear R3 to receive high byte

 CLRC

Clear the carry to receive high bit of 2 x R2

MOY A.R2

 Get R2 to A

RLC A

Rotate left, which doubles the number in A

MOY R4,A

Put low byte of result in R4

CLR A

Clear A to receive carry

RLC A

 

MOY R3.A

 

The carry bit is now bit 0 of A

 

Transfer any carry bit to R3

 

COMMENT

Note how the carry flag has to be cleared to a known state before being used in a rotate operation.

Ø  EXAMPLE PROBLEM 4.2

OR the contents of pons I and 2; put the result in external RAM location 0I00h.

·         Thoughts on the Problem The ports should be input ports for this problem to make any physical sense; otherwise, we would not know whether to use the pin data or the port SFR latch data.

The solution is as follows:

Mnemonic

Operation

 MOY A,90h

Copy the pin data from port 1 to A

ORL A,0A0h

OR the contents of A with port 2; results in A

MOY DPTR,#0100h

 Set the DPTR to point to external RAM address

 MOYX @DPTR.A

Store the result

COMMENT

Any time the port is the source of data, the pin levels are read; when the port is the destination, the latch is written. If the port is both source and destination (read-modify-write instruc­tions), then the latch is used.

Ø  EXAMPLE PROBLEM 4.3

Find a number that, when X0 Red to the A register, results in the number 3Fh in A.

·         Thoughts on the Problem Any number can be in A, so we will work backwards:

3Fh =A XOR N

A XOR 3Fh = A XOR A XOR N = N

The solution is as follows:

Mnemonic

Operation

 MOV R0,A

 Save A in R0

 XOR A,#3Fh

XOR A and 3Fh; forming N

XOR A,R0

 XOR A and N yielding 3Fh

COMMENT

Does this program work? Let’s try several A’s and see.

A= FFh

A XOR 3Fh = C0h

C0h XOR FFh = 3Fh

A= 00h

A XOR 3Fh = 3Fh

3Fh XOR 00h = 3Fh

A= 5Ah

A XOR 3Fh = 65h

65h XOR 5Ah = 3Fh

Summary

Boolean logic, rotate, and swap instructions are covered in this chapter. Byte-level opera­tions involve each individual bit of a source byte operating on the same bit position in the destination byte; the results are put in the destination, while the source is not changed:

ANL destination. Source

ORL destination. Source

XRL destination. Source

CLR A

CPL A

RR A

RLA

RRCA

RLC A

SWAP A

Bit-level operations involve individual bits found in one area of internal RAM and certain SFRs that may be addressed both by the assigned direct-byte address and eight individual bit addresses. The following Boolean logical operations may be done on each of these addressable bits:

ANLbit

ORL bit

CLR bit

CPL bit

SETB bit

MOY destination bit, source bit

Problems

Write programs that perform the tasks listed using only opcodes that have been discussed in this and previous chapters. Write comments for each line of code and try to use as few lines as possible.

1. Set Port 0. bits 1,3,5, and 7. to one: set the rest to zero.

2. Clear bit 3 of RAM location 22h without affecting any other bit.

3. Invert the data on the port 0 pins and write the data to port I.

4. Swap the nibbles of R0 and RI so that the low nibble of R0 swaps with the high nibble of RI and the high nibble of R0 swaps with the low nibble of R l .

5. Complement the lower nibble of RAM location 2Ah.

6. Make the low nibble of RS the complement of the high nibble of R6.

7. Make the high nibble of RS the complement of the low nibble of R6.

8. Move bit 6 of R0 to bit 3 of port 3.

9. Move bit 4 of RAM location 30h to bit 2 of A. to. XOR a number with whatever is in A so that the result is FFh.

11. Store the most significant nibble of A in both nibbles of register RS: for example, if A = B6h. then RS = BBh.

12. Store the least significant nibble of A in both nibbles of RAM address 3Ch; for example. if A = 36h. then 3Ch = 66h.

13. Set the carry flag to one if the number in A is even; set the carry flag to zero if the number in A is odd.

14. Treat registers R0 and RI as 16-bit registers, and rotate them one place to the left: bit 7 of R0 becomes bit 0 of RI. bit 7 of RI becomes bit 0 of R0, and so on.

15. Repeat Problem 14 but rotate the registers one place to the right.

16. Rotate the DPTR one place to the left; bit IS becomes bit 0.

17. Repeat problem 16 but rotate the DPTR one place to the right.

18. Shift register B one place to the left: bit 0 becomes a zero. bit 6 becomes bit 7. and so on. Bit 7 is lost.

 

8051 Logical Operations Byte-Level Logical Operations and Bit-Level Logical Operations

Introduction

8051 Logical Operations

One application area the 8051 is designed to fill is that of machine control. A large part of machine control concerns sensing the on-off states of external switches, making deci­sions based on the switch states. and then turning external circuits on or off.

Single point sensing and control implies a need for byte and bit opcodes that operate on data using Boolean operators. All 8051 RAM areas, both data and SFRs, may be ma­nipulated using byte opcodes. Many of the SFRs, and a unique internal RAM area that is bit addressable, may be operated upon at the individual bit level. Bit operators are notably efficient when speed of response is needed. Bit operators yield compact program code that enhances program execution speed.

The two data levels, byte or bit, at which the Boolean instructions operate are shown in the following table:

BOOLEAN OPERATOR

8051 MNEMONIC

AND

ANL (AND logical)

OR

ORL (OR logical)

XOR

XRL (exclusive OR logical)

NOT

CPL (complement)

There are also rotate opcodes that operate only on a byte, or a byte and the carry flag, to permit limited 8- and 9-bit shift-register operations. The following table shows the rotate opcodes:

Mnemonic

Operation

RL

Rotate a byte to the left; the Most Significant Bit (MSB) becomes the Least Significant Bit (LSB)

RLC

Rotate a byte and the carry bit left; the carry becomes the LSB, the MSB becomes the carry

RR

Rotate a byte to the right; the LSB becomes the MSB

RRC

Rotate a byte and the carry to the right; the LSB becomes the carry, and the carry the MSB

SWAP

Exchange the low and high nibbles in a byte

Byte-Level Logical Operations

The byte-level logical operations use all four addressing modes for the source of a data byte. The A register or a direct address in internal RAM is the destination of the logical operation result.

Keep in mind that all such operations are done using each individual bit of the desti­nation and source bytes. These operations, called byte-level Boolean operations because tlfe entire byte is affected, are listed in the following table:

Mnemonic

Operation

ANL A,#n

AND each bit of A with the same bit of immediate number n; put the results in A

ANL. A.add

AND each bit of A with the same bit of the direct RAM address; put the results in A

ANLA,Rr

AND each bit of A with the same bit of register Rr; put the results in A AND each bit of A with the same bit of the contents of the RAM address contained in Rp; put the results in A

ANL A,@Rp

AND each bit of A with the direct RAM address; put the results in the direct RAM address

ANL add.A

AND each bit of the RAM address with the same bit in the number n; put the result in the RAM address

ANL add,#n

OR each bit of A with the same bit of n; put the results in A

ORL A,#n

OR each bit of A with the same bit of the direct RAM address; put the results in A

ORL A,add

OR each bit of A with the same bit of register Rr; put the results in A OR each bit of A with the same bit of the contents of the RAM address contained in Rp; put the results in A

ORL A,Rr

OR each bit of A with the direct RAM address; put the results in the direct RAM address

ORL A,@Rp

OR each bit of the RAM address with the same bit in the number n; put the result in the RAM address

ORL add.A

XOR each bit of A with the same bit of n; put the results in A

ORL add,#n

XOR each bit of A with the same bit of the direct RAM address; put the results in A

XRL A,#n

XOR each bit of A with the same bit of register Rr; put the results in A XOR each bit of A with the same bit of the contents of the RAM address contained in Rp; put the results in A

XRL A,add

XOR each bit of A with the direct RAM address; put the results in the direct RAM address

XRL A,Rr

Operation

XRL A,@Rp

AND each bit of A with the same bit of immediate number n; put the results in A

XRL add.A

AND each bit of A with the same bit of the direct RAM address; put the results in A

XRL add,#n

XOR each bit of the RAM address with the same bit in the number n; put the result in the RAM address

CLRA

Clear each bit of the A register to zero

CPL A

Complement each bit of A; every I becomes a 0, and each 0 becomes a 1

Note that no flags are affected unless the direct RAM address is the PSW.

Many of these byte-level operations use a direct address, which can include the port SFR addresses, as a destination. The normal source of data from a port is the port pins; the normal destination for port data is the port latch. When the destination of a logical opera­tion is the direct address of a port, the latch register, not the pins, is used both as the source for the original data and then the destination for the altered byte of data. Any port operation that must first read the source data, logically operate on it, and then write it back to the source (now the destination) must use the latch. Logical operations that use the port as a source, but not as a destination, use the pins of the port as the source of the data.

For example, the port 0 latch contains FFh, but the pins are all driving transistor bases and are close to ground level. The logical operation

ANL PO,#0 Fh

which.is designed to turn the upper nibble transistors off, reads FFh from the latch, ANDs it with 0Fh to produce 0Fh as a result, and then writes it back to the latch to turn these transistors off. Reading the pins produces the result 00h, turning all transistors off, in error. But, the operation

ANL A ,P0

produces A = 00h by using the port 0 pin data, which is 00h.

The following table shows byte-level logical operation examples:

Mnemonic

Operation

MOV A,#0FFh

A= FF h

MOV R0,#77h

R0= 77h

ANL A,R0

A= 77h

MOV 15h,A

15h = 77h

CPL A

A= 88h

ORL 15h,#88h

15h = FFh

XRL A,15h

A= 77h

XRL A,R0

A= 00h

ANL A,15h

A= 00h

ORL A,R0

A= 77h

CLR A

A= 00h

XRL 15h,A

15h = FFh

XRL A.R0

A= 77h

Note that instructions that can use the SFR port latches as destinations are ANL, ORL, and XRL.

CAUTION

If the direct address destination is one of the port SFRs, the data latched in the SFR, not the pin data, is used.

No flags are affected unless the direct address is the PSW. Only internal RAM or SFRs may be logically manipulated.

Bit-Level Logical Operations

Certain internal RAM and SFRs can be addressed by their byte addresses or by the address of each bit within a byte. Bit addressing is very convenient when you wish to alter a single bit of a byte, in a control register for instance, without having to wonder what you need to do to avoid altering some other crucial bit of the same byte. The assembler can also equate bit addresses to labels that make the program more readable. For example, bit 4 of TCON can become TR0, a label for the timer 0 run bit.

The ability to operate on individual bits creates the need for an area of RAM that contains data addresses that hold a single bit. Internal RAM byte addresses 20h to 2Fh serve this need and are both byte and bit addressable. The bit addresses are numbered from 00h to 7Fh to represent the 12Sd bit addresses (16d bytes x S bits) that exist from byte addresses 20h to 2Fh. Bit 0 of byte address 20h is bit address 00h, and bit 7 of byte address 2Fh is bit address 7Fh. You must know your bits from your bytes to take advan­tage of this RAM area.

Internal RAM Bit Addresses

The availability of individual bit addresses in internal RAM makes the use of the RAM very efficient when storing bit information. Whole bytes do not have to be used up to store one or two bits of data.

The correspondence between byte and bit addresses are shown in the following table:

BYTE ADDRESS (HEX)

BIT ADDRESSES (HEX)

20

00-07

21

08-0F

22

10-17

23

18-lF

24

20-27

25

28-2F

26

30-37

27

38-3F

28

40-47

29

48-4F

2A

50-57

28

58-5F

2C

60-67

20

68-6F

2E

70-77

2F

78-7F

Interpolation of this table shows, for example, the address of bit 3 of internal RAM byte address 2Ch is 63h, the bit address of bit 5 of RAM address 21 h is 00h, and bit address 47h is bit 7 of RAM byte address 28h.

SFR Bit Addresses

All SFRs may be addressed at the byte level by using the direct address assigned to it, but not all of the SFRs are addressable at the bit level. The SFRs that are also bit addressable form the bit address by using the five most significant bits of the direct address for that SFR, together with the three least significant bits that identify the bit position from posi­tion 0 (LSB) to 7 (MSB).

The bit-addressable SFR and the corresponding bit addresses are as follows:

SFR

DIRECT ADDRESS (HEX)

BIT ADDRESSES (HEX)

A

OED

OEO-OE7

6

OFO

OFO-OF7

IE

OAS

OAS-OAF

IP

06S

06S-06F

PO

so

SO-S7

Pl

90

90-97

P2

OAO

OAO-OA7

P3

060

060-067

PSW

ODO

ODO-OD7

TCON

SS

SS-SF

SCON

9S

9S-9F

The patterns in this table show the direct addresses assigned to the SFR bytes all have bits 0-3 equal to zero so that the address of the byte is also the address of the LSB. For example, bit 0E3h is bit 3 of the A register. The carry flag, which is bit 7 of the PSW, is bit addressable as 0D7h. The assembler can also "understand" more descriptive mne­monics, such as P0.5 for bit 5 of port 0, which is more formally addressed as 85h.

Figure 4. I shows all the bit-addressable SFRs and the function of each addressable bit. (Refer to Chapter 2 for more detailed descriptions of the SFR bit functions.)

Bit-Level Boolean Operations

The bit-level Boolean logical opcodes operate on any addressable RAM or SFR bit. The carry flag (C) in the PSW special-function register is the destination for most of the opcodes because the flag can be tested and the program flow changed using instructions covered in Chapter 6.

The following table lists the Boolean bit-level operations.

Mnemonic

Operation

ANL C,b

AND C and the addressed bit; put the result in C

ANL C,/b

AND C and the complement of the addressed bit; put the result in C; the addressed bit is not altered

ORL C,b

OR C and the addressed bit; put the result in C

ORLC,/b

OR C and the complement of the addressed bit; put the result in C; the addressed bit is not altered

CPLC

Complement the C flag

CPL b

Complement the addressed bit

CLRC

Clear the C flag to zero

CLR b

Clear the addressed bit to zero

MOV C,b

Copy the addressed bit to the C flag

MOV b,C

Copy the C flag to the addressed bit

SETB C

Set the flag to one

SETB b

Set the addressed bit to one

Note that no flags, other than the C flag, are affected, unless the flag is an addressed bit.

As is the case for byte-logical operations when addressing ports as destinations, a port bit used as a destination for a logical operation is part of the SFR latch, not the pin. A port bit used as a source only is a pin, not the latch. The bit instructions that can use a SFR latch bit are: CLR, CPL, MOY, and SETB.

FIGURES 4.1 Bit-Addressable Control Registers

7

6

5

4

3

2

1

0

CY

AC

F0

RSI

RS0

0V

Resarved

P

PROGRAM STATUS WORD (PSW) SPECIAL FUNCTION REGISTER. BIT ADDRESSES D0h to D7h.

Bit

Function

7

Carry flag

6

Auxiliary carry flag

5

User flag 0

4

Register bank select bit 1

3

Register bank select bit 0

2

Overflow flag

1

Not used (reserved for future)

0

Parity flag

7

6

5

4

3

2

1

0

EA

Reserved

Reserved

ES

ET1

EX 1

ET0

EX0

INTERRUPT ENABLE (IE) SPECIAL FUNCTION REGISTER. BIT ADDRESSES A8h TO AFh.

Bit

Function

7

Disables all interrupts

6

Not used (reserved for future)

5

Not used (reserved for future)

4

Serial port interrupt enable

3

Timer 1 overflow interrupt enable

2

External interrupt 1 enable

1

Timer 0 interrupt enable

0

External interrupt 0 enable

EA disables all interrupts when cleared to 0; if EA = 1 then each individual interrupt will be enabled if 1, and disabled if 0.

7

6

5

4

3

2

1

0

*

*

Reserved

PS

PT1

PX1

PT0

PX0

INTERRUPT PRIORITY (IP) SPECIAL FUNCTION REGISTER. BIT ADDRESSES B8h to BFh.

Bit

Function

7

Not implemented

6

Not implemented

5

Not used (reserved for future)

4

Serial port interrupt priority

3

Timer 1 interrupt priority

2

External interrupt 1 priority

1

Timer 0 interrupt priority

0

External interrupt 0 priority

The priority bit may be set to 1 (highest) or 0 (lowest).

7

6

5

4

3

2

1

0

TF1

TR1

TF0

TR0

IE1

IT1

IE0

IT0

TIMER/COUNTER CONTROL (TCON) SPECIAL FUNCTION REGISTER. BIT ADDRESSES 88h to 8Fh.

Bit

Function

7

Timer 1 overflow flag

6

Timer run control

5

Timer 0 overflow flag

4

Timer 0 run control

3

External interrupt 1 edge flag

2

External interrupt 1 mode control

1

External interrupt 0 edge flag

0

External interrupt 0 mode control

All flags can be set by the indicated hardware action; the flags are cleared when interrupt is serviced by the processor.

7

6

5

4

3

2

1

0

SM0

SM1

SM2

REN

TBB

RBB

TI

RI

SERIAL PORT CONTROL (SCON) SPECIAL FUNCTION REGISTER. BIT ADDRESSES 98h to 9Fh.

Bit

Function

7

Serial port mode bit 0

6

Serial port mode bit 1

5

Multiprocessor communications enable

4

Receive enable

3

Transmitted bit in modes 2 and 3

2

Received bit in modes 2 and 3

1

Transmit interrupt flag

0

Receive interrupt flag

Bit-level logical operation examples are shown in the following table:

Mnemonic

 

SETB 00h

Operation

MOV C,00h

Bit 0 of RAM byte 20h = 1

MOV 7Fh,C

C=1

ANL C,/00h

Bit 7 of RAM byte 2Fh = 1

ORL C,00h

C = 0; bit 0 of RAM byte 20h =1

CPL 7Fh

C=1

CLR C

Bit 7 of RAM byte 2Fh = 0

ORL C,/7Fh

C=0

CAUTION

Only the SFRs that have been identified as bit addressable may be used in bit operations. If the destination bit is a port bit, the SFR latch bit is affected, not the pin.

ANL C,/b and ORL C,/b do not alter the addressed bit b,

 

ASSIGNMENTS on INTRODUCTION TO Z80 INSTRUCTIONS AND PROGRAMMING TECHNIQUES (part2)

ASSIGNMENTS on INTRODUCTION TO Z80 INSTRUCTIONS AND PROGRAMMING TECHNIQUES (part2)

f

25. Rewrite the instructions in Figures 8.2 (a), (b), and (c) using the index regis­ters IX and IY as memory pointers.

26. Write instructions to load XX70H into the IY index register. Using the regis­ter IY as a memory pointer with appropriate offsets, store the bytes A2H and 32H in memory locations XX4FH and XX9FH, respectively.

27. Calculate the value of the memory pointer if register IX contains 2000H with the displacement byte 80H.

28. Calculate the values of two memory pointers if register IY contains-20FFH and it is combined with the displacement bytes 7FH and 8FH.

29. Assuming the index register IX contains 2050H, explain the difference be­tween the instructions INC IX and INC (IX + 0).

30. Rewrite Illustrative Program l (Section 8.6), Block Transfer of Data Bytes, using the index registers as memory pointers.

31. Draw a flowchart to add the numbers stored in memory location INBUF (Input Buffer). When the result generates a carry, subtract the last byte and display the sum.

32. Modify the above program to count and display the number of bytes added (excluding the last one).

33. You are given a long grocery list and asked to buy the items from number 20 to 47. Any item that costs more than $10.00 should be excluded. Add up the total cost and show the total expenses. Draw a flowchart for performing these tasks.

34. Modify the above flowchart to include a ceiling of $100 on total expenses.

35. Draw a flowchart to add the string of numbers stored in memory locations BUFFER. The end of the string is indicated by the number 00. Display the sum.

36. The following block of data is stored in memory locations INBUF. Transfer the data to the locations OUTBUF in the reverse order.

Data (H) 47, 97, F2, 9C, A2, 98

37. Ten bytes are stored in memory locations starting from INBUF. To Insert an additional five bytes at the beginning locations, it is necessary to shift the first ten bytes by five locations. Write a program to shift the data string by five memory locations.

38. Ten 16-bit readings are stored in memory locations SOURCE; the low-order byte is stored first, followed by the high-order byte. Write a program to copy the low-order bytes only to a new location BUFFER in a sequence.

39. Given the initial conditions in 38, ignore the high-order readings and pack the low-order readings in consecutive memory locations SOURCE.

40. Draw a flowchart to modify Illustrative Program 2 (Section 8. 7) to include the instruction Jump on Carry instead of Jump on No Carry (JP NC, SKIPCY). You may have to use an additional Jump instruction, and the flowchart may have to be altered significantly.

41. Modify Illustrative Program 2 (Section 8. 7) using the DE register as a mem­ory pointer instead of HL.

42. Modify Illustrative Program 2 (Section 8. 7) using the DE register as a mem­ory pointer and a memory location as a counter (instead of register B).

43. Write a program to add the following string of data bytes until a carry is generated. When the Carry flag is set, subtract the last byte added and dis­play the sum at OUTPRT.

Data (H) 89, 32, 2B, 7A, B5, 68, 2F

44. Modify the program in 43 to count the number of bytes added (excluding the byte that generates the carry) and display the count at the second port.

45. Ten 16-bit readings are stored in memory locations SOURCE; the low-order byte first, followed by the high-order byte. Write a program to add the low­order bytes. Display the sum at two different ports and store the sum in two memory locations OUTBUF and OUTBUF + 1.

46. Two sets of data, ten bytes each, are stored in memory locations INBUF4 1 and INBUF2. Subtract each data byte stored at INBUF2 from the corresponding data byte at INBUF l. Add the remainders, and if the sum of the remainders generates a carry, display FFH at PORT; otherwise, display the sum at PORT.

47. Find the errors in the following instructions.

a. The following instructions add two Hex bytes (06 and 52) and display the sum at PORT7

XX00

06

LD B, 06H

;Load data bytes

XX0I

06

XX02

0E

LD C,52H

XX03

52

XX04

80

ADDA,B

;Add data bytes

XX05

81

ADDA,C

XX06

D3

OUT(07H),A

;Display the sum

XX07

76

HALT

b. The following instructions add five bytes stored in memory locations starting from XX50H. The sum will be Jess than FFH.

XX00

9F

SUBA

;Clear A

XX01

21

LDHL,XX50H

;Set up HL as memory pointer

XX02

XX

XX03

50

XX04

78

LDB,05H

;Set up B as a counter

XX05

05

XX06

86

ADDA,(HL)

;Add byte

XX07

23

INCHL

;Point to next byte

XX08

05

DECB

;Reduce count

XX09

D2

JPNZ,XX04H

;if B 0, get next byte

XX10

04

XX11

XX

XX12

76

HALT

;End of program

c. The following program transfers 100H bytes of data starting at the memory location 2100H to a new location starting at 2800H.

NEXT.

LDHL, 2100H

;Set up HL as index for source

LDBC, 2800H

;Set up BC as index for new memory

LDDE,0100H

;Set up DE as counter

LD A, (HL)

;Get byte

LD (BC),A

;Transfer byte to new memory

INC HL

;Update indexes and counter

INC BC

DEC DE

JP NZ, NEXT

;If transfer is not complete, go back and get next byte

HALT

;End of data transfer

48. A data set with 512 bytes is stored in memory locations with the starting address INBUFI (XX00H). Shift the entire data set by 256 Locations with the starting address INBUF2 on the next page (XX + 1.00). Use the instruction LDDR.

49. Rewrite Illustrative Program 2 (Section 8.7) using the instructions DJNZ and JR NC.

50. Rewrite Illustrative Program l (Section 8.6) using the index registers IX and! IY as memory pointers and the instruction DJNZ.

51. Rewrite Illustrative Program 1(Section 8.6) to copy 512 bytes by using the IX and IY registers as memory pointers. Define the SOURCE and OUTBUF memory locations accordingly, and use BC register as a counter. (Hint: The decrement instructions for a register pair (such as DEC BC) do not affect any flags. Set the zero flag by ORing the contents of registers B and C.)

 

ASSIGNMENTS on INTRODUCTION TO Z80 INSTRUCTIONS AND PROGRAMMING TECHNIQUES( part 1)

ASSIGNMENTS on INTRODUCTION TO Z80 INSTRUCTIONS AND PROGRAMMING TECHNIQUES

Note: In the following assignments, substitute high-order memory address XX with the high-order address and PORT with the output port address of your single-board microcomputer system, Use your own data if data are not given, and specify memory addresses for labels such as INBUF and OUTBUF.

Section

l. Write mnemonics to load 39H into register B and 92H into register D. Save the contents of B in register L, and display the contents of D at PORT 1.

2. Write instructions to load 47H into register Band F2H into register C using one instruction. Store the contents of C in memory location XX80H and dis­play the contents of B at PORTl. Assemble the Hex code and store the code in memory.

3. Write instructions to load A2H into register D and XX80H into register HL.Copy the contents of D into memory location XX80H.

4. Write instructions to load A7H into register D and XX55H into register BC.Copy the contents of D using BC as a memory pointer.

5. Write instructions to load 98H in memory location XX40H and F9H in loca­tion XX70H. Exchange the contents of these memory locations. Assemble and execute the code.

6. Specify the register contents and the flag statuses after execution of the fol­lowing instructions. Show only the changes in register contents, and when flags are not affected, write NA.

Registers

Flags

A B C H L

Z

CY

34 7F FF 01 00

0

l (Initial Conditions)

LDA,00H

LDBC, 8058H

LDB,A

LDHL, 2040H

LDL,C

LD(HL), A

HALT

7. Write instructions to read the input port 80H and output the reading to the port 05H (see Figure 8.11). What appliances will be turned on with this output?

8. Write comments to explain the functions of the following instructions:

LD HL, 2065H

LD (HL), 00H

HALT

9. What are the contents of the accumulator after the execution of the instruc­tion SUB A? Specify the status of the Z and CY flags.

10. Write the instructions to load FFH into the accumulator and increment A.

Specify the status of the S, Z, and CY flags after the execution of the incre­ment instruction.

Assembly Language Programming (22)

11. In the previous assignment (#10), replace the increment instruction with the instruction ADD A, 01H and explain how the flags S, Z, and CY are af­fected after the addition.

12. Specify the register contents and the flag status after the execution: of the following instructions. What is being displayed at OUTPRT?

13. Write instructions to load 40FFH into register HL and increment HL. Spec­ify the contents of register HL.

14. Register HL contains 20FFH. What are the contents of register HL if the byte 01H is added (not incremented) to register L? What are the statuses of the S, Z, and CY flags after the addition?

15. Write instructions to perform the operations listed in 14, and assemble the code showing memory addresses.

16. Show the contents of the registers and the memory locations that are af­fected after the execution of the following instructions. Explain the differ­ence between the two INC instructions shown below.

LDHL,209FH

LD(HL), FFH

INC (HL) INCHL

HALT

17. Find the results of the following operations and explain the difference be­tween the two results.

SUB A

SUBA

LD HL,971FH

LDHL,971FH

LDBC,8F9CH

LDBC,8F9CH

ADDA,L

ADDA,L

ADDA,C

ADDA,C

ADDA,B

SUB H

SUB H

ADDA,B

HALT

HALT

18. Load 48A2H into register BC. Subtract the contents of C from B. If the an­swer is in 2’s complement, display 01H at PORT; otherwise, display the re­sult. Assemble the code and execute the program.

19. Execute the program in 18 by loading F247H in register BC.

20. Three data bytes are stored in memory locations XX50, XX5l, and XX52H. Write instructions to subtract the bytes stored in memory locations XX50 and XX5l from the byte stored in location XX52H. If the answer is in 2’s complement, display FFH at PORT; otherwise, display the answer. Execute the instructions with the following set of data in Hex.

Set 1: XX50 = 32, XX51 = 78, XX52 = F9

Set 2: XX50 = 67, XX51 = 98, XX52 = F9

21. The Relative Jump instruction JR NZ, 68H is stored in memory locations XXA7H and XXA8H. Calculate the jump location.

22. If the opcode of the Relative Jump instruction JR NC, 8FH is located at memory location XX50H, calculate the jump location.

23. Assemble the code in Illustrative Program 1 (Section 8.6.3) and replace the instruction JP NZ, NEXT with the appropriate Relative Jump instruction and offset.

24. In Illustrative Program 2 (Figure 8. 10), assemble the code and replace the Jump instructions JP NC, SKIPCY; and JP NZ, NXTBYT with the appro­priate Relative Jump instructions and their offsets.

 

SUMMARY off INTRODUCTION TO Z80 INSTRUCTIONS AND PROGRAMMING TECHNIQUES

SUMMARY off INTRODUCTION TO Z80 INSTRUCTIONS AND PROGRAMMING TECHNIQUES

 

cvjg

In this chapter, we illustrated a group of instructions from the Z80 set frequently used in writing programs. Instructions were selected from three groups: data copy, arithmetic, and branch. These instructions range from 1 byte to 4 bytes long. General characteristics of these instructions are as follows:

1. The data copy and load instructions copy the contents of the source into the destination without affecting the source contents. They do not affect the flags.

2. The arithmetic instructions (with some exceptions) assume one of the oper­ands is the accumulator, and the result of an operation is usually stored in the accumulator. Most of these instructions affect the flags.

3. The conditional Jump instructions are decision-making instructions and are executed according to the status of the flags. Not all instructions affect the flags; in particular, the data copy instructions and 16-bit increment/decrement instructions do not affect the flags.

4. The Z80 microprocessor includes two index registers (IX and IY), which are used primarily as memory pointers. The instructions related to index regis­ters have 2-byte Opcode and perform data copy and arithmetic operations with the contents of memory registers.

Programming techniques such as looping, counting, and indexing were dis­cussed and a generalized flowchart was illustrated. Two illustrative programs were discussed in the context of this generalized flowchart.

Finally, some Z80 special instructions were introduced. These instructions perform multiple tasks; thus, they improve programming efficiency.