19 The 8051 Microcontroller: The Programmer’s Perspective – The x86 Microprocessors: 8086 to Pentium, Multicores, Atom and the 8051 Microcontroller, 2nd Edition

19

The 8051 Microcontroller: The Programmer’s Perspective

IN THIS CHAPTER, YOU WILL LEARN

  • The architecture of 8051 from a progra­mmer’s perspective.
  • The addressing modes of 8051.
  • The complete instruction set of 8051.
  • How to write assembly language programs using the Keil assembler.

Introduction

In this chapter, we will start our study of the very popular microcontroller 8051. The programming model is discussed here while internal peripherals and their programming will be discussed in Chapter 20. Assembly language programming with worked out examples is extensively discussed in this chapter and Chapter 20. Interfacing of external peripherals is covered in Chapter 21.

19.1 | History and Family Details of 8051

Intel produced the 8051 microcontroller in the year 1981 calling it Intel MCS-51, the technology used for it being NMOS. Now CMOS technology has taken over and with this, relatively low-power versions of 8051 are also available. Over the years, Intel stopped manufacturing this chip (in 2007) but allowed other manufacturers to do it. Thus, we have this chip with different versions, packing and manufacturers. Chips manufactured by Atmel, Philips, Maxim (originally Dallas Semiconductors) are available with varying numbers of peripherals inside. Let us make a review of this extremely popular family of 8-bit microcontrollers. The important features of 8051 when it was first designed by Intel are as follows:

  1. 8-bit data bus
  2. 16-bit address bus
  3. 4 register banks
  4. 32 general purpose registers each of 8 bits
  5. A 16-bit program counter (PC) and data pointer (DPTR)
  6. 4 KB on chip program memory (ROM)
  7. 128 bytes on chip data memory (RAM)
  8. Two 16-bit timers
  9. Four 8-bit ports
  10. 3 internal and 2 external interrupts
  11. One serial communication port (UART)
  12. Bit as well as byte addressable RAM area of 16 bytes
  13. 12 clock cycles to constitute one machine cycle

Because of different manufacturers, many versions of the 8051 with different speeds and differing amounts of on-chip ROM are now found in the market. What is important is that although there are different flavours of the 8051, they are all compatible with the original 8051 as far as the instruction set is considered. Figure 19.1 shows the internal components of an 8051 chip.

Figure 19.1 | Building blocks of a generic 8051

19.1.1 | Other Members of the Family

Two members of the family which stand out (because of being different) are the 8052 and 8031. The latter, i.e., 8031 does not have internal ROM and so is frequently denoted as a ‘ROM less’ 8051; it needs external ROM to burn the program designed for it. 8052 is different by having more RAM in it—128 bytes more and also an extra timer.

When you try to buy a chip of 8051, it is likely that you will not find such a part number available. This is because 8051 has been given different numbers based on the type of ROM inside; if the ROM is UV PROM, the version is denoted 8751. If it is flash memory that is present, it is called 8951. The letter ‘C’ is added to the chip name, as it is based on CMOS technology rather than the NMOS used by Intel in the beginning. Thus, we find 89C51 is the chip that we might get to buy. Atmel is a popular manufacturer of 8051. Table 19.1 displays a partial list of its 8051 versions.

Table 19.1 | A List of Some 8051 Versions from Atmel

Consider the name AT89C51-12PC, where ‘AT’ stands for Atmel, ‘C’ for CMOS, ‘12’ indicates 12 MHz, ‘P’ is for plastic DIP package and ‘C’ for commercial. Note that 2051 and 1051 are scaled down versions of 8051 with less number of I/O pins, timers, etc. There are versions with the full 64K ROM available, and the clock frequency also varies from 4 to 40MHz.

Another major producer of the 8051 family is NXP founded by Philips Corporation. This manufacturer has a very large collection of 8051 microcontrollers. Their products include features such as A-to-D converters, D-to-A converters, extended I/O, and both OTP (One Time Programmable ROM) and flash ROM. As an exercise, you can try to find out the extra and extended peripherals available in the version P89C51RD2 manufactured by NXP.

19.1.2 | Learning the Features of 8051

Once the 8051 is understood well, learning any other microcontroller will be very easy. Our approach will be to understand the 8051 first, from a programmer’s point of view and then to enlarge this view by learning its hardware and interfacing features. This chapter is concerned with the programming aspects only.

19.2 | 8051: The Programmer’s Perspective

Let us look at the 8051, as a programmer needs to know it. Figure 19.2 shows the internal blocks which a programmer needs, to do coding. We will examine it block by block.

Figure 19.2 | The 8051 architecture from a programmer’s point of view

In this figure, the bus connecting the blocks is not shown, but keep in mind that the data bus is 8 bits wide, while the address bus is 16 bits wide. These buses are inside the chip.

19.2.1 | Eight-bit Registers of 8051

The 8051 is an 8-bit microcontroller. This means that it can handle a maximum data width of 8 bits only. This also implies that all its data registers are 8 bits long.

The Accumulator Register 'A'

The most important data register is the A register, which acts as the ‘accumulator’. It is mandatory that the A register carry one of the operands for all arithmetic instructions. The other operand may be in memory (RAM) or in any other register.

Register B

The register B is not a frequently used register, because it can be used as an operand only for some specific operations like multiplication and division. For example, for the multiplication of two numbers, one operand should be in A and the other should be in B. Same is the case for division. But it can store data.

Register Banks

There is a set of eight registers named R0 to R7, which act as general purpose data registers. Actually, there are four sets of such registers, each set being called a register bank. But, at a particular time, only one block is operational. In conclusion, we can say that the general purpose registers available for data manipulation at any time are A, B and the current bank of eight registers. See Fig. 19.3, which shows this set.

Figure 19.3 | General purpose registers

Processor Status Word (PSW)

This is an 8-bit register which contains the flag bits and also has the bits that permit ‘bank switching’. We will see it in detail in the forthcoming sections.

Stack Pointer (SP)

This is an 8-bit register which stores the address of the top of the stack.

19.2.2 | Internal Memory

Internal RAM

Totally, the 8051 has 256 bytes of RAM, but half of it is reserved to act as the ‘special function registers’, i.e., the registers which are used to handle the activities of the peripherals of the device. We will discuss the SFRs in Chapter 20. The remaining 128 bytes is what is referred to as internal RAM, and it is divided into parts. The first 32 bytes act as register banks 0 to 3; each bank contains 8-data registers named R0 to R7. These registers are used for data manipulations and data movement. At a time, only one of these banks is operational. It is possible to switch from the ­current bank to another bank by using two bits of the PSW. By default, it is bank 0 that is the current bank. The remaining area of RAM is used simply as user RAM and can be accessed using their addresses. We will see the details as we go into programming.

Internal ROM

All versions of 8051 contain some amount of ROM (except the 8031). ROM is used to store the final code that an application needs. Once a design is tested and finalized, the code is burned into ROM. Flash ROM is the type that is used nowadays. A part of ROM can store data also. There are instructions that allow us to access ROM during the course of programming. The amount of ROM available varies between chips, but the maximum possible is 64K (because the address bus is 16 bits).

19.2.3 | Sixteen-bit Registers

Program Counter (PC)

This is an address register, which ‘sequences’ instructions. This means that at any time, it points to the address of the next instruction to be fetched. Instructions are stored in ROM—hence, the PC is a pointer to ROM—the maximum size of ROM is 64K, and the size of the PC is 16 bits. See Fig. 19.4. On reset, the content of PC is 0, meaning that the first instruction is always taken from the address 0000.

Figure 19.4 | The program counter

Data Pointer (DPTR)

This is also an address register, and so, it is 16 bits in size. However, it can be used as two 8-bit registers—DPH and DPL, with H and L standing for high and low respectively, i.e., the MSB and LSB of the DPTR. See Fig. 19.5.

Figure 19.5 | The data pointer register

The DPTR is used as a pointer for accessing internal ROM and also for external memory (if added to the chip).

19.2.4 | Ports

There are four 8-bit ports for 8051, and they are named 0 to 3. There are corresponding port pins, and these are used to connect to the peripherals. The ports are designated as P0, P1, P2 and P3 and can be used with such designations in programs. They can also be designated by their RAM addresses in the SFR space.

19.3 | Assembly Language Programming

We have had just a glance at the internal structure of 8051, but with this, we can start programming. This will help to get a better view of the chip and its use. Also, as we do assembly language programming, we will get a fuller view of the internal architecture.

The general format of an assembly language instruction line is

LABEL: INSTRUCTION ;COMMENTS

In this, the label and comments are optional. The instruction consists of the opcode and the operands. The comment field needs a semicolon to indicate its presence.

For programming the 8051, different assemblers are available. In this book, all programs are tested using the Keil assembler; the details of which can be looked up in Appendix G. The evaluation version of this is freely downloadable by looking up ‘Keil microvision 4’ or trying the link https://www.keil.com/demo/eval/c51.htm.

19.3.1 | Modes of Addressing

As in the case of any processor, the 8051 also has various modes of addressing. Here, we use the ‘move’ instruction to illustrate the different modes. The general format of this instruction is

MOV destination, source

The source and destination can be registers or memory. There is also the possibility of the source being a data item, i.e., an immediate number.

19.3.1.1 | Register Addressing

In this mode, both the source and destination are registers. The registers that can be used are A, B and the registers from R0 to R7. Examples of this mode are as follows:

19.3.1.2 | Immediate Addressing

In this mode, the source is a data item and is indicated by preceding the data by a ‘#’ symbol, indicating ‘immediate’. Data can be copied to a register or a memory location, using this mode.

The 16-bit DPTR can be loaded with immediate data, considering it as two 8-bit numbers being moved to DPH and DPL

Note 1

  1. Any number is treated as a decimal number. Hexadecimal numbers are to be written suffixed with an ‘H’ or prefixed with 0x. For example, 91 is treated as a decimal number. If it to be considered as a hexadecimal number, it is to be written as 91H or 0x91, in programs.
  2. Hexadecimal numbers starting with the symbols ‘A to F’ must be preceded by a 0. Otherwise, the assembler will indicate a syntax error. For example, FEH is to written as 0FEH, in any program.

19.3.1.3 | Direct Addressing

In this mode, one of the operands is to be in a memory location. For the case of the MOV instruction, the content of a memory location is moved to a register or vice versa. The memory that we have is either RAM or ROM. Now, we will look into the case of addressing RAM locations. The case of ROM will be examined in Section 19.3.1.5.

Before we write any instructions, let us examine the RAM structure of 8051. The internal RAM area is 128 bytes with addresses 00 to 7FH. See Fig. 19.6, which shows the RAM structure.

Figure 19.6 | The subdivisions of internal RAM

The first 32 bytes of RAM constitute the four register banks. For example, examine bank 0, which is the default register bank. There are eight registers named R0 to R7. Since they are part of the internal RAM, they have addresses 00 to 07 also. See Fig. 19.7. Thus, the instruction MOV A, R2 can be written as MOV A,02 as well. In both the cases, the same content is being addressed.

Figure 19.7 | Register banks and their RAM addresses

Similarly MOV A, R0 is the same as MOV A, 00

MOV 06, A is the same as MOV R6, A

MOV B, 04 is the same as MOV B, R4

MOV 00, 03 is the same MOV R0, R3

If bank 0 is the current bank, the other banks are just RAM locations. See the following instructions:

Example 19.1

Run the following program and explain what happens after the execution of each line of the program.

Solution

  1. The first line ORG 0 shows the ‘origin’ of the program. It indicates that this program is to start from 0, i.e., the address from which the first instruction will be taken up for execution.
  2. The last line END is also mandatory for any assembler. It tells the assembler to stop reading beyond this line.
  3. For each of the program lines, the result of execution is shown in the comments field.

19.3.1.4 | Register Indirect Addressing

There is an indirect method of addressing data, which is in RAM, by using certain registers as pointers to the address. However, only registers R0 and R1 are allowed to be used as pointers.

Consider two data items residing in RAM locations 25H and 30H. R0 and R1 can be made to act as pointers to these data, by loading the address values in them. See the code snippet given as follows. The content of these RAM allocations can be copied to registers A and B using the notation ‘@’ along with R0 and R1.

Data can also be copied to RAM locations ‘indirectly’, by using the pointer registers R0 and R1. But registers R0 to R7 cannot be used as destination registers in indirect addresses.

However, using the RAM address 07 for R7 does not give any error

Example 19.2

Examine the following program and find out which registers and which RAM locations contain the data 7EH and EFH, after program execution. What else will be noticed?

Solution

In this program, R0 acts as a pointer to the data 7EH, which is in RAM address 25H. After program execution, registers A, R5 and R7 contain the data 7EH. The program does not show R5 and R7 as destinations to this data, instead their RAM addresses 05 and 07 have been used. In the Keil debugger, this data will be seen in the register list as well as in the RAM address (however, they mean the same).

The data EFH (in address 30H) is pointed by R1. The program makes this data to be copied to register B, as well as to RAM address 26H (which is beyond the address of the register banks. See Fig. 19.7.

The last line of the program treats R0 as a pointer to a destination. The content of B is moved to this destination. Hence, 88H will be found in the RAM address 30H.

19.3.1.5 | Indexed Addressing

This is a type of addressing applicable to ROM alone. It was mentioned earlier that ROM stores program code, but it can also be used to hold some data also. Usually tables and some constants are stored there to be used by programs. Suppose we want to retrieve some of these data items, we cannot access ROM using any of the methods so far discussed.

The maximum size of ROM is 64K, and so addresses of ROM locations can be 16 bits long. In indexed addressing mode, the DPTR is used as a base address, and the accumulator is used as an offset. The effective address formed by adding the value of the base address to the offset, is the ROM address to be accessed. There is the MOVC instruction especially tailor-made for ROM access.

MOVC A, @A+DPTR is the instruction which loads the content of ROM with effective address A+DPTR into the A register.

Consider that the ROM location 0500H is to be accessed. The instructions needed for getting data from the address are as follows.

19.4 | Internal RAM

Before we go into details of active programming, it will be worthwhile to take a second look at the different subdivisions of internal RAM.

Figure 19.8 shows the memory map of the 256 bytes of internal RAM that the 8051 possesses. The upper 128 bytes from addresses 80H to FFH are addresses of the special function registers, which cater to the operation of the peripherals. Incidentally, the addresses of the A, B and SP (Stack Pointer) registers are also in this space. See Table 19.2. In programs, these addresses may be used, instead of the names, (but that may not be necessary, normally). The details of the SFRs are discussed in Chapter 20.

Figure 19.8 | Address map of internal RAM

Table 19.2 | Addresses of Important Registers

Now look at Fig. 19.8 once again. The 16 RAM addresses from 20H to 2FH are stated to be bit addressable. Figure 19.9 shows the addresses of the ‘bit’ locations. Note that each 'byte' of RAM of this RAM area has an address. Within that byte, there are eight 'bit' addresses too. For example, the byte location with address 20H can be addressed with 8 different addresses from 00 to 07, for each of the bits.

Figure 19.9 | Addresses of the bit addressable locations of RAM

How Do We Differentiate between Bit Addresses and Byte Addresses?

For example, 03 is a bit address, but there is also a byte address 03.

The trick is that both use different instructions. The instructions that are applicable to bit addresses are SETB, CLR, JNB and JNB. The following instructions refer to the ‘bit address’ 03.

For byte addresses, instructions like the following apply.

It is obvious that a byte is referred here.

What Can Be Done with One Bit?

It can be ‘set’ or cleared; there are instructions available which will set or clear each individual bit of these 16-byte locations, i.e., there are 16 × 8 = 128 bit addressable locations in the internal RAM.

Byte Addressable RAM

The rest of the RAM from 30H to 7FH is addressable only as bytes. These locations can be read from or written into, using the MOV instruction in the direct or indirect addressing mode.

19.5 | The 8051 Stack

All processors need a stack. A stack is a portion of memory which can act as a temporary storage location for data, which will be taken back later. The stack is a special type of data structure, in that it can be accessed (read from or written to) only at the ‘top of the stack’. The instructions used for this kind of access are PUSH (for writing to) and POP (for reading from). The stack is user defined, but on start up, the stack pointer register contains the number 07.

The 8051 stack is an ascending stack. This means that as data is pushed in, it grows upwards to increasing addresses. If the stack pointer contains the number 07, the stack area is defined from 08 onwards. The first data item pushed in will be stored in 08, the next in 09 and so on.

In practice, it is best to change the value of the stack pointer from 07 to a higher location. This is because register bank 1 starts at 08, and using the stack there prevents us from being able to use bank 1. For example, the instruction MOV SP, #42H makes the stack to be defined from 43H onwards (upwards), by loading the number 42H into the stack pointer.

19.5.1 | The Push Operation

Consider the case shown in Fig. 19.10, where the SP value is 42H. Assume that R3 contains the value xx and R5 contains the value yy.

Figure 19.10 | PUSH operation for the 8051 stack

Let us do the exercise of pushing in the values of R3 and R5 onto the stack. The natural way of pushing in would be to write the instructions PUSH R3 followed by PUSH R5. But 8051 does not allow us to use register names in the PUSH instruction. The address of these registers needs to be used. If register bank 0 is the one referred to, the instructions to be used are

The stack pointer is now incremented (after each push instruction) and the end, it has the content of 44H. Figure 19.10 shows the stack

19.5.2 | The pop operation

Now, to do popping to, say, register R7, the instruction to be used is

The SP value is decremented by one, to become 43H, and data, which is on top of the stack, i.e., yy, will now be in R7. See Fig. 19.11.

Figure 19.11 | POP operation in an 8051 stack

Example 19.3

Assume that register bank 2 is now the working bank. It is needed to push the content of registers R5 and R6 to stack. It is also needed to pop out these values to A and B, respectively. Write instructions for this.

Solution

Now let us examine the salient points of this simple program

  1. The addresses of the registers have been used.
  2. The content of R5 is first pushed in and then that of R6. After this, the stack top contains the data that was in R6.
  3. The requirement is to copy the contents (through the stack) of R5 to A and R6 to B. Since the stack top contains the content of R6, the first POP operation is to pop to B.
  4. Keep in mind that for a stack, what is pushed in last is what can be popped out first.
  5. The second pop operation copies the stack top contents to A.

Note There is no need to use the stack to copy the contents of one register to another. The program here uses this method only to illustrate the working of a stack.

19.6 | Processor Status Word (PSW)

This is a register with address D0H, which has the conditional flags and also contains the bits that allows the switching of register banks, see Fig. 19.12.

Figure 19.12 | The PSW register

This register (like many other SFRs), is bit addressable, meaning that each bit can be set or cleared individually. To do that, the notation for each bit is as given in column 2 of Table 19.3.

Table 19.3 | Bits of the PSW and their Functions

Now let us discuss the bits of the PSW register.

The Carry Flag (CY)

Bit D7, notated as PSW.7 is the carry flag. The carry flag (CY) is set if there is a carry out from the most significant bit during a calculation. For example, when 8-bit addition causes the result to be greater than 8 bits, there is a carry out from the MSB (D7), which causes this flag to be set. This flag is set also when there is ‘borrow’ during subtraction.

The Auxiliary Carry Flag (AC)

Bit D6, notated as PSW.6 is the AC flag. This flag functions similar to the carry flag, except that the overflow is from bit D3 into D4. It, thus, indicates a carry out from the lower 4 bits. The need for this flag is for the Decimal Adjust (DA) instruction, which is important in BCD number calculations. There are no other instructions that directly test the state of this flag and no conditional branching is associated with this flag.

The Overflow Flag (OV)

Bit D2, notated as PSW.2 is the overflow flag. This flag is set under one of the following conditions:

  1. There is an overflow into the MSB (D7) from the bit of lower significance, but no carry out from the MSB,
  2. There is a carry out from the MSB, but no carry into the MSB.

This flag indicates that the result of a signed number operation is too large, causing the higher order bit to overflow into the sign bit, thus changing the sign bit.

The Parity Flag (P)

Bit D0, notated as PSW.0 is the parity flag. The setting of this flag indicates the presence of an even number of ‘1’ bits in the destination. For example, after a particular arithmetic or logic operation, if the destination contains the number 11100111, the parity flag is set to indicate even parity.

Have You Noticed That There is No Zero Flag (Z) for 8051?

Well, there is not a zero flag that a user has to take note of, but instead, there are instructions which verify if the result of an arithmetic operation causes the A register to be zero and then takes appropriate action. We will see it in the context of our discussions on the instruction set and programming.

Bank Switching

The bits RS1 and RS0 (PSW. 4 and PSW.3) are used for bank switching. There are four banks of registers designated as Bank 0, Bank 1, Bank 2 and Bank 3. On start up, it is the default bank 0, which is the ‘current bank’. To switch to another bank, refer to Table 19.4. When bank 0 is being used, RS0 and RS1 are 00. To get to use bank 1, say, the instruction to be used just needs to set PSW.3, i.e., RS0. Similarly, other banks can be used by setting /clearing these two bits.

Table 19.4 | Bit Values for Bank Switching

Unused Bits of the PSW

One bit, PSW.5 is available to the user to define as he deems fit or leave unused. The bit PSW.1 is reserved for future uses.

19.7 | Assembler Directives

Very soon, we will learn the instructions set of 8051 and start the programming process in dead earnest. So, it is important to be aware of some of the important directives used by a typical 8051 assembler. You should already know that directives are different from instructions, in that they are non-executable statements. They just help the assembler by providing certain important information.

ORG

ORG is a directive, which means ‘origin’. In the context of assembly language programming, it defines the starting address for any item (data or code) in the program memory (ROM). We have already used the statement ORG 0 in Examples 19.1 and 19.2.

EQU

This directive allows us to equate names to constants. The assembler just replaces the names by the values mentioned.

Examples

DB

This directive stands for ‘data byte’ and places an 8-bit number constant at this memory (ROM) location. If labels are used for these memory locations, a ‘colon’ should suffix the labels.

Examples

BIT

This directive equates a bit to either ‘1’ or ‘0’, or labels a bit, which can be set or reset. When the bit is named, the name, when encountered in a program is replaced by the logic value specified.

Examples

END

This indicates that the assembler need not read beyond this.

19.8 | Storing Data in Code Memory (ROM)

We know that what we store in ROM is program code but data can also be stored and read from it, when needed. In fact, the ROM does not need to know what is stored;whatever is stored is binary numbers, either way. But when we store data, it is needed for use by the program, and therefore, there should be a mechanism to read it and bring it to registers.

Example 19.4

See the following program which illustrates the use of some of the above referred directives. Data is to be stored in ROM addresses 0500H and 0800H onwards. Note that there are no instructions in this program, but only directives. Give a brief explanation on what is achieved by each of these lines.

Solution

This is only a set of directives. No instructions are involved, so ‘execution’ is not necessary. This data is just burned in ROM at the address 0500H and also at 0800H. In the simulator, the data is found to be in code memory, just after the program is assembled. We find data as in Tables 19.5 and 19.6.

Table 19.5 | Data in ROM from 0500H

Table 19.6 | Data in ROM from 0800H

We find another set of data from address 0800H onwards.

19.9 | The Instruction Set of 8051

Now, let us start the assembly language programming of 8051, by first understanding the instruction set. The instructions can be divided into functional groups as follows:

  1. Data transfer instructions
  2. Bit manipulation instructions
  3. Branch instructions
  4. Port manipulation instructions
  5. Arithmetic instructions
  6. Logical instructions
  7. Call and return instructions

19.9.1 | Data Transfer Instructions

In any processor, moving data is of primary concern. There is a destination and a source for the movement. Data is moved between registers, memory and ports. Table 19.7 lists the data transfer instructions of 8051.

Table 19.7 | List of the Data Transfer Instructions

Now let us have a more detailed discussion on how and when each of these instructions is to be used.

19.9.1.1 | MOV—Move

Usage: MOV dest, src

For 8051, the data is 8 bits in size and so it is 8-bit data that is always moved. Let us see a few examples and the actions performed by them:

19.9.1.2 | MOVX—Move To/From External RAM

Sometimes the 8051 needs extra RAM, as the internal data RAM in sufficient. If extra data RAM is connected externally, its content is accessed using the MOVX instruction. The DPTR is used for this instruction by loading the RAM address (to be accessed) into it. Then MOVX is used as shown as follows:

19.9.1.3 | MOVC

The use of this instruction for accessing ROM has already been considered in Section 19.3.1.5. The ROM can be external or internal. In this book, we will concern ourselves only with on-chip ROM.

19.9.1.4 | PUSH and POP

The use of these instructions has already been discussed in Section 19.5.

19.9.1.5 | XCH—Exchange

There are two instructions which perform the act of exchanging (swapping). One is 8-bit swapping, and the other is 4-bit swapping.

The format for 8-bit exchange is XCH A, byte. The byte can be another register or a memory location.

Examples

19.9.1.6 | Nibble Swapping

The format of this is XCHD A,@Ri.

This instruction exchanges the lower nibble of A and the lower nibble of the byte pointed by Ri, leaving the upper nibbles of both unchanged.

After execution, A will contain 40H and the RAM address will contain 35H.

19.9.2 | Bit Manipulation Instructions

All microcontrollers need to address data at the bit level because they may have to deal with one bit interfaces like single switches, LEDs, relays, etc. All these devices require the setting or clearing of single bits.

Which Are the Bits That Can Be Addressed Individually?

  1. The carry flag
  2. The bits in the bit addressable area of RAM
  3. The bits in registers that are bit addressable, e.g., PSW.1. P0.3, P2.4, ACC.0, etc.

Let us see, one by one, the instructions which allow single bits to be addressed.

Refer Table 19.8 and the following examples.

Example

Table 19.8 | List of Data Manipulation Instructions

Example 19.5

When the MCU is powered on, the default register bank is bank 0. Write a program to switch to bank 3 and then to switch to bank 1.

Solution

On startup, it is register bank 0, which is operational, i.e., RS0 = RS1 = 0 will be the status of the bank select bits.

The bits of the PSW needed for selecting a register bank are shown as follows:

The code lines are as follows, for switching to bank 3.

Now to switch to bank 1, it is only necessary to make RS1 = 0. The instruction for this is

19.9.3 | Branch Instructions

Branching is a very important aspect in programming and making its actions to be ­‘conditional’ is what gives decision-making capability to any computer. In 8051, there are unconditional, as well as conditional branch instructions. Let us have a look at these ­instructions. We will start with the unconditional type of the ‘jump’ instruction.

19.9.3.1 | Unconditional Jump Instructions

SJMP Target

SJMP stands for ‘short jump’; it is also a ‘relative’ jump. What these terms mean is that the destination is expressed as a ‘relative’ number, and that the ‘relative’ number is short, i.e., only 8 bits. The number is a signed number and denotes the distance (in bytes) between the current PC value and the target (destination) address. If this number is negative, it is a backward jump, the maximum range of which is -128. If forwarding jumping is what is needed, the number is positive with a maximum range of +127.

In practice, the programmer does not need to know this relative number. He can write the label corresponding to the destination, and the assembler will calculate the ‘displacement’ and insert it into the machine code. To get to the target, the value of PC (when the SJMP instruction is executed) will be added to the displacement in the code, and this will be the new value of PC. Thus, control will be taken to the target address and the change of flow of the program occurs.

See the following code snippet. The target has the label THERE. When the SJMP instruction is being executed, the PC will be pointing to the next instruction in the sequence. The assembler calculates the offset to the ‘THERE’ label, adds it to PC and then continues execution, which is from the address THERE.

LJMP Target

This is a long jump instruction, and it is not ‘relative’. It is a three byte instruction; the first byte is the opcode and the next two bytes constitute the absolute address of the target. When this instruction is executed, the current PC value is simply replaced by the 16-bit number in the instruction, which can have any value from 0 to FFFFH. Since code is written in program memory (ROM), the 16-bit number can only be as big as the actual ROM present in the chip (all 8051 chips will not have 64K ROM).

AJMP Dest

This is also a relative jump, but the range of jumping is 2K, and 11 bits specify the destination range.

Unconditional jump instructions will be used later in programs which generate square waves (Section 19.12.1) Besides that, it is likely that many programs end with the following line

This instruction loops to itself continuously. This is done, because when programs are burned in ROM, execution should not proceed beyond the last instruction in the program. In the ROM, in addresses beyond the last line, random numbers (some of which are codes burned earlier) are likely to have been stored and if those get executed, it will cause havoc. To prevent this from happening, the last code line can be written using an SJMP instruction like

19.9.3.2 | Conditional Branch Instructions

These are the instructions which make programming really useful. Computers are used for repetitive and conditional tasks and conditional branching is the method for it. Table 19.9 gives the list of conditional branch instructions.

Table 19.9 | List of Conditional Jump Instructions

Note 2 All conditional jumps are short jumps.

JC Target

Jump on carry to target.

JNC Target

Jump on No carry, to target.

These instructions test the carry flag and jump to the target depending on the condition of the carry flag, as specified.

JZ Target

Jump on Zero (A = 0) to target.

JNZ Target

Jump on no Zero (A! = 0) to target.

Recollect that there is no Zero flag for 8051. Theses two instructions test the A register to see if it contains a non-zero number or not and jumps to the target accordingly.

JB Bit, Target

Jump to target if the specified bit is set.

JNB Bit, Target

Jump to target if the specified bit is not set.

JBC Bit Target

Jump to target if the specified bit is set, then clear the bit.

The bits that can be used here are bits of registers, ports or RAM.

Examples

DJNZ Byte, Target

This instruction decrements the specified byte and jumps to the target if the byte becomes zero (on decrementing). The byte can be one of the registers of the register bank, or a RAM address.

Examples

Now, let us use these conditional jump instructions in programs.

Example 19.6

Write a program to fill 20 spaces in RAM with the ASCII value of ‘*’.

Solution

This is a very direct program. The ASCII value of * is loaded in A and moved to 20 RAM locations, by using R0 as the pointer to the starting address 30H. The pointer is incremented 20 times and at the end of the program, we find that 20 locations in RAM have this content – i.e., '*'. The counter R3 is decremented by the DJNZ instruction, and it causes jumping out of the loop once the counter is zero.

Example 19.7

Store the ASCII values of the first 10 capital letters of the alphabet in ROM locations. Bring these 10 values to RAM locations starting from 40H.

Solution

In this example, both ROM and RAM are accessed. The ROM address (starting from 0500H) is pointed by DPTR, while the RAM address (from 40H) is pointed by R1. The directive DB at 0500H stores the required characters in ROM.

The content of ROM is brought to A and copied to RAM continuously until the counter R3 is 0.

Note that the 10 letters of the alphabets are stored as an ASCII string (in double quotes). In some (not Keil) assemblers, it is not possible to store strings like this, instead they should be stored as single characters separated by commas, i.e, ‘A’, ‘B’, ‘C’… and so on.

19.9.4 | Arithmetic Instructions

The complete list of arithmetic operations of the 8051 is given in Table 19.10.

Table 19.10 | List of Arithmetic Instructions

Note 3 For 8051, it is mandatory that the A register is one of the operands for addition, subtraction, multiplication and division.

19.9.4.1 | Addition Instructions

ADD A, src

This instruction adds the source and A, and puts the sum in A. The CY, OV and AC flags are affected.

ADC A, src

This is the ‘add with carry’ instruction. The source, the carry flag and A are added and the sum is put in A.

INC Dest

This instruction adds 1 to the destination, which can be any register or RAM location.

No flags are affected.

Example 19.8

Add the first 20 natural numbers and store the sum in a RAM location.

Solution

This is quite a simple program. In this program, the numbers 1, 2, 3… 20 are consecutively added and the sum is stored in RAM—the sum is less than 255, so one byte space is sufficient for it. R2 is used as one of the registers, and R2 is continuously incremented to get the numbers to be added.

Example 19.9

Add four 16-bit numbers which are in consecutive memory locations, assuming that the sum does not go above 16 bits.

Solution

The first part of the program simply loads the numbers in RAM locations 40H to 47H. The four numbers are 0575H,0265H,1276H,3457H. The sum is to be 4EA7H.

The program first adds the LSBs. They are added taking into account the fact that their addition may lead to a carry, after adding any two numbers. Whenever a carry is generated, the RAM address 49H is incremented. The sum of the LSBs is finally copied to R4.

Then the MSBs are added. There are five numbers to be added, the fifth being the sum of the ‘carry’ of LSB addition. This is in address 49H and the pointer R1 points to this as the last operand.

We have used numbers which do not generate carries in the MSB addition. The sum is limited to four hex digits. The sum is finally in R4 and R5, with R4 = 0A7H and R5 = 4EH.

19.9.4.2 | Subtraction Instructions

SUBB A, src

This subtracts the source byte and the carry flag from A and puts the result in A. The OV, CY and AC flags are affected. This is actually a ‘subtract with borrow’ instruction. There is no subtraction instruction, as such. For subtraction, the carry flag is cleared and then the operation is done.

An example of a typical set of instructions for carrying out subtraction is

The result of this subtraction will be 55H in A

DEC Dest

This instruction subtracts 1 from the destination, which can be any register or RAM location.

No flags are affected.

19.9.4.3 | Multiplication Instruction

MUL AB

This instruction multiplies two unsigned numbers—one is to be in A and the other in B. The product can be two bytes long (maximum), and it will have its lower byte in A and its upper byte in B.

The multiply instruction clears the carry flag and sets the OV flag if the product is greater than FFH.

Example

19.9.4.4 | Division Instruction

DIV AB

This instruction divides the content of A by the content of B. The quotient will be in A and the remainder in B. The CY and OV flags are affected. CY is always 0, and OV is set to 1 only when the division is invalid, i.e., when B, the divisor is 0, and the result is undefined.

Example

19.9.4.5 | Decimal Adjust for BCD Addition

DA A

This is the instruction for ‘decimal adjust accumulator’ after BCD addition. The details of how this is done are given in Section 0.7.2.

19.9.4.6 | Clear the Accumulator

CLR A

This instruction clears the accumulator and is equivalent to MOV A,#0. No flags are affected.

Example 19.10

The selling prices of 5 items are stored in ROM locations 0100H onwards. The corresponding cost prices are entered in RAM locations from 40H onwards. Calculate the average profit of the five items.

Solution

The method is to get the selling prices (SP) from ROM into the A register, subtract the cost prices(CP), which are in RAM from 40H and save the corresponding profits in RAM addresses from 50H onwards. The last item will be in 54H.

The second part of the program from the label CALCU adds the five profits. During addition, R1 is used as the pointer to addresses from 54H and R1 is decremented to get the 5 items. The sum is divided by 5, to get the profit in the R5 register. See the program.

The program is logically very simple, but it includes a number of actions for 5 data items and is done by looping with a counter R3.

  1. It copies the ROM contents to A
  2. It subtracts the contents of A and the contents of RAM (from 40H). This subtraction is Profit = SP − CP
  3. It stores results of the subtraction in RAM from 50H onwards
  4. It then adds contents of 5 RAM locations
  5. It divides the sum by 5
  6. The quotient is moved to R5

19.9.4.7 | Compare Instruction

CJNE Dest, Src, Target

This instruction compares the source and destination, and if they are not equal, branches to the target address, otherwise the next instruction in the sequence is executed.

The second action that this compare action does is to grade the ‘inequality’ by indicating whether the destination or source is the bigger number. The carry flag is used for this; the operands, i.e., the source and destination do not change in the process of comparison. The CY flag is updated according to the conditions as indicated in Table 19.11.

Table 19.11 | Condition of the Carry Flag After a Compare Instruction

But, there are some restrictions on the ways by which the source and destination can be represented. The following are the sources allowed when A is the destination register

  1. the source can be an immediate data

    e.g., CJNE A, #0E4H, THERE

  2. the source can be a direct address

    e.g., CJNE A, 67H, BACK

When A is not the destination register, there are two possible cases

  1. The destination can be any of the R0-R7 registers, and the source is to be an immediate data

    e.g., CJNE R3, #34H, FORE

  2. The destination is a RAM address pointed by R0 or R1 and the source is an immediate data

    e.g., CJNE @R0, #0C4H, NOPE

Example 19.11

Find the biggest of 3 numbers which are stored in RAM locations 45H, 46H and 47H. Load the biggest number in R2.

Solution

The flowchart (Fig. 19.13) shows how comparison proceeds in the case of three numbers X, Y, Z.

Figure 19.13 | Flowchart for the comparison of three unsigned numbers

In this program, the first number X is copied to A and the second (Y) to B. They are compared.

  1. If they are equal or if A > B, then A is to be compared to the third number. For this, the third number Z is copied to B, and A and B are then compared. If A is found bigger now, then the first number X is the biggest. If A is smaller, the third number Z is the biggest.
  2. If A < B in the first comparison, then the second number is bigger, so swap the number such that the bigger number is in A. Then get the third number in B and compare them.
  3. If A < B, then the third number Z is the biggest, otherwise

    the second number Y is the biggest.

    The biggest number is copied to the register R2.

Example 19.12

50 bytes are stored from locations 34H onwards. Find out how many of these bytes are zero.

Solution

This is a simple program. R0 is the pointer to RAM location 34H. It is incremented to load data into A from each of the locations. After that, the JZ instruction is used to verify whether the A register has 0. Every time a 0 is loaded into A, the register R4 is incremented. At the end of the program execution, R4 has the result.

19.10 | Port Programming

We have seen many of the important instructions, but a few more are left. They are the logical and rotation instructions, and the types involving call and return.

But before we go to that, let us learn programming involving the GPIO (General Purpose I/O) ports of the chip. There are four ports for the 8051 as can be seen in the functional pin diagram in Fig. 19.14.

Figure 19.14 | Functional pin diagram of 8051

This diagram is meant only for understanding the port structure of 8051. You can ignore all the other pins, for the time being. Note that there are four ports—P0, P1, P2 and P3, each of which consists of 8 pins. (Note that Port 3 has dual functions associated with each of its pins.) Each of these ports can be used as inputs or outputs. On reset, all port pins will have logic‘1’. Any data can be directly outputted to the pins, but to make them act as inputs, a ‘1’ must be sent out on the pins–only after that, will that pin be able to accept an input signal and transfer it to the internal registers.

19.10.1 | Port Instructions

Ports can only take data in (from outside) or put data out. There are no special instructions for ports. The 8051 uses the MOV instruction for this.

In these two cases, each of the ports has 8 bits, and all the 8 bits are taken together as a byte. But each port pin is bit addressable too, it can be set or cleared (if it is an output pin) or read in as a single pin, (for a 0 or 1), if declared to be an input pin.

For this, the nomenclature is ‘portname. bit no ‘. For instance, we use P1.0, P2.3, P3.7, etc. meaning the 0th bit of Port 1, 3rd bit of port 2, 7th bit of port 3 and so on. Now let us do a few programs in which port pins are involved.

Example 19.13

The ports 0 and 1 are connected to two input devices. Write a program to take in data from these ports and compare them. If they are found to be equal, pin P2.0 should be set, otherwise it should be cleared.

Solution

For a port to be able to act as an input port, it should first be given a ‘1’ on all its pins. Only after this step, will it be able to accept input data.

Example 19.14

Switches are connected to Port pins P1.6 and P1.7 as shown in Fig. 19.15. They are to be monitored continuously, and if found closed, LEDs are to be lighted up or switched off (if the corresponding switch is found open), at port pins P1.0 and P1.1, respectively. Write a program to do this.

Figure 19.15 | LEDs and switches connected to an 8051

Solution

Here, the value of the input pin P1.6 is tested and the LED on P1.0 is lighted if the switch S1 is found closed, i.e., if P1.6 = 0 (switch closed). Then P1.0 must be made ‘1’. The same is the relationship between i/p pin P1.7 and o/p pin P1.1.

Example 19.15

Port pin P2.2 is connected to a water level sensor, which continually senses the water level. When the level reaches a specified limit, this pin will go high. Then the following actions are to occur (See Fig. 19.16).

Figure 19.16 | Water level controller using 8051

  1. Bit 05 of the RAM (in the bit addressable part) is to be set.
  2. Port pin P2.0, which is connected to a switch is to be set (this will switch off the water supply).
  3. Port pin P2.1, which is connected to a buzzer (active low) should be cleared.
  4. In the program, the port pins are given labels, and are referred by them, using the BIT directive.

19.10.2 | Logical Instructions

Now, let us take a quick look at the logical instructions of 8051. The list of logical instructions is shown in Table 19.12.

Table 19.12 | List of Logical Instructions

The points to be noted are

  1. For the ANL,ORL and XRL instructions, the format is dest,src.
  2. Except for one special case, it is mandatory that the A register be the destination.

Examples

The special case is when a RAM address is allowed to be the destination as follows:

19.10.3 | Complement Instruction

Only the A register and a direct RAM address can be used as the destination

19.10.4 | Rotate Instructions

There are four rotate and one swap instruction for the chip. Only the A register can be used for these instructions.

Let us examine each one of them

  1. RL A: Rotate left the contents of A

    Figure 19.17 shows that the A register is rotated left and D7 appears in the D0 position after rotation.

    Figure 19.17 | Rotate left instruction

  2. RR A: Rotate right the contents of A

    Figure 19.18 shows that the A register is rotated right and the bit D0 is moved to D7.

    Figure 19.18 | Rotate right instruction

  3. RLC A: Rotate left through carry

    The A register is shifted left and bit D7 is moved to carry, while the carry bit is moved to D0 of A. See Fig. 19.19.

    Figure 19.19 | Rotate left through carry

  4. RRC A: Rotate right through carry

    The A register is shifted right and the carry bit is moved to D7, while D0 moves into the carry. See Fig. 19.20.

    Figure 19.20 | Rotate right through carry

  5. SWAP A: This is a special instruction where the lower and upper nibbles of A are swapped. See Fig. 19.21.

    Figure 19.21 | Swapping the nibbles of the accumulator

Example 19.16

Read in data from port 0. Only the upper four bits of this data is needed. Take the upper four bits and send it as an output nibble to the lower four bits of port 1.

Solution

At the end of the program, the wanted data is in the lower four bits of Port 1

Example 19.17

Count the number of 1’s in register R1. Take the data from a RAM location.

Solution

Here, the method is rotate A into the carry bit and check if the carry if 1 or not. If it is 1, increment a count in register R2. Finally, R2 has the count of the number of 1’s in register R1.

19.11 | Subroutines (Procedures)

All the programs that we have written are straightforward, in the sense that control flows sequentially from one instruction to the next, and a change in the sequence in which a program is executed, is changed only on encountering a JUMP instruction.

But there is another way by which the execution order is changed and that is by ‘one program calling another program’. The calling program is called a main program, while the called program is designated as a ‘subroutine, function or procedure’. When a program has to do a task repeatedly it is better that a procedure is called whenever required. Once the procedure is executed and done with, once again the main program takes charge. See Fig. 19.22. The fundamental aspects involved here are as follows:

Figure 19.22 | A main program calling procedures

  1. The main program calls a procedure.
  2. The procedure returns control to the main program after its completion.

The first step needs a CALL instruction, and the second needs a return instruction. Let us discuss them. The 8051 has two CALL instructions, i.e., the LCALL and the ACALL. The format for these instructions is

  1. LCALL proc-name
  2. ACALL proc-name

19.11.1 | LCALL

This is a ‘long call’ instruction. This means that the target program (i.e., the procedure) can be anywhere within the 64K space of program memory. This is a three byte instruction—the first byte is the opcode and the next two bytes are the two byte address of the procedure.

19.11.2 | ACALL

This is a call instruction in which the target procedure must lie within 2K range of the calling program. This is a two byte instruction, with 11 bits allotted for the address of the procedure. Thus, this instruction is used frequently, because it saves one byte of code memory.

What Happens When a Call Occurs?

When a CALL (LCALL or ACALL) instruction is encountered, the content of PC (which is the address of the next instruction) is pushed on to the stack. The address of the procedure is copied to PC, and the next instruction that is executed will be the first instruction of the procedure. The last instruction in the procedure is RET (return). This will pop the return address from stack to PC so that control returns to the main program.

RET

This instruction causes the stack top contents to be popped to PC. When a procedure was called, the return address had been pushed onto stack. The return instruction simply retrieves this. It gives back this address to the program counter.

Example 19.18

Port 0 receives BCD input data from a source. It has to be converted to ASCII form and outputted through two output ports, the lower digit at Port 1 and the upper digit at Port 2.

Write a program for this.

Solution

Consider a BCD number like, say, 89. The ASCII of this needs two bytes. The lower byte is 39H (ASCII of 9) and the upper byte is 38H (ASCII of 8).

In this program, the ASCII conversion is written as a procedure.

The salient points of this program are as follows:

  1. The BCD digit is got from port 0 and stored in R1. Then the lower nibble is processed. For this, the procedure ASCII is called.
  2. The procedure first masks the upper byte—if the BCD no is 89H, 09 is got
  3. Then it is ORed with 30H to get 39H, the ASCII of 9.
  4. On returning to the main program, the no is again brought to A and its nibbles are swapped, to get the upper nibble in the lower nibble position, i.e., 89H becomes 98H.
  5. Then the ASCII procedure masks the upper byte to get 08, and then this is ORed with 30H to get the ASCII 38H of 8.
  6. The values of ASCII numbers are outputted on P1 and P2.

Note The procedure is stored in a different location (0040H) away from the main program. That is why ORG 0040H is seen. This is not absolutely necessary. The procedure can be stored just after the main program itself.

Now, we have almost come to the end of the instruction set. In fact, just one instruction is left. It is the NOP instruction, which means ‘no operation’. It does nothing, in fact, but it causes a delay of one machine cycle and can be used to bring in an additional element of delay in ‘delay loops’, which we will now discuss.

19.12 | Delay Loops

Why Do We Need Delays?

It may be required to create delays to time events, for example, we may want to output data at a port (which may be changing) every ‘t’ seconds, say. To define ‘t’ seconds, the microcontroller will create a delay and that can be realized by software or hardware. In the latter case, the ‘timer’ hardware will do this task.

But here, we will create delay using software. This simply means that we get the 8051 to execute a number of repetitive instructions. Since each instruction needs a certain amount of time for execution, the net effect of executing these instructions is to cause a delay. Nothing else is achieved with these instructions (in this context).

To create a delay, the following information must be available

  1. The clock frequency of the 8051 used
  2. The number of clock cycles that constitute a machine cycle
  3. The number of machine cycles needed for each of the instructions which constitute the delay loop

Crystal Frequency

Refer to Fig. 19.14. You can see the pins 18 and 19 between which a crystal is to be connected. The frequency of this crystal decides the clock ­frequency for the chip. It is possible to use frequencies between 4 to 40 MHz as crystal frequencies. The frequency 11.0592 MHz is a commonly available and used crystal frequency. We will use this frequency for our calculations in this section.

Machine Cycle

A machine cycle is defined as the time required for completing some part of an instruction. All instructions may require one or more machine cycles. A machine cycle will be more than one clock cycle. For 8051, a machine cycle constitutes 12 clock cycles. This standard will be used here, even though there are other versions of this chip which use less number of clock cycles.

Table 19.13 gives a list of the number of machine cycles needed for some commonly used instructions. Appendix F gives the complete list.

Table 19.13 | Machines Cycles Expended in Executing Some Instructions

19.12.1 | Calculating Delay

Assume the clock frequency of f = 11.0592 MHz for the 8051. One clock period = 1/f.

One machine cycle is 12 × 1/f = 1.085 μ secs

How Do We Create a Delay?

The method is to load a number in a register and decrement if down to zero. The amount of delay obtained depends on the number loaded.

Example 19.19

Find the delay obtained in the following loop

Solution

The MOV instruction takes 1 machine cycle, and the DJNZ instruction takes 2 machine cycles. The DJNZ instruction gets repeated 250 times.

Total delay = 1.085[250 × 2 + 1] = 1.085 × 501 = 543.585 μ secs

The amount of delay obtained in Example 19.18 is only around half a millisecond. This is quite small. To increase the delay, two registers can be used in a nested loop configuration.

Example 19.20

Find the delay obtained in the following nested loop.

Solution

Take the INSIDE loop. It creates a delay of 1.085 × (255 × 2 + 1) = 555

The OUTER loop repeats the INSIDE loop 50 times to get an effective delay of 555 × 50 = 27750 μ secs = 27.750 m secs.

In this calculation, we have neglected the delay due to the initial instructions of

This delay = 50 × 3 × 1.085 = 162 μ secs. Compared to the delay created by the double loop, this delay is negligible—and anyway, we consider the delay created by software as only approximate. So, in our next examples, we will simply neglect the delay due to these ‘peripheral’ instructions.

Example 19.21

Write a program to generate a delay of 20 msecs using 8051.

Solution

The maximum number that can be loaded into a register is 255. From Example 19.20, it is seen that with this, the maximum delay that can be obtained is 555 μ secs. So, to get a delay of 20 msecs, we should find the number of times this loop should be repeated.

To get this, the method is to divide 20 msecs by 555 μ secs

20 m secs/555 μ secs = 36

So, the program is

Delay = 36 × 255 × 2 × 1.085 us = 19920 us = 19.92 m secs = 20 m secs (approx).

Figure 19.23 shows the square wave generated at pin P1.3

Figure 19.23 | Square wave generated at P1.3

Example 19.22

Generate a symmetrical square waveform of time period 40 m secs at P1.3.

Solution

To generate such a waveform, the pin P1. 3 should be held high for 20 msecs and low for 20 msecs. We can use the delay program of example (previous) to create the delay, we can write the delay creation part as a procedure.

Note that in this program, the delay procedure is written just after the main program. The last instruction of the program is actually SJMP START. It causes an infinite repetition of the program.

Example 19.23

Generate a square waveform at all the pins of port 1, with an ON time of 0.5 secs and OFF time of 1.5 secs (Fig. 19.24).

Figure 19.24 | Square wave generated at all pins of Port 1

Solution

We might need three registers to get a large delay of 0.5 secs. For the inner loops, let us use registers with the maximum count of 255. For the outer most loop, let the register be loaded with the number N, which we calculate as follows.

0.5 × 1000 × 1000 μ secs = N × 255 × 255 × 2 × 1.085 μ secs

500 × 1000 = 141104 N

N = 3.5 = 4 (approx)

This will give a delay of 0.5 secs.

We call the procedure which gives a delay of 0.5 secs, as DELAY_HALF. This is just a label for the procedure and indicates the address (in ROM) where the procedure is stored.

We write a delay procedure to get 0.5 secs delay and call it three times to get the delay of 1.5 sec. See the complete program. The asymmetric square wave generated, can be observed at all the pins of Port 1.

19.12.2 | Using NOP

It was mentioned in Section 19.11.2, that the NOP instruction could be used in delay loops.

Example 19.24

Let us make a delay loop with just one register and 5 NOP instructions. Find the maximum delay that can be obtained with this.

Solution

The total delay inside the delay loop is [255 (1 + 1 + 1 + 1 + 1 + 1 + 2)] × 1.085 μ secs = 1936 μ secs = 1.9 m secs

Thus, we have obtained a high delay using a NOP instruction.

Whenever an extra element of delay is needed, the NOP instruction comes in handy.

KEY POINTS OF THIS CHAPTER

  • A microcontroller is a device which has a number of peripherals and memory inside the chip.
  • The 8051 family has a number of members with different numbers of peripherals and different amounts of ROM, but the instruction set is the same for all of them.
  • From a programmer’s point of view, the registers, RAM, ROM and ports are the important entities in the chip.
  • The total internal R/W memory consists of user RAM and special function register RAM
  • The user RAM is referred to as internal RAM and consists of 128 bytes.
  • There are four register banks, and bank switching is possible.
  • The stack of 8051 is an ascending type of stack.
  • The processor has data transfer, bit manipulation, arithmetic, logical, rotate and call instructions.
  • The Keil assembler is a popular assembler to write and test programs, using its inbuilt simulator.
  • There are different modes of addressing like register, direct, indirect and indexed modes.
  • Delays can be generated using software.

QUESTIONS

  1. Name at least four peripherals that a microcontroller can have.
  2. What is the use of flash ROM inside the chip?
  3. What is the use of register banks? How can bank switching be done?
  4. Which are the registers that can be used for indirect addressing?
  5. Is the 8051 stack a LIFO or FIFO stack?
  6. What is the value of SP on reset?
  7. What is meant by saying that a register is bit addressable?
  8. What is the difference between the LJMP and SJMP instructions?
  9. What is done by the instruction JB bit target?
  10. 10. Which are the two forms of the exchange instructions?
  11. Which is the instruction used to create delays?
  12. What is the use of the NOP instruction?

EXERCISES

  1. Write a program to store the ASCII string "MY NAME IS SUSAN" IN ROM.

    Now bring it to RAM one byte at a time and output it to port A with a delay of 1 msec between each outputting action.

  2. Write a program to use register bank 2 for adding ten numbers which are in RAM.
  3. Take two numbers which are in ROM, multiply them and save the product in RAM. Fix up the locations as you want.
  4. Add two BCD numbers and use the DA instruction to correct the result.
  5. Perform division of two numbers using repeated division.
  6. Write a program to convert a hex number to decimal form.
  7. Take in data from Port 1, add 10H to it and sent it out through Port 2.
  8. Read data at pins P1.2 and P1.3 and if they are both of the same logic, output ‘1’ to P1.7. Otherwise clear P1.7.
  9. Write a program to toggle all the bits of Port 1 at a rate of once per second.
  10. Add two 32-bit numbers which are stored in ROM.
  11. Add two 64-bit numbers which are stored in RAM.
  12. Check the 50-byte locations of RAM from 30H onwards. Search for the character ‘Q’ in these locations and find how many times this character is present.