Sunteți pe pagina 1din 28

8051 CODE

Delay using 8051 timer.


The 8051 microcontroller has two independent 16 bit up counting timers named Timer 0 and Timer 1 and this article is about
generating time delays using the 8051 timers. Generating delay using pure software loops have been already discussed here but such
delays are poor in accuracy and cannot be used in sensitive applications. Delay using timer is the most accurate and surely the best
method.
A timer can be generalized as a multi-bit counter which increments/decrements itself on receiving a clock signal and produces an
interrupt signal up on roll over. When the counter is running on the processors clock , it is called a Timer, which counts a
predefined number of processor clock pulses and generates a programmable delay. When the counter is running on an external
clock source (may be a periodic or aperiodic external signal) it is called a Counter itself and it can be used for counting external
events.
In 8051, the oscillator output is divided by 12 using a divide by 12 network and then fed to the Timer as the clock signal. That means
for an 8051 running at 12MHz, the timer clock input will be 1MHz. That means the the timer advances once in every 1uS and the
maximum time delay possible using a single 8051 timer is ( 2^16) x (1S) = 65536S. Delays longer than this can be implemented by
writing up a basic delay program using timer and then looping it for a required number of time. We will see all these in detail in next
sections of this article.
Designing a delay program using 8051 timers.
While designing delay programs in 8051, calculating the initial value that has to be loaded inot TH and TL registers forms a very
important thing. Let us see how it is done.
Assume the processor is clocked by a 12MHz crystal.
That means, the timer clock input will be 12MHz/12 = 1MHz
That means, the time taken for the timer to make one increment = 1/1MHz = 1uS
For a time delay of X uS the timer has to make X increments.
2^16 = 65536 is the maximim number of counts possible for a 16 bit timer.
Let TH be the value value that has to be loaded to TH registed and TL be the value that has to be loaded to TL register.
Then, THTL = Hexadecimal equivalent of (65536-X) where (65536-X) is considered in decimal.
Example.
Let the required delay be 1000uS (ie; 1mS).
That means X = 1000
65536 X = 65536 1000 = 64536.
64536 is considered in decimal and converting it t0 hexadecimal gives FC18
That means THTL = FC18
Therefore TH=FC and TL=18
Program for generating 1mS delay using 8051 timer.
The program shown below can be used for generating 1mS delay and it is written as a subroutine so that you can call it anywhere in
the program. Also you can put this in a loop for creating longer time delays (multiples of 1mS). Here Timer 0 of 8051 is used and it is
operating in MODE1 (16 bit timer).
DELAY: MOV TMOD,#00000001B // Sets Timer 0 to MODE1 (16 bit timer). Timer 1 is not used
MOV TH0,#0FCH // Loads TH0 register with FCH
MOV TL0,#018H // LOads TL0 register with 18H
SETB TR0 // Starts the Timer 0
HERE: JNB TF0,HERE // Loops here until TF0 is set (ie;until roll over)
CLR TR0 // Stops Timer 0
CLR TF0 // Clears TF0 flag
RET
The above delay routine can be looped twice in order to get a 2mS delay and it is shown in the program below.
MAIN: MOV R6,#2D
LOOP: ACALL DELAY
DJNZ R6,LOOP
SJMP MAIN

DELAY: MOV TMOD,#00000001B
MOV TH0,#0FCH
MOV TL0,#018H
SETB TR0
HERE: JNB TF0,HERE
CLR TR0
CLR TF0
RET
Few points to remember while using timers.
Once timer flag (TF) is set, the programmer must clear it before it can be set again.
The timer does not stop after the timer flag is set. The programmer must clear the TR bit in order to stop the timer.
Once the timer overflows, the programmer must reload the initial start values to the TH and TL registers to begin counting up
from.
We can configure the desired timer to create an interrupt when the TF flag is set.
If interrupt is not used, then we have to check the timer flag (TF) is set using some conditional branching instruction.
Maximum delay possible using a single 8051 timer is 65536S and minimum is 1S provided that you are using a 12MHz crystal
for clocking the microcontroller.
Square wave generation using 8051 timer.
Square waves of any frequency (limited by the controller specifications) can be generated using the 8051 timer. The technique is very
simple. Write up a delay subroutine with delay equal to half the time period of the square wave. Make any port pin high and call the
delay subroutine. After the delay subroutine is finished, make the corresponding port pin low and call the delay subroutine gain.
After the subroutine is finished , repeat the cycle again. The result will be a square wave of the desired frequency at the selected port
pin. The circuit diagram is shown below and it can be used for any square wave, but the program has to be accordingly. Programs for
different square waves are shown below the circuit diagram.

Square wave generation using 8051 timer
1KHz Square wave using 8051 timer.
MOV P1,#00000000B
MOV TMOD,#00000001B
MAIN: SETB P1.0
ACALL DELAY
CLR P1.0
ACALL DELAY
SJMP MAIN
DELAY: MOV TH0,#0FEH
MOV TL0,#00CH
SETB TR0
HERE: JNB TF0,HERE
CLR TR0
CLR TF0
SETB P1.0
RET
END
2 KHz Square wave using 8051 timer.
MOV P1,#00000000B
MOV TMOD,#00000001B
MAIN: SETB P1.0
ACALL DELAY
CLR P1.0
ACALL DELAY
SJMP MAIN
DELAY: MOV TH0,#0FCH
MOV TL0,#018H
SETB TR0
HERE:JNB TF0,HERE
CLR TR0
CLR TF0
SETB P1.0
RET
END
10 KHz square wave using 8051 timer.
MOV P1,#00000000B
MOV TMOD,#00000001B
MAIN: SETB P1.0
ACALL DELAY
CLR P1.0
ACALL DELAY
SJMP MAIN
DELAY: MOV TH0,#0FFH
MOV TL0,#0CEH
SETB TR0
HERE:JNB TF0,HERE
CLR TR0
CLR TF0
SETB P1.0
RET
END
Object counter using 8051 microcontroller.
This article is about a simple object counter/visitor counter using 8051 microcontroller . AT89S51 belonging to the 8051 family is the
microcontroller used here. This circuit can count the number of objects passing across a line , number of persons passing through a
gate/door and so on. The can be simply divided into two sections i.e. the sensor section and the display section.
Sensor.
The sensor part consists of a ultra bright led (with focus), and LDR, opamp LM324 and the associated passive components. The LED
is placed on one side of the door and the LDR is placed on the other side so that the light from the LED falls directly on the LDR.As
you know, the resistance of the LDR has an inverse relationship with the intensity of the light falling on it. The preset resistor R14 is
so adjusted that the voltage across the LDR is below 1.5V when it is illuminated. This voltage (labelled A in the circuit diagram) is
connected to the inverting input of the opamp which is wired as a comparator with reference voltage 1.5V (set using R15 and
R16).Capacitor C1 is meant for bypassing noise or anything like that which may cause false triggering.Resistor R13 is meant to
control the current through the LED.
When the light is falling on the LDR the voltage across it will be less than the reference voltage and so the output of the opamp
remains high. When the light beam is interrupted, the voltage across the LDR goes above the reference voltage and so the opamp
output goes low and it indicates a pass.
Display section.
The output of the opamp is fed to the INTO (interrupt 0) pin of the microcontroller. The microcontroller is programmed to count the
number of negative edge pulses received at the INT0 pin and displays it on the three digit seven segment display.
Circuit diagram.
Object counter using 8051

Program.
ORG 000H
SJMP INIT
ORG 003H // starting address of interrupt service routine (ISR)
ACALL ISR // calls interrupt service routine
RETI

INIT: MOV P0,#00000000B
MOV P3,#11111111B
MOV P1,#00000000B
MOV R6,#00000000B
MOV DPTR,#LUT
SETB IP.0 // sets highest priority for the interrupt INT0
SETB TCON.0 // interrupt generated by a falling edge signal at INT0 pin
SETB IE.0 //enables the external interrupt
SETB IE.7 //enables the global interrupt control

MAIN: MOV A,R6
MOV B,#100D
DIV AB
ACALL DISPLAY
SETB P1.0
ACALL DELAY
ACALL DELAY
MOV A,B
MOV B,#10D
DIV AB
ACALL DISPLAY
CLR P1.0
SETB P1.1
ACALL DELAY
ACALL DELAY
MOV A,B
ACALL DISPLAY
CLR P1.1
SETB P1.2
ACALL DELAY
ACALL DELAY
CLR P1.2
SJMP MAIN

ISR: INC R6 //interrupt service routine
RET

DISPLAY: MOVC A,@A+DPTR // display sub routine
CPL A
MOV P0,A
RET

DELAY: MOV R3,#255D // 1mS delay
LABEL: DJNZ R3,LABEL
RET
LUT: DB 3FH
DB 06H
DB 5BH
DB 4FH
DB 66H
DB 6DH
DB 7DH
DB 07H
DB 7FH
DB 6FH
END
About the program.
The program is written so that, it keeps displaying the current value in register R6 on the three digit seven segment display. When
ever there is a valid negative going pulse (interrupt) at the INT0 pin, the program branches to the interrupt service routine (sub
routine ISR). Subroutine ISR increments the value in register R6, then jumps back to the MAIN loop and the display gets updated by
the new value.
Notes.
Entire circuit can be powered from a 5V DC supply.
LDR must be placed in an enclosure so that the light from LED alone falls on it.


This article is about interfacing a hex key pad to 8051 microcontroller. A clear knowledge on interfacing hex key pad to 8051 is very
essential while designing embedded system projects which requires character or numeric input or both. For example projects like
digital code lock, numeric calculator etc. Before going to the interfacing in detail, lets have a look at the hex keypad.
Hex keypad.
Hex key pad is essentially a collection of 16 keys arranged in the form of a 44 matrix. Hex key pad usually have keys representing
numerics 0 to 9 and characters A to F. The simplified diagram of a typical hex key pad is shown in the figure below.

Hex keypad
The hex keypad has 8 communication lines namely R1, R2, R3, R4, C1, C2, C3 and C4. R1 to R4 represents the four rows and C1 to
C4 represents the four columns. When a particular key is pressed the corresponding row and column to which the terminals of the
key are connected gets shorted. For example if key 1 is pressed row R1 and column C1 gets shorted and so on. The program identifies
which key is pressed by a method known as column scanning. In this method a particular row is kept low (other rows are kept high)
and the columns are checked for low. If a particular column is found low then that means that the key connected between that
column and the corresponding row (the row that is kept low) is been pressed. For example if row R1 is initially kept low and column
C1 is found low during scanning, that means key 1 is pressed.
Interfacing hex keypad to 8051.
The circuit diagram for demonstrating interfacing hex keypad to 8051 is shown below.Like previous 8051 projects, AT89S51 is the
microcontroller used here. The circuit will display the character/numeric pressed on a seven segment LED display. The circuit is
very simple and it uses only two ports of the microcontroller, one for the hex keypad and the other for the seven segment LED
display.

Interfacing hex keypad to 8051
The hex keypad is interfaced to port 1 and seven segment LED display is interfaced to port 0 of the microcontroller. Resistors R1 to
R8 limits the current through the corresponding segments of the LED display. Capacitors C1, C2 and crystal X1 completes the clock
circuitry for the microcontroller. Capacitor C3, resistor R9 and push button switch S1 forms a debouncing reset mechanism.
Program.
ORG 00H
MOV DPTR,#LUT // moves starting address of LUT to DPTR
MOV A,#11111111B // loads A with all 1's
MOV P0,#00000000B // initializes P0 as output port

BACK:MOV P1,#11111111B // loads P1 with all 1's
CLR P1.0 // makes row 1 low
JB P1.4,NEXT1 // checks whether column 1 is low and jumps to NEXT1 if not low
MOV A,#0D // loads a with 0D if column is low (that means key 1 is pressed)
ACALL DISPLAY // calls DISPLAY subroutine
NEXT1:JB P1.5,NEXT2 // checks whether column 2 is low and so on...
MOV A,#1D
ACALL DISPLAY
NEXT2:JB P1.6,NEXT3
MOV A,#2D
ACALL DISPLAY
NEXT3:JB P1.7,NEXT4
MOV A,#3D
ACALL DISPLAY
NEXT4:SETB P1.0
CLR P1.1
JB P1.4,NEXT5
MOV A,#4D
ACALL DISPLAY
NEXT5:JB P1.5,NEXT6
MOV A,#5D
ACALL DISPLAY
NEXT6:JB P1.6,NEXT7
MOV A,#6D
ACALL DISPLAY
NEXT7:JB P1.7,NEXT8
MOV A,#7D
ACALL DISPLAY
NEXT8:SETB P1.1
CLR P1.2
JB P1.4,NEXT9
MOV A,#8D
ACALL DISPLAY
NEXT9:JB P1.5,NEXT10
MOV A,#9D
ACALL DISPLAY
NEXT10:JB P1.6,NEXT11
MOV A,#10D
ACALL DISPLAY
NEXT11:JB P1.7,NEXT12
MOV A,#11D
ACALL DISPLAY
NEXT12:SETB P1.2
CLR P1.3
JB P1.4,NEXT13
MOV A,#12D
ACALL DISPLAY
NEXT13:JB P1.5,NEXT14
MOV A,#13D
ACALL DISPLAY
NEXT14:JB P1.6,NEXT15
MOV A,#14D
ACALL DISPLAY
NEXT15:JB P1.7,BACK
MOV A,#15D
ACALL DISPLAY
LJMP BACK

DISPLAY:MOVC A,@A+DPTR // gets digit drive pattern for the current key from LUT
MOV P0,A // puts corresponding digit drive pattern into P0
RET

LUT: DB 01100000B // Look up table starts here
DB 11011010B
DB 11110010B
DB 11101110B
DB 01100110B
DB 10110110B
DB 10111110B
DB 00111110B
DB 11100000B
DB 11111110B
DB 11110110B
DB 10011100B
DB 10011110B
DB 11111100B
DB 10001110B
DB 01111010B
END
About the program.
Firstly the program initializes port 0 as an output port by writing all 0s to it and port 1 as an input port by writing all 1s to it. Then
the program makes row 1 low by clearing P1.0 and scans the columns one by one for low using JB instruction.If column C1 is found
low, that means 1 is pressed and accumulator is loaded by zero and DISPLAY subroutine is called. The display subroutine adds the
content in A with the starting address of LUT stored in DPTR and loads A with the data to which the resultant address points (using
instruction MOVC A,@A+DPTR). The present data in A will be the digit drive pattern for the current key press and this pattern is
put to Port 0 for display. This way the program scans for each key one by one and puts it on the display if it is found to be pressed.
Notes.
The 5V DC power supply must be well regulated and filtered.
Column scanning is not the only method to identify the key press. You can use row scanning also. In row scanning a particular
column is kept low (other columns are kept high) and the rows are tested for low using a suitable branching instruction. If a
particular row is observed low then that means that the key connected between that row and the corresponding column (the
column that is kept low) is been pressed. For example if column C1 is initially kept low and row R1 is observed low during
scanning, that means key 1 is pressed.
A membrane type hex keypad was used during the testing. Push button switch type and dome switch type will also work. I
havent checked other types.
The display used was a common cathode seven segment LED display with type number ELK5613A. This is just for information
and any general purpose common cathode 7 segment LED display will work here.


A Note about 7 segment LED display.
This article is about how to interface a seven segment LED display to an 8051 microcontroller. 7 segment LED display is very
popular and it can display digits from 0 to 9 and quite a few characters like A, b, C, ., H, E, e, F, n, o,t,u,y, etc. Knowledge about how
to interface a seven segment display to a micro controller is very essential in designing embedded systems. A seven segment display
consists of seven LEDs arranged in the form of a squarish 8 slightly inclined to the right and a single LED as the dot character.
Different characters can be displayed by selectively glowing the required LED segments. Seven segment displays are of two
types,common cathode and common anode. In common cathode type , the cathode of all LEDs are tied together to a single
terminal which is usually labeled as com and the anode of all LEDs are left alone as individual pins labeled as a, b, c, d, e, f, g & h
(or dot) . In common anode type, the anode of all LEDs are tied together as a single terminal and cathodes are left alone as
individual pins. The pin out scheme and picture of a typical 7 segment LED display is shown in the image below.

7 segment LED display
Digit drive pattern.
Digit drive pattern of a seven segment LED display is simply the different logic combinations of its terminalsa to h in order to
display different digits and characters. The common digit drive patterns (0 to 9) of a seven segment display are shown in the table
below.
Digit a b c d e f g
0 1 1 1 1 1 1 0
1 0 1 1 0 0 0 0
2 1 1 0 1 1 0 1
3 1 1 1 1 0 0 1
4 0 1 1 0 0 1 1
5 1 0 1 1 0 1 1
6 1 0 1 1 1 1 1
7 1 1 1 0 0 0 0
8 1 1 1 1 1 1 1
9 1 1 1 1 0 1 1
Interfacing seven segment display to 8051.

Interfacing 7 segment display to 8051
The circuit diagram shown above is of an AT89S51 microcontroller based 0 to 9 counter which has a 7 segment LED display
interfaced to it in order to display the count. This simple circuit illustrates two things. How to setup simple 0 to 9 up counter using
8051 and more importantly how to interface a seven segment LED display to 8051 in order to display a particular result. The
common cathode seven segment display D1 is connected to the Port 1 of the microcontroller (AT89S51) as shown in the circuit
diagram. R3 to R10 are current limiting resistors. S3 is the reset switch and R2,C3 forms a debouncing circuitry. C1, C2 and X1 are
related to the clock circuit. The software part of the project has to do the following tasks.
Form a 0 to 9 counter with a predetermined delay (around 1/2 second here).
Convert the current count into digit drive pattern.
Put the current digit drive pattern into a port for displaying.
All the above said tasks are accomplished by the program given below.
Program.
ORG 000H //initial starting address
START: MOV A,#00001001B // initial value of accumulator
MOV B,A
MOV R0,#0AH //Register R0 initialized as counter which counts from 10 to 0
LABEL: MOV A,B
INC A
MOV B,A
MOVC A,@A+PC // adds the byte in A to the program counters address
MOV P1,A
ACALL DELAY // calls the delay of the timer
DEC R0//Counter R0 decremented by 1
MOV A,R0 // R0 moved to accumulator to check if it is zero in next instruction.
JZ START //Checks accumulator for zero and jumps to START. Done to check if counting has been
finished.
SJMP LABEL
DB 3FH // digit drive pattern for 0
DB 06H // digit drive pattern for 1
DB 5BH // digit drive pattern for 2
DB 4FH // digit drive pattern for 3
DB 66H // digit drive pattern for 4
DB 6DH // digit drive pattern for 5
DB 7DH // digit drive pattern for 6
DB 07H // digit drive pattern for 7
DB 7FH // digit drive pattern for 8
DB 6FH // digit drive pattern for 9
DELAY: MOV R4,#05H // subroutine for delay
WAIT1: MOV R3,#00H
WAIT2: MOV R2,#00H
WAIT3: DJNZ R2,WAIT3
DJNZ R3,WAIT2
DJNZ R4,WAIT1
RET
END
About the program.
Instruction MOVC A,@A+PC is the instruction that produces the required digit drive pattern for the display. Execution of this
instruction will add the value in the accumulator A with the content of the program counter(address of the next instruction) and will
move the data present in the resultant address to A. After this the program resumes from the line after MOVC A,@A+PC.
In the program, initial value in A is 00001001B. Execution of MOVC A,@A+PC will add oooo1001B to the content in PC ( address
of next instruction). The result will be the address of label DB 3FH (line15) and the data present in this address ie 3FH (digit drive
pattern for 0) gets moved into the accumulator. Moving this pattern in the accumulator to Port 1 will display 0 which is the first
count.
At the next count, value in A will advance to 00001010 and after the execution of MOVC A,@+PC ,the value in A will be 06H which
is the digit drive pattern for 1 and this will display 1 which is the next count and this cycle gets repeated for subsequent counts.
The reason why accumulator is loaded with 00001001B (9 in decimal) initially is that the instructions from line 9 to line 15
consumes 9 bytes in total.
The lines 15 to 24 in the program which starts with label DB can be called as a Look Up Table (LUT). label DB is known as Define
Byte which defines a byte. This table defines the digit drive patterns for 7 segment display as bytes (in hex format). MOVC operator
fetches the byte from this table based on the result of adding PC and contents in the accumulator.
Register B is used as a temporary storage of the initial value of the accumulator and the subsequent increments made to accumulator
to fetch each digit drive pattern one by one from the look up table(LUT).
Note:- In line 6, Accumulator is incremented by 1 each time (each loop iteration) to select the next digit drive pattern. Since MOVC
operator uses the value in A to fetch the digit drive pattern from LUT, value in ACC has to be incremented/manipulated accordingly.
The digit drive patterns are arranged consecutively in LUT.
Register R0 is used as a counter which counts from 10 down to 0. This ensures that digits from o to 9 are continuously displayed in
the 7 segment LED. You may note lines 4, 11, 12, and 13 in the above program. Line 4 initializes R0 to 10 (OAh). When the program
counter reaches line 11 for the first time, 7 segment LED has already displayed 0. So we can reduce one count and that is why we
have written DEC Ro. We need to continuously check if R0 has reached full count (that is 0). In order to do that lines 12 and 13 are
used. We move R0 to accumulator and then use the Jump if Zero (JZ) instruction to check if accumulator has reached zero. If Acc=0,
then we makes the program to jump to START (initial state) and hence we restart the 7 segment LED to display from 0 to 9 again. If
Acc not equal to zero, we continue the program to display the next digit (check line 14).
Multiplexing 7 segment display to 8051.
Suppose you need a three digit display connected to the 8051. Each 7 segment display have 8 pins and so a total amount of 24 pins
are to the connected to the microcontroller and there will be only 8 pins left with the microcontroller for other input output
applications. Also the maximum number of displays that can be connected to the 8051 is limited to 4 because 8051 has only 4 ports.
More over three 3 displays will be ON always and this consumes a considerable amount of power. All these problems associated with
the straight forward method can be solved by multiplexing .
In multiplexing all displays are connected in parallel to one port and only one display is allowed to turn ON at a time, for a short
period. This cycle is repeated for at a fast rate and due to the persistence of vision of human eye, all digits seems to glow. The main
advantages of this method are
Fewer number of port pins are required .
Consumes less power.
More number of display units can be interfaced (maximum 24).
The circuit diagram for multiplexing 2 seven segment displays to the 8051 is shown below.

Multiplexing 7 segement display to 8051
When assembled and powered on, the circuit will display the number 16 and let us see how it is done. Initially the first display is
activated by making P3.0 high and then digit drive pattern for 1 is loaded to the Port 1. This will make the first display to show
1. In the mean time P3.1 will be low and so do the second display will be OFF. This condition is maintained for around 1ms and
then P3.0 is made low. Now both displays will be OFF. Then the second display is activated by making P3.1 high and then the digit
drive pattern for 6 is loaded to the port 1. This will make the second display to show 6. In the mean time P3.0 will be low and so
the second display will be OFF. This condition is maintained for another 1ms and then port 3.1 is made low. This cycle is repeated
and due to the persistence of vision you will feel it as 16.
Transistor Q1 drives the first display (D1) and transistor Q2 drives the second display (D2). R11 and R12 are the base current limiting
resistors of Q1 and Q2. The purpose of other components are explained in the first circuit.
Program.
ORG 000H // initial starting address
MOV P1,#00000000B // clears port 1
MOV R6,#1H // stores "1"
MOV R7,#6H // stores "6"
MOV P3,#00000000B // clears port 3
MOV DPTR,#LABEL1 // loads the adress of line 29 to DPTR
MAIN: MOV A,R6 // "1" is moved to accumulator
SETB P3.0 // activates 1st display
ACALL DISPLAY // calls the display sub routine for getting the pattern for "1"
MOV P1,A // moves the pattern for "1" into port 1
ACALL DELAY // calls the 1ms delay
CLR P3.0 // deactivates the 1st display
MOV A,R7 // "2" is moved to accumulator
SETB P3.1 // activates 2nd display
ACALL DISPLAY // calls the display sub routine for getting the pattern for "2"
MOV P1,A // moves the pattern for "2" into port 1
ACALL DELAY // calls the 1ms delay
CLR P3.1 // deactivates the 2nd display
SJMP MAIN // jumps back to main and cycle is repeated
DELAY: MOV R3,#02H
DEL1: MOV R2,#0FAH
DEL2: DJNZ R2,DEL2
DJNZ R3,DEL1
RET
DISPLAY: MOVC A,@A+DPTR // adds the byte in A to the address in DPTR and loads A with data
present in the resultant address
RET
LABEL1:DB 3FH
DB 06H
DB 5BH
DB 4FH
DB 66H
DB 6DH
DB 7DH
DB 07H
DB 7FH
DB 6FH
END


Interrupt sources
In an 8051 micro controller there are 2 external interrupts, 2 timer interrupts, and 1 serial interrupt. External interrupts are
external interrupt 0(INT0) and external interrupt 1 (INT1). Timer interrupts are Timer 0 interrupt and Timer 1 interrupt. A serial
interrupt is given for serial communication with the micro controller (transmit and receive) .
All these four interrupts, when evoked serves or executes a particular set of predefined activities known asInterrupt Service
Routines. Its way of functioning is similar to the subroutines we write while developing a complete program. In the case of
8051, the interrupt service routines(ISR) of each interrupt must begin from a corresponding address in the program memory. This
address from which an ISR begins is called the vector address of the interrupt.
Interrupt Source Vector address Interrupt priority
External Interrupt 0 INT0 0003H 1
Timer 0 Interrupt 000BH 2
External Interrupt 1 INT1 0013H 3
Timer 1 Interrupt 001BH 4
Serial Interrupt 0023H 5
Interrupt Priority
All the 5 interrupts of 8051 has got different priorities. Interrupts are serviced according to its priority order. From the table above,
you can see that INT0 has the highest priority of 1 and Timer 0 comes next with priority value 2. The order of priority works like this
consider a case where two interrupts are raised at the same time one from INT0 and another from Timer 1 interrupt. Now which
one would be served first? In such a case, processor would serve the interrupt according to its priority. In our case INT0 is of high
priority (priority order 1)and Timer 1 interrupt is of low priority (priority order 4). So processor will execute ISR of INTO first and
then later,after finishing ISR of INT0, processor will begin executing ISR of Timer 1 interrupt.

From the figure above, you may note that INTO is an alternate function P3.2 and INT1 is an alternate function of P3.3. A signal
received at these pins will evoke the interrupts accordingly. But not all signals will evoke the interrupt! The signal received at pins
should be either a low level one or it should be a falling edge signal to evoke the corresponding interrupt. However to serve the
interrupt upon receiving the signal at pins, the man who programs 8051 should preprocess a few bits 3 SFRs namely TCON, IE and
IP. Lets examine them.
TCON

TCON is a bit addressable SFR. Out of the 8 bits, only the lower 4 bits are concerned with external interrupts. The upper 4 bits deals
with interrupts from Timers. The lower four bits are TCON.0 (IT0), TCON.1 (IE0), TCON.2 (IT1) and TCON.3 (IE1). You can refer
the figure given below for a better understanding. Out of these 4 bits, bits 0 and 1 that means TCON.0 and TCON.1 are
concerned with external interrupt 0 (INT0), where as bits 2 and 3 TCON.2 and TCON.3 are concerned with external interrupt 1
(INT1). Out of these bits only TCON.0 and TCON.2 are directly manipulated by the programmer while dealing with an external
interrupt. Bits TCON.1 (IE0) and TCON.3 (IE1) are manipulated by the processor itself. An external signal received at INTO would
set the bit TCON.1 (also known as IE0) and will be cleared by the processor itself, after it branches to the corresponding ISR located
at 0003H. Similarly TCON.3 is set when an interrupt signal is received at INT1 and would be cleared by processor after
branching. The other 2 bits TCON.0 and TCON.2 are used for selecting type of signal received.
TCON.0 (or IT0) is set to 0 if the interrupt at INT0 is to be evoked by a low level signal. If TCON.0 is set to high, then the interrupt
at INT0 would be evoked by a falling edge signal (high to low transition). Same is the case with TCON.1 if set to 0 then low level
signal would raise an interrupt at INT1 and if set to high, then a falling edge signal would do the job.
IE (Interrupt Enable)

There are 3 bits associated with external interrupts in IE they are bits 0,2 and 7. The main purpose of this SFR is to enable/disable
different interrupts based on whether its corresponding bits are set or not. Refer the figure below.
IE.7 is known as global interrupt bit which when set to 0 disables all kinds of interrupts in 8051. Only if this bit is set to 1,
any kind of interrupt would be enabled in 8051. If this bit is set to 1, programmer can then individually enable or disable all other
interrupts INT0, INT1, Timer interrupts (0 and 1) and serial interrupt.
IE.0 If set to 1 it enables INT0 and if set to 0 INT0 would be disabled. So in order to enable external interrupt 0 (INT0)
IE.7 and IE.0 should be set to 1.
IE.2 Similar to IE.0 IE.1 enables/disables external interrupt 1 (INT1).
Interrupt Priority (IP)

Basic function of this SFR is to set interrupt priority (IP). By default INT0 is of priority value 1 (which is the highest) and INT1 is of
priority value 3 (which is lower than INT0). The programmer can alter this priority, if he wants! If IP.0 is set to 0 and then IP.2 is
set to 0 then the priority order changes. INT1 will change to high priority and INT0 will change to lower priority compared to
INT1.
How to write an ISR (Interrupt Service Routine)
An ISR is just like any other subroutine we write inside a program, except for the difference that an ISR must always end with
a RETI instruction and not with a RET instruction (as in the case of subroutines). An ISR when evoked, executes a certain lines of
code that does some kind of operations. It can be anything as defined by the programmer. The only condition is that the first line of
ISR must begin from the corresponding vector address. Vector address of INT0 is 0003H and that of INT1 is 0013H.
Note: In some cases the ISR will be too long that it wont be practical to write all codes staring from 0003H or the other vector
address. In such cases, ISR can be placed at any other location in program memory and programmer must provide an unconditional
jump to the starting address of ISR from the corresponding vector address. Example:- The ISR of INT0 has been written from
location 2000H. Now programmer must place an instruction LJMP 2000H at the vector address of INT0 0003H.
Note:- Whenever an evoked interrupt is acknowledged and the processor branches to its corresponding vector address, it
automatically disables the interrupt in IE register. This disabled interrupt would only be re-enabled upon executing
the RETI instruction placed inside the ISR. That is the single reason, a programmer must use RETI inside an ISR
instead of RET instruction. Placing RET will also do the job of returning from interrupt routine to main program (the calling
program) but the RET instruction will not re-enable the disabled interrupt in IE register. So if an RET is used, the interrupt would be
permanently disabled after its first serving of ISR (unless it is enabled again by the programmer at some other part of the same
program).
So in order to write an ISR for INT0, you have to keep in mind the following things:-
1) Place the ISR for INT0 beginning from its vector address 0003H. If the ISR is too long, place an unconditional jump from
0003H to the starting address of ISR (which is placed at some other location of program memory). The ISR must end with a
RETI instruction.
2) Select the triggering signal type of interrupt by setting/clearing TCON.0 bit. TCON.0=1 means interrupt would be triggered by a
falling edge signal. TCON.0 =0 means interrupt would be triggered by a low level signal.
3)Set IE.0 =1 to enable the external interrupt 0 (INT0)
4)Set IE.7=1 to enable the global interrupt control bit.
5) Optionally, programmer can alter the priority of INT0 by setting/clearing IP.0 (Note: This step is optional.)
Now when it comes to external interrupt 1 INT1 the processes are all same, except for the change in bits that are to be
programmed.
1) Place the ISR in vector address of INT1 0013H. Or if the ISR is long, place an LJMP at 0013H to the corresponding starting
address of ISR for INT1.
2)Triggering signal type is selected by setting/clearing TCON.2. TCON.2 = 0 triggered by low level signal. TCON.2 = 1 triggered
by falling edge signal.
3)Set IE.2 = 1 to enable INT1
4) Set IE.7 =1 to enable global interrupt control bit.
5) Interrupt priority can be altered by changing value of IP.2 (optional). Refer the diagram of IP register given above.
How to generate Software Interrupts in 8051?
Software interrupts are nothing but an interrupt generated by a program inside the controller. To generate an external interrupt, we
need a signal input either at INT0 or INT1 pin of the 8051 micro controller. We have seen that, when an interrupt signal is received
at the INTo pin, the TCON.1 bit would automatically get set and that is how the processor knows an interrupt signal has been
received at INT0 pin. When TCON.1 is set, processor would immediately acknowledge the interrupt and branch to the corresponding
ISR of INT0. While branching to the ISR, processor would also clear the TCON.1 bit. The same happens in the case of INT1 and the
associated bit is TCON.3.
Now in order to generate a software interrupt, the programmer can manipulate these bits TCON.1 and TCON.3
manually inside a program. An instruction like SETB TCON.1 will activate the interrupt for INT0 (without any external
signal at the INT0 pin) inside the controller. Now the processor will acknowledge the interrupt and branch to the corresponding
location of ISR for INT0 (vector address 0003H). After branching to ISR, the processor would clear the bit TCON.1. An instruction
like SETB TCON.3 would activate the interrupt for INT1 and processor would branch to ISR of INT1 located at vector address
0013H. While branching it would automatically clear the bit TCON.3, so that the programmer can activate the interrupt again inside
a loop or some other part of the program.
Example Program:-
Previously,we have developed a circuit to toggle two LEDs with a single push button switch in 8051. It has been developed for
educational purpose.
1) To learn how to interface LEDs to 8051
2) How to use push button switch to manipulate output status of LEDs
3) How to use interrupt and develop an ISR for 8051.

You can see the circuit and article here
This article is all about how to interface push button switches to an 8051 microcontroller. Push button switches are widely used in
embedded system projects and the knowledge about interfacing them to 8051 is very essential in designing such projects. A typical
push button switch has two active terminals that are normally open and these two terminals get internally shorted when the push
button is depressed. Images of a typical pushbutton switch is shown below.

Pushbutton switch
Circuit diagram.

Interfacng 8051 and pushbutton
The circuit diagram for interfacing push button switch to 8051 is shown above. AT89S51 is the microcontroller used here. The
circuit is so designed that when push button S1 is depressed the LED D1 goes ON and remains ON until push button switch S2 is
depressed and this cycle can be repeated. Resistor R3, capacitor C3 and push button S3 forms the reset circuitry for the
microcontroller. Capacitor C1, C2 and crystal X1 belongs to the clock circuitry. R1 and R2 are pull up resistors for the push buttons.
R4 is the current limiting resistor for LED.
Program.
MOV P0,#83H // Initializing push button switches and initializing LED in OFF state.
READSW: MOV A,P0 // Moving the port value to Accumulator.
RRC A // Checking the vale of Port 0 to know if switch 1 is ON or not
JC NXT // If switch 1 is OFF then jump to NXT to check if switch 2 is ON
CLR P0.7 // Turn ON LED because Switch 1 is ON
SJMP READSW // Read switch status again.
NXT: RRC A // Checking the value of Port 0 to know if switch 2 is ON or not
JC READSW // Jumping to READSW to check status of switch 1 again (provided switch 2 is OFF)
SETB P0.7 // Turning OFF LED because Switch 2 is ON
SJMP READSW // Jumping to READSW to read status of switch 1 again.
END

The Logic
The first instruction MOV P0 #83H - is to turn LED off (Hex 83 in binary = 10000011) and to initialize switches 1 and 2. Switch
1 is connected to port 0.0 and switch 2 is connected to port 0.1. Also note that LED is connected to port 0.7.
Note:- Po.0 = 1 means switch 1 is OFF and Po.1 = 1 means switch 2 is OFF. P0.0 = o means switch 1 is ON and p0.1 = o means
switch 2 is ON. LED turns ON when P0.7 = 0 and turns OFF when P0.7 = 1
The program has two labels READSW and NXT. Its all about reading switch values that is P0.0 and P0.1. We are using RRC
instruction to read switch values. The values of port 0 is moved to accumulator. Since port 0 and 1 are used to interface switches 1
and 2, we can get the values of both port bits in LSBs 0 and 1 of accumulator by using MOV A,P0 instruction. RRC means rotate
right through carry. You can learn more about this instruction here 8051 programming tutorial 1 . What RRC do is simple it
will move value of port 0.0 to the carry bit. Now we can check the carry bit using instruction JC which means jump if carry is set .
If carry is SET then it means port0.0 =1 and this means switch 1 is OFF. If switch 1 is OFF then we have to check status of switch 2
and that is why we jump to label NXT.
In the mean time if switch 1 is pressed then value of port 0.0 will be equal to zero. This will get moved to accumulator and hence
an RRC will result in carry bit = o. If carry bit = 0 then result of executing JC instruction is negative and it will not jump. The next
instruction will get executed that is CLR P0.7. This clears port 0.7 to zero and hence LED will turn ON. Once turned On- LED will
be kept On until switch 2 is pressed.
The status of switch 2 is checked in NXT label. When NXT is executed, we are using RRC for the second time consecutively. This
means, the carry bit now holds the value of P0.1 which is status of switch 2. If carry bit = 1 then switch 2 is OFF. This means LED
should not be turned OFF. If carry bit = 0 then LED should be turned OFF (The instruction SETB P0.7 turns LED OFF)

Toggling 2 LED with a pushbutton using interrupt.
This circuit demonstrates how to toggle two LEDs with a single push button using the external interrupts. Interrupt is an
asynchronous signal (either hardware or software) which indicates the processor to make a change in current execution. When the
processor receives a valid interrupt signal it saves the current state and then goes to execute a set of predefined steps called
interrupt service routine (ISR). After executing ISR, the processor goes back to the point where it deviated and continues from
there. To learn more about interrupts check this link. External interrupt handling in 8051.
Circuit diagram.

Toggling LED using 8051 with interrupt
In the circuit shown above D1, D2 (the LEDs to be toggled) are connected to P1.0 and P1.1 respectively. R2 and R4 limits the
current through the LEDs. The push button switch S2 is connected to the INT0 pin where R1 is a pull up resistor and C4 is the
debouncing capacitor. C3, R3 and S3 forms the reset circuitry. Capacitors C2, C2 and crystal X1 are related to the clock
circuitry. When powered ON LED D1 will be OFF and and LED D2 will be ON. Whenever push button switch S2 is pressed it creates
an interrupt and the software makes the status of P1.o and P1.1 to toggle which gets reflected in the LEDs.
Program.
ORG 000H // starting address
SJMP LABEL //jumps to the LABEL
ORG 003H // starting address for the ISR(INT0)
ACALL ISR // calls the ISR (interrupt service routine)
RETI // returns from the interrupt
LABEL: MOV A,#10000000B // sets the initial stage of the LEDs (D1 OFF & D2 ON)
MAIN: // main function that sets the interrupt parameters
SETB IP.0 // sets highest priority for the interrupt INT0
SETB TCON.0 // interrupt generated by a falling edge signal at INT0 (pin12)
SETB IE.0 // enables the external interrupt
SETB IE.7 // enables the global interrupt control
SJMP MAIN // jumps back to the MAIN subroutine
ISR: // interrupt service routine
CPL A // complements the current value in accumulator A
MOV P1,A // moves the current accumulator value to port 1
RET // jumps to RETI
END
If you come across any doubts/errors while implementing this circuit, please feel free to ask in our comments section.

S-ar putea să vă placă și