Chapter 1 - 8051 ASSEMBLY LANGUAGE PROGRAMMING
Upon Completion of this Chapter, You will be able to:
- List the registers of the 8051 Microcontroller
- Manipulate data Using the registers and MOV instructions
- Code simple 8051 Assembly Language Instructions
- Assemble and run an 8051 Program
- Describe the sequence of events that occur upon 8051 power-up
- Examine programs in ROM code of the 8051
- Explain the ROM memory map of the 8051
- Detail the execution of 8051 Assembly Language Instructions
- Describe the 8051 data types
- Explain the purpose of the [PSW] 'Program Status Word' register
- Discuss RAM memory space allocation in the 8051
- Diagram the use of the stack in the 8051
- Manipulate the 'Register Banks' of the 8051
SECTION I - INSIDE THE 8051:
Lets begin with an exploration of the major registers of the 8051. A, B, R0, R1, R2, R3, R4, R5, R6, R7, DPTR, and PC. The use of these registers will be demonstrated in context of programming examples. The process of creating an assembly language program will be described from writing the source file, to assembling it, linking and executing the program. The PC [program counter] register always points to the next instruction to be executed. An assembly language program is composed of a series of statements that are either instructions or pseudo-instructions, also called directives. Instructions are translated by the assembler into machine code. Pseudo-instructions are not translated into machine code. They direct the assembler in how to translate instructions into machine code. Some pseudo-instructions, called data directives, are used to define data. Data is allocated in byte-size increments. The data can be in binary, hex, decimal, or ASCII formats.
Flags are useful to programmers as they indicate certain conditions, such as carry or overflow, that results from execution of instructions. The stack resides in the RAM space of the 8051. Manipulation of the stack via POP and PUSH instructions will also be explained.
Here we will examine the major registers of the 8051 and show their use with the simple instructions MOV and ADD.
In the CPU, registers are used to store information temporarily. That information could be a byte of data to be processed, or an address pointing to the data to be fetched. The large number of 8051 registers are 8-bit registers. There is only one data type in 8051 Microcontroller: 8 Bits. The 8 bits and 16-Bits of a register are shown in Figure Below. From the MSB [Most Significant Bit] D7 to the LSB [Least Significant Bit] D0. With an 8-bit data byte, any data larger than 8 bits must be broken into 8-bit chunks before it is used.
Some 8-Bit Registers of the 8051:
Some 8051 16-Bit Registers:
DPTR [Data Pointer]
PC [Program Counter]
The most widely used registers of the 8051 are A[accumulator], B, R0, R1, R2, R3, R4, R5, R6, R7, DPTR, and PC. All the registers are 8-bits except 'Data Pointer' DPTR and the 'Program Counter' PC. The accumulator, register A, is used for all arithmetic and logic instructions. To understand the use of these registers, two simple instructions 'MOV' and 'ADD' can be used.
The MOV instruction copies data from one location to another. The format of MOV instruction is given below
|MOV destination , source ;copy source to destination|
This instruction tells the CPU to copy the source operand to the destination operand. For example, the instruction "MOV A,R1" copies the contents of register R1 to register 'A'. After execution of this instruction, register A will have the same value as register R1. The MOV instruction does not affect the source operand. The following program given below first loads the register A with value 44H [44 in HEX], then this value around the various registers inside the CPU. The '#' sign in the instruction indicates that it is a value.
|MOV A,#44H||;Load value 44H into register A|
|MOV R0,A||;Copy the contents of A into R0, A=R0=44H|
|MOV R1,A||;Copy contents of A into R1, A=R0=R1=44H|
|MOV R2,A||;Copy contents of A into R2, A=R0=R1=R2=44H|
|MOV R3,55H||;Load value 55H into R3|
|MOV R3,A||;Copy contents of R3 into A, A=R3=55H|
Using '#' Pound Sign in Assembly Language:
Values can be loaded directly into any of the registers A, B, or R0 - R7. To indicate that it is an immediate value it must be preceded with a pound sign [#].
|MOV A,#32H||;Load 32H into A, i.e. A=32H|
|MOV R0,#21H||;Load 21H into R0, i.e. A=21H|
|MOV R1,#2FH||;Load 2FH into R1, i.e. A=2FH|
|MOV R2,#1BH||;Load 1BH into R2, i.e. A=1BH|
|MOV B,#1CH||;Load 1CH into B, i.e. B=1CH|
|MOV R7,#8DH||;Load 8DH into R7, i.e. A=8DH|
|MOV R5,#0F8H||;Load F8H into R5, i.e. R5=F8H|
|MOV R6,#12||;Load 12 decimal into register R6 i.e. R6=12|
- In Instruction "MOV #0F8H" , there is a '0' between the '#' sign and 'F' to indicate tha F is a hex number and not a letter.
"MOV #F8H" will cause an error.
- If values 0 to F are moved into an 8-bit register, the rest of the bits are assumed to be all zeros. For example, in "MOV A,#6" the result will be A=05; i.e. A=0000 0110 in Binary.
- Moving a value that is too large into a register will cause an error.
- To load a value into a register, it must be preceded with a pound sign [#]. Otherwise it means to load from a memory location. For example "MOV A,16H" means to move into A the value held in memory location 16H, which could have any value. In order to load the value 16H into the accumulator A, we must write "MOV A,#16H" with the '#' preceding the number. The absense of the pound sign '#' will not cause an error by the assembler since it is a valid instruction. However, the result would not be what the programmer expect to do. This is a common error/mistake for beginning programmers in the 8051.
|MOV A,#8F3H ;Illegal 8F3H is greater than 8 bits [FFH]|
|MOV R1,#789 ;Illegal 789 is greater than 255 decimal [FFH]|
The ADD instruction has the following format:
|ADD A,source ;ADD the source operand to the accumulator|
The ADD instruction tells the CPU to add the source byte to register A and put the result in register A. To add two numkbers such as 24H and 33H, each can be moved to register A then added together:
|MOV A,#24H ;Load 24H into A|
|MOV R1,#33H ;Load 33H into A|
|ADD A,R1 ;Add R1 to Accumulator, i.e. [A=A + R1]|
When executing the program above results in A=57H [24H + 33H = 57H], and R2 = 33H. The contents of R2 does not change. The program above can be written in many way, depending on the registers used. In Some other ways might be like given below:
|MOV R4,#24H ;Load 24H into register R4 [R4=24H]|
|MOV R6,#33H ;Load 33H into register R6 [R6=33H]|
|MOV A,#0 ;Load 0 into A [A=0, Clear A]|
|ADD A,R4 ;Add to accumulator, content of R4|
|ADD A,R6 ;Add to accumulator, content of R6, where A=A+R6|
The above program results in A=57H. There are always many ways to write the same program.
It is necessary to move Data item into registers before adding them together?:
The answer is no. It is not necessary at all. The following program below proves this.
|MOV A,#24H ;Load one operand into accumulator A [A=24H]|
|ADD A,#33H ;Load the second operand 33H to accumulator|
- In the above scenario, one register contained one value, the second value followed the instruction as an operand. This is called an immediate operand. The program above shown for the ADD instruction indicate that the source operand can be either a register or immediate data, but the destination must always be register accumulator 'A'. In other words, an instruction such as "ADD R2,#12H" is invalid since register accumulator A must be involved in any arithmetic operation.
- Notice that "ADD R4,A" is also invalid, This reason is that accumulator A must be the destination of any arithmetic operation. In the 8051, the register accumulator A must be involved and be the destination for all arithmatic operations.