Você está na página 1de 12

This tutorial is downloaded from https://sites.google.

com/site/enggprojectece

Introduction to Embedded C for 8051 and Implementation of Timer and


Interrupt Handling
Compiled by: Sivaranjan Goswami, Pursuing M. Tech. (2013-15 batch)
Dept. of ECE, Gauhati University, Guwahati, India
Contact: sivgos@gmail.com

Note: It is a practical guide in which it is presumed that the reader has already learned about the
hardware architecture, programming model, and assembly language programming of 8051
microcontroller. In case you are totally new to 8051 microcontroller I recommend you to read the
8051 Tutorial available at:
https://sites.google.com/site/enggprojectece/my-reading-list
It has also been presumed that the reader has at least the beginner level knowledge of computer
programming in C language (user defined functions, data types, header files, loops and the flow of a C
program).
In this tutorial first an introduction to Embedded C is given. A few examples are shown. Then the
implementation of timer and interrupt are discussed.
(All programs shown here are compiled and executed using Keil Vision 3)
Pin Diagram of 8051
(please note the pins used for external interrupts INT0 & INT1, Serial Port Transmitter TxD,
Serial Port Receiver RxD, Counter input for Timer-0 T0 and Counter input for Timer-1 T1)

This tutorial is downloaded from https://sites.google.com/site/enggprojectece

Embedded C
The syntax of embedded C is the same as the C language that we use for writing computer programs.
The only difference is the libraries and hence the functions. Particularly for 8051 based
microcontrollers, the header file <REGX51.H> has to be added. In this header file the addresses of all
the special function registers (SFRs) and other memory locations are defined. Hence we can access an
SFR by simply writing its name. We dont need to use the registers of the programming model (A, B,
R0, R1, R2, , R7) because when the compiler compiles the compiles the C program, it actually
converts the program into an equivalent assembly language program. In this process the compiler
itself uses the registers in an optimized manner to represent the variables that we define in the C
program.
Lets see a simple program to blink an LED at a fixed interval.
#include <REGX51.H>
sbit x=P0^0; //x is defined as a binary variable to represent bit-0 of
// port P0
void delay() //delay program
{
int i,j;
for(i=0;i<1000;i++)
for(j=0;j<1000;j++);
}
void main()
{
x=0; //This will define P0^0 as an output port.
while(1)
{
x=!x;
delay();
}
}

In the program we can see that the delay is achieved by running two nested empty loops to achieve
some fixed delay. It is assumed that the LED is connected to the bit 0 of port P0 (P0.0).
It is totally inconvenient to know the exact duration of the delay as we dont know what assembly
code is generated by the compiler to implement this C code. It may vary from compiler to compiler.
Even if we know, it requires lots of calculations. Another drawback is that the achieved delay must be
an integral multiple of the time required to execute one empty for-loop used in the program.

The Super-Loop (while(1) with no break statement)


If you are familiar with computer programming using C language you must know that the main()
function of a computer program must end with a return statement. But it is not same for embedded C.
A computer program, after its execution, must return the control to the operating system. But a simple
embedded system doesnt have an operating system. The single program that we write controls the
embedded system entirely. So we must write the body of the main program (excluding the variable
declarations and initializations) inside a super-loop (or infinite loop) as shown in the above example

This tutorial is downloaded from https://sites.google.com/site/enggprojectece


so that the program keeps on running until it is reset or turned off by a user. If the chip is the main()
function will start from the beginning and do all the variable declarations and initializations again.
If the embedded system you want to design is intended to perform a single task and then stop until it
is restarted (or reset) an empty super-loop should be written at the end.
while(1);
It is equivalent to assembly (8051) mnemonics:
loop: jmp loop;
or
jmp $;
This is required because if some values are stored in the program memory after the last line of the
program, the microcontroller will treat them as some opcodes and attempt to execute them. It can
cause some really unexpected run-time error as we are not aware of what values are stored and their
equivalent instructions.

Event Counter using Embedded C


Let us now look at another program. Here the aim is to count the number of times an event occurs.
Whenever the event occurs, the pin P0.0 is reset. It remains reset as the event is occurring and it is set
again as the event has occurred. In other words a negative wire is connected from an external source
to the pin P0.0 of the microcontroller. The aim of the program is to keep track of the number of times
the wire feeds a logic zero to the microcontroller. Here the program goes:
#include <REGX51.H>
sbit b=P0^0;
void main()
{
int x=0;
P1=0x00;
while(1)
{
if(b==0)
{
x++;
while(b==0); //Wait until b is set again
}
P1=x; //send result to port 1
}
}

As we can see the entire processor remains busy in keeping track of whether the selected bit is set or
reset. We cannot risk including some additional task into the program because it may lead to miss
some event when it is busy in executing additional tasks.

This tutorial is downloaded from https://sites.google.com/site/enggprojectece

Timer and Interrupt


We have discussed how delay and counter can be implemented in a conventional embedded C
program and also discussed their limitations. Now we will see how we can implement the same things
using timer and interrupt. First we will discuss the timers and interrupts of 8051 microcontroller and
their operation and control. Then we will see their implementation in a program.
Interrupt and Timer are two very important tools which are provided by any microcontroller. They
can help us to make our programs more efficient and smarter. Like many other microcontrollers in
8051 also we can manage and use them by adjusting the values of some pre-defined Special Function
Registers (SFRs). In the theory and lab classes of 8051 microcontrollers, these topics are covered in
details and students are also taught to write Assembly Language Programs to control timer and
interrupt.
If you are not familiar with timers and interrupts, please refer to the 8051 tutorial available in the page
mentioned at the beginning of this tutorial. Here we will cover only the SFRs involved with timer and
interrupt along with the functions of their bits.

Timers of 8051 Microcontroller:


The 8051 comes equipped with two timers, both of which may be controlled, set, read, and configured
individually. The 8051 timers have three general functions:
(1) Keeping time and/or calculating the amount of time between events,
(2) Counting the events themselves
(3) Generating baud rates for the serial port. (beyond the scope of this tutorial you may go
through serial port of 8051 for further details)
There are two 16-bit timers (Timer0 and Timer1) in 8051. Both the timer counts up. (In some
microcontrollers we can program the timer registers to move up or down, some varieties of 8051 also
includes this feature, but in general the timers of 8051 only counts up hence we consider the general
case only)
How long a Timer does take to Count?
First, its worth mentioning that when a timer is in interval timer mode (as opposed to event counter
mode) and correctly configured, it will increment by 1 every machine cycle. A machine cycle in 8051
contains 12 clock pulses. The crystal oscillator usually used in 8051 is of frequency 11.059 MHz
(11059000 Hz).
Thus time required by the counter to count is:
1,10,59,000/12 = 9,21,583 times per second. (Or once in every 1.085 s).

This tutorial is downloaded from https://sites.google.com/site/enggprojectece


SFRs associated with the Timers of 8051 microcontroller:

TCON and TMOD registers are used for controlling the two timers. TH0 and TL0 jointly store the
current 16-bit (2 bytes) value of Timer 0. Similarly, TH1 and TL1 store the current value of Timer 1.
If we initialize the Timer register with some value then it will start counting up from that value. In this
way we can make the timer to reach its maximum value at the required instant of time. After reaching
this maximum value the timer will overflow, that is, it will start from zero (0000h).
TMOD Register
Bit
7

Name
GATE1

C/T1

5
4
3

T1M1
T1M0
GATE0

C/T2

1
0

T0M1
T0M0

Description
When this bit is set the timer will only run when INT1 (P3.3) is high.
When this bit is clear the timer will run regardless of the state of
INT1.
When this bit is set the timer will count events on T1 (P3.5). When
this bit is clear the timer will be incremented every machine cycle.
Mode select for Timer 1
When this bit is set the timer will only run when INT0 (P3.2) is high.
When this bit is clear the timer will run regardless of the state of
INT0.
When this bit is set the timer will count events on T0 (P3.4). When
this bit is clear the timer will be incremented every machine cycle.
Mode select for Timer 0

Timer
1

1
1
1
0

0
0
0

Modes of Timer 0 and Timer 1


TxM1
0
0
1
1

TxM0
0
1
0
1

Timer Mode
Mode 0
Mode 1
Mode 2
Mode 3

Description of Mode
13 - bit timer (0000h to 1FFFh)
16 - bit timer (0000h to FFFFh)
8 - bit (00h to FFh) auto reload
Split Timer Mode

*x can be either 0 or 1.
(Read the concepts of auto-reload and split timer from the 8051 Tutorial mentioned above or some
book)

This tutorial is downloaded from https://sites.google.com/site/enggprojectece


TCON Register:

As you may notice, weve only defined 4 of the 8 bits. Thats because the other 4 bits of the SFR dont have
anything to do with timers they have to do with Interrupts and they will be discussed in the chapter that
addresses interrupts.

Generation of Baud Rate for Serial Port:


Timer-1 can be used for generating baud rate for serial communication. To explain the operation a brief
discussion of the serial port of 8051 microcontroller is given. The serial communication of 8051 microcontroller
is done through pins P3.0 (serial input port) and P3.1 (serial output port). The serial communication is controlled
by the SFR SCON. The various bits of the SCON SFR and their descriptions are given in the following table:

Table: Bits of SCON Register


Bit Name
0
SM0
1
SM1
2
SM2
3
REN
4
TB8
5
RB8
6
TI
7
RI

Bit Address
9Fh
9Eh
9Dh
9Ch
9Bh
9Ah
99h
98h

Description
Serial port mode bit 0
Serial port mode bit 1
Multiprocessor communication enable
Receive Enable. This bit must be set to receive characters.
Transmit Bit 8. The 9th bit to transmit in mode 2 and mode 3
Receive Bit 8. The 9th bit to receive in mode 2 and mode 3
Transmit Flag. Set when a byte has been completely transmitted
Receive Flag. Set when a byte has been completely received

Interrupts of 8051 Microcontroller:


Program flow is always sequential, being altered only by those instructions which expressly cause
program flow to deviate in some way. However, interrupts give us a mechanism to "put on hold" the
normal program flow, execute a subroutine, and then resume normal program flow as if we had never
left it. This subroutine, called an interrupt handler, is only executed when a certain event (interrupt)
occurs. The event may be one of the timers "overflowing," receiving a character via the serial port,
transmitting a character via the serial port, or one of two "external events." The 8051 may be
configured so that when any of these events occur the main program is temporarily suspended and
control passed to a special section of code which presumably would execute some function related to
the event that occurred. Once complete, control would be returned to the original program. The main
program never even knows it was interrupted.

This tutorial is downloaded from https://sites.google.com/site/enggprojectece


We can configure the 8051 so that any of the following events will cause an interrupt:

Timer 0 Overflow.
Timer 1 Overflow.
Reception/Transmission of Serial Character.
External Event 0.
External Event 1.

We need to be able to distinguish between various interrupts and executing different code depending
on what interrupt was triggered. This is accomplished by jumping to a fixed address (known as
interrupt vector) when a given interrupt occurs. These addresses are stored in a inbuilt table inside the
microcontroller called interrupt vector table.

The Interrupt Vector Table of 8051 Microcontroller


(In order of polling sequence)

The SFRs used for setting and controlling interrupts in 8051 are:
1. Interrupt Enable (IE) SFR: Address 0A8h
2. Interrupt Priority (IP) SFR: Address 0B8h
3. Lower 4 bits of the TCON SFR for external interrupt control
IE SFR
Bit
7
6
5
4
3
2
1
0

Name
EA
ES
ET1
EX1
ET0
EX0

Bit Address
AFh
AEh
ADh
Ach
ABh
AAh
A9h
A8h

Description
Global Interrupt Enable/Disable
Undefined
Undefined
Enable Serial Interrupt
Enable Timer 1 Interrupt
Enable External 1 Interrupt
Enable Timer 0 Interrupt
Enable External 0 Interrupt

Interrupt Priority
When more than one interrupts are enabled, it is necessary to set priority of interrupts. The priority of
an interrupt can be high or low. A high priority interrupt can interrupt the service routine of a low
priority interrupt.

This tutorial is downloaded from https://sites.google.com/site/enggprojectece


For example, you may have enabled Timer 1 Interrupt which is automatically called every time Timer
1 overflows. Additionally, you may have enabled the Serial Interrupt which is called every time a
character is received via the serial port. However, you may consider that receiving a character is much
more important than the timer interrupt. In this case, if Timer 1 Interrupt is already executing you may
wish that the serial interrupt itself interrupts the Timer 1 Interrupt. When the serial interrupt is
complete, control passes back to Timer 1 Interrupt and finally back to the main program. You may
accomplish this by assigning a high priority to the Serial Interrupt and a low priority to the Timer 1
Interrupt.
IP SFR

Lower 4 bits of TCON for External Interrupt


It has already been said that the lower 4 bits of TCON are used for interrupt handling in 8051. The
following figure shows the use of these four bits.

So use of these bits can give more sophisticated control over external interrupt which may of use for
certain applications. However, we dont use these bits in our examples.

This tutorial is downloaded from https://sites.google.com/site/enggprojectece

8051 Embedded C Example 1


Aim: To write a program to blink an LED after every 0.5 second using timer. Assume that a 12 MHz
crystal is used generate clock pulses the 8051 microcontroller.
Calculation of Timer Value:
Clock frequency = 12 MHz = 12,000,000 Hz
Time required for 1 clock pulse = 1/12,000,0000 sec
1 machine cycle = 12 clock pulses
Hence, time required for 1 machine cycle = 12 x 1/12,000,000 sec = 10 6 sec
In other words,
Machine cycles in 10 6 sec = 1
Machine cycles 0.5 sec = 0.5 x 106 = 500,000
A 16-bit timer can count from 0000h to FFFFh, i.e., 0 to 65,535.
Let us start the timer from (65,535 50,000) = 15,535 = 3CAFh so that it overflows after 50,000
steps.
We need to run the timer 10 times to make it 500,000.
Calculation of SFR Values:
Let us use timer 0 as 16-bit timer. Here we are using the timers to keep time. As the timer will be used
as 16-bit mode (Mode 1) we need to specify this to TMOD register
TMOD = 0000 0001 b = 1
Here goes the program:
#include <REGX51.H>
sbit x=P0^0; //set x as the bit 0 of P0 where the LED is connected
void main()
{
int count=0;
x=0;
TMOD=1;
TH0=0x3c;
TL0=0xaf; //separately initialize TH0 & TL0
TR0=1;
while(1)
{
while(!TF0); //wait until TF bit is set
TF0=0;
count++;//when timer overflows we increment the counter
TH0=0x3c;
TL0=0xaf; //Initialize every time so that we get 0.5 sec
TR0=1; //Start the timer again

This tutorial is downloaded from https://sites.google.com/site/enggprojectece


if(count==10)
{
count=0;
x=!x;
}
}
}

This tutorial is downloaded from https://sites.google.com/site/enggprojectece

8051 Embedded C Example 2


Aim: Write a program to read port 0 when an external interrupt occurs. After 2 second of reading,
display double of the value in port 1.
Steps:
1.
2.
3.
4.

When external interrupt occurs, read the present value of port 0 and disable the interrupt.
Start timer to calculate 2 second elapse (calculation of time shown below).
Multiply the value with 2.
When 2 seconds are over, display the result at port 1 and enable the interrupt.

Calculation of time:
Let the clock frequency be 12 MHz. The number of machine cycles required for 2 sec is: 2106
With reference to example 1, if we set timer to be elapse at 50,000 machine cycles, then number of
times the timer needs to overflow is:
2,000,000
= 40
50,000
So here maximum value of counter will be 40. Let us use timer interrupt to increment counter.
Interrupt Table

The interrupt number is required to write the interrupt service routine in embedded C.
Program:
#include <REGX51.H>
int counter;
bit flag;
sbit ext_int=P3^2;
void timer0_isr (void) interrupt 1 //timer 0: serial no. 1 in table
{
TH0=0x3c;
TL0=0xaf; //initialize timer for next overflow
TR0=1; //start timer
counter++;
}
void extern0_isr (void) interrupt 0 //external 0: serial no. 0 in table
{
ext_int=1;

This tutorial is downloaded from https://sites.google.com/site/enggprojectece


flag=1;
}
void main()
{
int x,y;
flag=0;
P0=0xff; //define P0 as input port
P1=0x00; //define P1 as output port
P3=0xff; //define P3 as input port (to receicve interrupt)
while(1)
{
IE=0x81;
//Global enable(bit 7) on and external interrupt (bit 0) on.
while(!flag); //flag will be set by external interrupt
flag=0;
IE=0x82; //enable general and timer0 interrupt
counter =0;
TMOD=1;
TH0=0x3c;
TL0=0xaf; //initialize timers
TR0=1; //run timer
x=P0;
y=2*x;
while(counter<40);
counter=0;
P1=y;
}
}

Você também pode gostar