Académique Documents
Professionnel Documents
Culture Documents
Embedded Systems/Advance
Embedded uControllers/ RTOS
Contents
Section I
Basic Electronics and Circuits Pg.
Power supplies 4
Positive Regulated ICs 78XX 9
Negative Regulated ICs 79XX 10
Positive Variable Regulator LM317 11
Negative Variable Regulator LM337 12
Precision Temperature sensor LM35 13
Operational Amplifiers 14
IC555 Timers 17
Relays 20
Opto-Isolators 21
ULN Drivers 22
Combinational circuits- adders, subtractors, mux-demux etc. 23
Sequential circuits, flip-flops, registers, counters 35
Section II
8 bit microcontrollers (8051)
S/W Tool: Keil-uV3 49
Introduction to 8051 58
Architecture 59
Register-sets 60
Assembly language programming 68
Addressing modes 81
Programming 8051 in C 88
I/O port programming 91
Timers and counters 94
Interrupts 108
Serial communication 120
Section III
Peripheral interfacing with 8051
LEDs 127
7 segment display 128
ADC(Analog to Digital converter) 131
DAC (Digital to Analog converter) 133
LCD 135
Stepper motor 140
Prepared by: Vivek Joshi(08MTES17) 2
Hex keypad 142
PC Interfacing using RS232 146
Top view simulator, Top view programmer 147
Section V
Introduction to advance microprocessors and controllers
ARM 156
SHARC 162
PIC 165
AVR 168
MOTOROLA-68HC11 180
Section VI
Introduction to Real Time Operating Systems
Introduction to RTOS 183
uCOS-II 185
VxWorks 186
Symbian 186
WinCE6.0. 188
References:
Embedded Systems by Dr. Rajkamal
Embedded Systems by Mazidi & Mazidi
Various internet sites.
Overview
This section covers the design of basic unregulated DC power supplies.
Load Requirements
Before designing any power supply the load requirements must be known. It is
always a good idea to take the worstcase scenario when making this decision. For
example if your circuit is designed to draw 1 amp at 12 volts, assume that
component tolerances are 20% and design to meet these requirements with at least
20-50% reserve current, in this example I would design a power supply which could
safely deliver 12 volts at 1.5 amps without overheating.
VA Rating 6 12 20 50 100
% Regulation 25 12 10 10 10
For example a 12 VA rated transformer would have a no load voltage which is 12%
higher than the rated value. If the transformer was rated at 12 V, 1 A, then
Prepared by: Vivek Joshi(08MTES17) 4
measuring the secondary RMS voltage with a high impedance meter, you would
measure approximately 13.44 Volts.
Rectification
This is the process where alternating current is converted to direct current. There are
three main types of rectifier circuit, half wave, full wave and bridge.
Half-Wave:
The half wave rectifier circuit is shown in Fig. 1 below:
Fig. 1
Fig. 2
Full-Wave:
Fig. 3
Fig. 4
Bridge Rectifier:
The bridge rectifier is the most popular of rectifier circuits. It uses four diodes
arranged in a ring, but complete four terminal bridge rectifiers are also available.
The circuit is shown at Fig. 5 below:
Prepared by: Vivek Joshi(08MTES17) 6
Fig. 5
Fig. 6
Smoothing Capacitor(Filter):
The "raw" DC produced after rectification is OK to charge a battery or light a lamp
but any electronic circuit needs a smooth DC supply. In the case of audio circuits,
particularly amplifiers, any unfiltered DC will be heard as a "hum" in the
equipments loudspeakers. The hum is proportional to the AC power supplies
Fig. 7
Fig. 8
• Output Current up to 1A
• Output Voltages of 5, 6, 8, 9, 10, 12, 15, 18, 24
• Thermal Overload Protection
• Short Circuit Protection
• Output Transistor Safe Operating Area Protection
78xx Pin-out
The 78xx, 78Mxx, and 78Sxx regulators all have the pin-out shown in the left of
figure 1 and are normally supplied in a case style known as TO-220. The 78Lxx
series, shown in the right of figure 1, also has the same pin-out but has a case style
known as TO-92. They are all connected to the rest of the power supply in the
same way, as shown in figure 2.
Specifications
Features
Description
The MC79XX / MC79XXA/ LM79XX series of three
terminal negative regulators are available in TO-220
package and with several fixed output voltages, making
them useful in a wide range of applications. Each type
employs internal current limiting, thermal shut down and
safe operating area protection, making it essentially
indestructible.
A.
LM317
This is the standard part number for an integrated three-terminal adjustable linear
voltage regulator. LM317 is a positive voltage regulator supporting input voltage
of 3V to 40V and output voltage between 1.25V and 37V. A typical current rating
is 1.5A although several lower and higher current models are available. Variable
output voltage is achieved by using a potentiometer or a variable voltage from
another source to apply a control voltage to the control terminal.
LM317 also has a built-in current limiter to prevent the output
current from exceeding the rated current, and LM317 will
automatically reduce its output current if an overheat condition
occurs under load. LM317 is manufactured by many companies,
including National Semiconductor, Fairchild Semiconductor, and
STMicroelectronics.
Specifications
Vout range 1.25V - 37V
Vin - Vout difference 3V - 40V
Operation ambient temperature 0 - 125°C
Output Imax <1.5A
Minimum Load Currentmax 10mA
Specifications
Output Current 1500 mA
Output Min -37 Volt
Input Min Voltage -50 Volt
Input Max Voltage -4.2 Volt
Adjustable Output Yes
Specifications
Supply Min 4 Volt
Quiescent Current_ 56 uA
Temperature Min -40, 0, -55 deg C
Temperature Max 100, 110, 150 deg C
Sensor Gain 10 mV/Deg C
Pin-out diagram
Non-inverting amplifier
The general op-amp has two inputs and one output. The output voltage is a
multiple of the difference between the two inputs (some are made with floating,
differential outputs):
G is the open-loop gain of the op-amp. The inputs are assumed to have very high
impedance; negligible current will flow into or out of the inputs. Op-amp outputs
have very low source impedance.
then:
, where G > 0
Solving for Vout / Vin, we see that the result is a linear amplifier with gain:
Inverting amplifier
Because it does not require a differential input, this negative feedback connection
was the most typical use of an op-amp in the days of analog computers. It remains
very popular, but many different configurations are possible, making it one of the
most versatile of all electronic building blocks.
However, because the input current into any operational amplifier is assumed to be
zero,
and so
Comparator
When else 0
I.5
555 Timers
The 555 Timer IC is an integrated circuit
(chip) implementing a variety of timer and
multivibrator applications. The IC was designed
Prepared by: Vivek Joshi(08MTES17) 16
and invented by Hans R. Camenzind. It was designed in 1970 and introduced in
1971 by Signetics (later acquired by Philips). The original name was the
SE555/NE555 and was called "The IC Time Machine". The 555 gets its name from
the three 5-kohm resistors used in typical early implementations. It is still in wide
use, thanks to its ease of use, low price and good stability.
As of 2003, 1 billion units are manufactured every year.
Monostable mode
which is the time it takes to charge C to 2/3 of the supply voltage. See RC
circuit for an explanation of this effect.
Astable Mode
In astable mode, the 555 timer outputs a continuous stream of rectangular pulses
having a specified frequency. A resistor (call it R1) is connected between Vcc and
the discharge pin (pin 7) and another (R2) is connected between the discharge pin
(pin 7) and the trigger (pin 2) and threshold (pin 6) pins that share a common node.
Hence the capacitor is charged through R1 and R2, and discharged only through R2,
since pin 7 has low impedance to ground during output low intervals of the cycle,
therefore discharging the capacitor. The use of R2 is mandatory, since without it the
high current spikes from the capacitor may damage the internal discharge transistor.
In the astable mode, the frequency of the pulse stream depends on the values of R1,
R2 and C:
Where R1 and R2 are the values of the resistors in ohms and C is the value of the
capacitor in farads.
The dual version is called 556. It features two complete 555s in a 14 pin DIL
package.
The quad version is called 558 and has 16 pins. To fit four 555's into a 16 pin
package the control voltage and reset lines are shared by all four modules. Also for
each module the discharge and threshold are internally wired together and called
timing.
I.6
Relays
A relay is an electrical switch that opens and closes under the control of another
electrical circuit. In the original form, the switch is operated by an electromagnet to
open or close one or many sets of contacts. It was invented by Joseph Henry in 1835.
Because a relay is able to control an output
circuit of higher power than the input circuit, it
can be considered to be, in a broad sense, a
form of an electrical amplifier.
I.7
Opto-couplers/Opto-isolators
In electronics, an opto-isolator (or optical isolator, optocoupler, photocoupler, or
photoMOS) is a device that uses a short optical transmission path to transfer a
signal between elements of a circuit, typically a transmitter and a receiver, while
keeping them electrically isolated — since the signal goes from an electrical signal
to an optical signal back to an electrical signal, electrical contact along the path is
broken.
The opto-isolator is simply a package that contains both an infrared LED and a
photodetector such as silicon diode, transistor Darlington pair, or SCR. The wave-
I.8
ULN Drivers
The ULN2803 is a small integrated circuit that contains 8 transistor driver channels.
Each channel has an input to a resistor connected to the base of a transistor and a 1
amp open collector output capable of handling up to about 30volts (if my memory is
correct). Each of the collectors has a reverse biased diode connected to a common
Vcc pin that provides inductive spike protection.
Features
TTL, DTL, PMOS, or CMOS-
compatible Inputs
Output Current to 500 mA
Output Voltage to 95 V
Transient-Protected Outputs
Dual In-Line Plastic Package or Small-Outline IC Package
Input Voltage, V IN ................................ 30 V
Continuous Output Current,Io ................................................. 500 mA
Continuous Input Current, Iin........... 25 mA
Power Dissipation, Pd
(one Darlington pair) ..................... 1.0 W
I.9
Combinational Logic
INPUT OUTPUT
A B A AND B
0 0 0
0 1 0
AND
1 0 0
1 1 1
INPUT OUTPUT
A B A OR B
0 0 0
0 1 1
OR A+B 1 0 1
1 1 1
INPUT OUTPUT
A NOT A
0 1
NOT
1 0
In electronics a NOT gate is more commonly called an inverter. The circle on the symbol is called
a bubble, and is generally used in circuit diagrams to indicate an inverted (active-low) input or
INPUT OUTPUT
output.[1]
A B A NAND B
0 0 1
0 1 1
1 0 1
NAND
1 1 0
INPUT OUTPUT
A B A XOR B
0 0 0
0 1 1
XOR
1 0 1
1 1 0
INPUT OUTPUT
A XNOR
A B
B
0 0 1
XNOR 0 1 0
1 0 0
1 1 1
74LS02 Quad
NOR
74LS08 Quad AND
I.9.2 Adders
For single bit adders, there are two general types.
A half adder has two inputs, generally labelled A and B, and two outputs, the sum
S and carry C. S is the two-bit XOR of A and B, and C is the AND of A and B.
Essentially the output of a half adder is the sum of two one-bit numbers, with C
being the most significant of these two outputs.
A full adder has three inputs - A, B, and a carry in C, such that multiple adders
can be used to add larger numbers. To remove ambiguity between the input and
output carry lines, the carry in is labelled Ci or Cin while the carry out is labelled Co
or Cout.
Half adder
A B C S
1 1 1 0
Input Output
A B Ci Co S
0 0 0 0 0
0 0 1 0 1
0 1 0 0 1
0 1 1 1 0
1 0 0 0 1
1 0 1 1 0
1 1 0 1 0
1 1 1 1 1
A full adder is a logical circuit that performs an addition operation on three binary
digits. The full adder produces a sum and carry value, which are both binary digits.
It can be combined with other full adders (see below) or work on its own.
Note that the final OR gate before the carry-out output may be replaced by an XOR
gate without altering the resulting logic. This is because the only difference
between OR and XOR gates occurs when both inputs are 1; for the adder shown
here, this is never possible. Using only two types of gates is convenient if one
desires to implement the adder directly using common IC chips.
A full adder can be constructed from two half adders by connecting A and B to the
input of one half adder, connecting the sum from that to an input to the second
adder, connecting Ci to the other input and OR the two carry outputs. Equivalently,
S could be made the three-bit xor of A, B, and Ci and Co could be made the three-
bit majority function of A, B, and Ci. The output of the full adder is the two-bit
arithmetic sum of three one-bit numbers.
Multiple-bit adders
It is possible to create a logical circuit using multiple full adders to add N-bit
numbers. Each full adder inputs a Cin, which is the Cout of the previous adder. This
kind of adder is a ripple carry adder, since each carry bit "ripples" to the next full
adder. Note that the first (and only the first) full adder may be replaced by a half
adder.
The layout of ripple carry adder is simple, which allows for fast design time;
however, the ripple carry adder is relatively slow, since each full adder must wait
for the carry bit to be calculated from the previous full adder. The gate delay can
easily be calculated by inspection of the full adder circuit. Following the path from
Cin to Cout shows 2 gates that must be passed through. Therefore, a 32-bit adder
requires 31 carry computations and the final sum calculation for a total of 31 * 2 +
1 = 63 gate delays.
Subtracter
Subtracter circuits take two binary numbers as input and subtract one binary
number input from the other binary number input. Similar to adders, it gives out
two outputs, difference and borrow (carry-in the case of Adder). There are two
types of subtracters.
• Half Subtracter.
• Full Subtracter.
The half-subtracter is a
combinational circuit which is used
to perform subtraction of two bits. It
has two inputs, X (minuend) and Y
(subtrahend) and two outputs D (difference) and B (borrow). The logic symbol
and truth table are shown below.
An electronic multiplexer makes it possible for several signals to share one device or
resource, for example one A/D converter or one communication line, instead of
having one device per input signal.
A 2-to-1 multiplexer has a Boolean equation where A and B are the two inputs, S is
the selector input, and Z is the output:
S A B Z
1 1 1
1 0 1
0
0 1 0
0 0 0
1 1 1 1
0 1 1
0 0 0
16-to-1 mux
8-to-1 mux
4-to-1 mux
Demultiplexer
I.9.4
Encoder Circuit
An encoder has 2n input lines and n output lines.The output lines generate a binary
code corresponding to the input value. For example a single bit 4 to 2 encoder
Prepared by: Vivek Joshi(08MTES17) 32
Gate level circuit diagram of a single bit 4-to-2 line encoder
takes in 4 bits and outputs 2 bits. It is assumed that there are only 4 types of input
signals these are : 0001, 0010, 0100, 1000.
I3 I2 I1 I0 O1 O0
0 0 0 1 0 0
0 0 1 0 0 1
0 1 0 0 1 0
1 0 0 0 1 1
4 to 2 encoder
The encoder has the limitation that only one input can be active at any given time.
If two inputs are simultaneously active, the output produces an undefined
combination. To prevent this we make use of the priority encoder.
Decoders
Decoders are circuits with two or more inputs and one or more outputs, resulting by
combining various types of gates. Their basic function is to accept a binary word
(code) as an input and create a different binary word as an output. A typical decoder
is the so-called full adder (3 inputs-2 outputs) implementing the addition of two one-
digit numbers (Ai, Bi) taking into consideration the status of any previous carry (Ci-
1), resulting into the sum (Si), and generating a new carry (Ci). The addition of two 1-
digits numbers and the corresponding truth table of full adder are shown below:
I.10
Sequential Logic
I.10.1 Flipflops
A flip-flop is usually controlled by one or two control signals and/or a gate or clock
signal. The output often includes the complement as well as the normal output. As
Prepared by: Vivek Joshi(08MTES17) 34
flip-flops are implemented electronically, they require power and ground
connections.
The fundamental latch is the simple SR flip-flop , where S and R stand for set and
reset respectively. It can be constructed from a pair of cross-coupled NAND or
NOR logic gates . The stored bit is present on the output marked Q.
Normally, in storage mode, the S and R inputs are both low, and feedback
maintains the Q and Q outputs in a constant state, with Q the complement of Q. If
S is pulsed high while R is held low, then the Q output is forced high, and stays
high even after S returns low; similarly, if R is pulsed high while S is held low,
then the Q output is forced low, and stays low even after R returns low.
0 1 Q=0 0 1 1 0 set
1 0 Q=1 1 0 0 1 reset
A circuit symbol for a T-type flip-flop, where > is the clock input, T is the toggle
input and Q is the stored data output.
If the T input is high, the T flip-flop changes state ("toggles") whenever the clock
input is strobed. If the T input is low, the flip-flop holds the previous value. This
behavior is described by the characteristic equation:
1 0 1 toggle 0 1 1 Complement
When T is held high, the toggle flip-flop divides the clock frequency by two; that
is, if clock frequency is 4 MHz, the output frequency obtained from the flip-flop
will be 2 MHz. This 'divide by' feature has application in various types of digital
counters. A T flip-flop can also be built using a JK flip-flop (J & K pins are
connected together and act as T) or D flip-flop (T input and Q previous is connected to
the D input through an XOR gate).
JK flip-flop
A circuit symbol for a JK flip-flop, where > is the clock input, J and K are data
inputs, Q is the stored data output, and Q' is the inverse of Q.
0 1 reset 0 1 1 X Set
1 0 set 1 0 X 1 Reset
1 1 toggle 1 1 X 0 No change
D flip-flop
D flip-flop symbol
The Q output always takes on the state of the D input at the moment of a rising
clock edge (or falling edge if the clock input is active low).[7] It is called the D flip-
flop for this reason, since the output takes the value of the D input or Data input,
and Delays it by one clock count. The D flip-flop can be interpreted as a primitive
memory cell, zero-order hold, or delay line.
Truth table:
Clock D Q Qprev
Prepared by: Vivek Joshi(08MTES17) 38
Rising
0 0 X
edge
Rising
1 1 X
edge
Non-Rising X Qprev
In digital circuits, a shift register is a group of flip flops set up in a linear fashion
which have their inputs and outputs connected together in such a way that the data is
shifted down the line when the circuit is activated.
Shift registers can have both parallel and serial inputs and outputs. These are often
configured as serial-in, parallel-out (SIPO) or as parallel-in, serial-out (PISO).
There are also types that have both serial and parallel input and types with serial and
parallel output. There are also bi-directional shift registers which allows one to vary
the direction of the shift register. The serial input and outputs of a register can also
be connected together to create a circular shift register. One could also create
multi-dimensional shift registers, which can perform more complex computation.
Serial-in, parallel-out
This configuration allows conversion from serial to parallel format. Data is input
serially, as described in the SISO section above. Once the data has been input, it
may be either read off at each output simultaneously, or it can be shifted out and
replaced.
Parallel-in, serial-out
This configuration has the data input on lines D1 through D4 in parallel format. To
write the data to the register, the Write/Shift control line must be held LOW. To
shift the data, the W/S control line is brought HIGH and the registers are clocked.
The arrangement now acts as a SISO shift register, with D1 as the Data Input.
However, as long as the number of clock cycles is not more than the length of the
data-string, the Data Output, Q, will be the parallel data read off in order.
I.10.3 Counters
In digital logic and computing, a counter is a device which stores (and sometimes
displays) the number of times a particular event or process has occurred, often in
relationship to a clock signal. In practice, there are two types of counters:
The simplest counter circuit is a single D-type flip-flop, with its D (data) input fed
from its own inverted output. This circuit can store one bit, and hence can count
from zero to one before it overflows (starts over from 0). This counter will
increment once for every clock cycle and takes two clock cycles to overflow, so
every cycle it will alternate between a transition from 0 to 1 and a transition from 1
to 0. Notice that this creates a new clock with a 50% duty cycle at exactly half the
frequency of the input clock. If this output is then used as the clock signal for a
similarly arranged D flip-flop (remembering to invert the output to the input), you
will get another 1 bit counter that counts half as fast. Putting them together yields a
two bit counter:
Cycle Q1 Q0 (Q1:Q0)dec
0 0 0 0
1 0 1 1
2 1 0 2
3 1 1 3
4 0 0 0
The use of flip-flop outputs as clocks leads to timing skew between the count data
bits, making this ripple technique incompatible with normal synchronous circuit
design styles.
Synchronous counter
Ring counter
Main article: Ring counter
Johnson counter
Decade counter
A decade counter is one that counts in decimal digits, rather than binary. A decimal
counter may have each digit binary encoded (that is, it may count in binary-coded
decimal, as the 7490 integrated circuit did) or other binary encodings (such as the
bi-quinary encoding of the 7490 integrated circuit). Alternatively, it may have a
"fully decoded" or one-hot output code in which each output goes high in turn; the
4017 was such a circuit. The latter type of circuit finds applications in multiplexers
and demultiplexers, or wherever a scanning type of behaviour is useful. Similar
counters with different numbers of outputs are also common. The decade counter is
also known as a mod-10 counter.
Up–down counter
A counter that can change state in either direction, under control an up–down
selector input, is known as an up–down counter. When the selector is in the up
state, the counter increments its value; when the selector is in the down state, the
counter decrements the count.
Exercise
14. Which mode of IC555 timer is also referred as free running mode?
15. What are the three connecting terminal of a normal SPDT relay?
16. Which of the following IC has 1 transistor and 1 LED integrated in it?
17. To interface microcontroller with high current devices like motors etc. we need
f. 74LS86 F. Quad OR
20. What are the boolean equations for sum and carry of a half adder circuit?
d. Sum=A.B, Carry=A+B
21. What are the boolean equations for sum and carry of a full adder circuit?
b. Sum=A+B+Cin, Cout=A.B.Cin
a. 1 b. 2 c. 3 d. 4
24. If input of the decoder is of 4 lines, how many lines will be at output?
a. 2 b. 4 c. 8 d. 16
a. 1 b. 2 c. 3 d. 4
a. 4 b. 8 c. 16 d. 64
Section II
7
. Here
you
have
to
choose
device for
which
you need
to write
programs. As we are targeting programs to AT89C51/52(Commercial name
of 8051), we will select Atmel>AT89C51
13.Select the file you just created…i.e. First.c and click on Add button and then
on Close button.
14.After doing so, you will find the summery of compilation (in the window
called output window just below the project window), i.e. whether there are
some bugs (error or warnings) or not. Program size with data and code size is
also displayed.
17. In the Target tab write Xtal(MHz) as 11.0592. This is the crystal frequency of
8051.
19. Now compile your file again from the option Project>Rebuild all target files or
by pressing F7. You will find that in the output window summery, details of hex
file is also displayed. Now this hex file (First.hex) is ready to be burnt on to the
device (8051).
Introduction to 8051
The 8051 is an 8-bit microprocessor originally designed in the 1980's by Intel that
has gained great popularity since its introduction. Its standard form includes several
standard on-chip peripherals, including timers, counters, and UART ' s, plus 4kbytes
of on-chip program memory and 128 bytes (note: bytes, not Kbytes) of data
memory, making single-chip implementations possible. Its hundreds of derivatives,
manufactured by several different companies (like Philips) include even more on-
chip peripherals, such as analog-digital converters, pulse-width modulators, I2C bus
interfaces, etc. Costing only a few dollars per IC, the 8051 is estimated to be used in
a large percentage in all the embedded system products.
The 8051 memory architecture includes 128 bytes of data memory that are
accessible directly by its instructions. A 32-byte segment of this 128 byte memory
block is bit addressable by a subset of the 8051 instructions, namely the bit-
instructions. External memory of up to 64 Kbytes is accessable by a special "movx"
instruction. Up to 4 Kbytes of program instructions can be stored in the internal
memory of the 8051, or the 8051 can be configured to use up to 64 Kbytes of
external program memory The majority of the 8051's instructions are executed
within 12 clock cycles.
For example, if you want to add the number 10 and 20, the resulting 30 will be
stored in the Accumulator. Once you have a value in the Accumulator you may
continue processing the value or you may store it in another register or in memory.
These registers are used as auxillary registers in many operations. To continue with
the above example, perhaps you are adding 10 and 20. The original number 10 may
be stored in the Accumulator whereas the value 20 may be stored in, say, register
R4. To process the addition you would execute the command:
ADD A,R4
After executing this instruction the Accumulator will contain the value 30.
You may think of the "R" registers as very important auxillary, or "helper", registers.
The Accumulator alone would not be very useful if it were not for these "R"
registers.
The "R" registers are also used to temporarily store values. For example, lets say you
want to add the values in R1 and R2 together and then subtract the values of R3 and
R4. One way to do this would be:
As you can see, we used R5 to temporarily hold the sum of R3 and R4. Of course,
this isnt the most efficient way to calculate (R1+R2) - (R3 +R4) but it does illustrate
the use of the "R" registers as a way to store values temporarily.
The "B" register is only used by two 8051 instructions: MUL AB and DIV AB.
Thus, if you want to quickly and easily multiply or divide A by another number, you
may store the other number in "B" and make use of these two instructions.
The Data Pointer (DPTR) is the 8051s only user-accessable 16-bit (2-byte) register.
The Accumulator, "R" registers, and "B" register are all 1-byte values.
While DPTR is most often used to point to data in external memory, many
programmers often take advantge of the fact that its the only true 16-bit register
available. It is often used to store 2-byte values which have nothing to do with
memory locations.
The Program Counter (PC) is a 2-byte address which tells the 8051 where the next
instruction to execute is found in memory. When the 8051 is initialized PC always
starts at 0000h and is incremented each time an instruction is executed. It is
important to note that PC isnt always incremented by one. Since some instructions
require 2 or 3 bytes the PC will be incremented by 2 or 3 in these cases.
The Program Counter is special in that there is no way to directly modify its value.
That is to say, you cant do something like PC=2430h. On the other hand, if you
execute LJMP 2430h youve effectively accomplished the same thing.
When you push a value onto the stack, the 8051 first increments the value of SP and
then stores the value at the resulting memory location.
When you pop a value off the stack, the 8051 returns the value from the memory
location indicated by SP, and then decrements the value of SP.
SFRs are accessed as if they were normal Internal RAM. The only difference is that
Internal RAM is from address 00h through 7Fh whereas SFR registers exist in the
address range of 80h through FFh.
Each SFR has an address (80h through FFh) and a name. The following chart
provides a graphical presentation of the 8051's SFRs, their names, and their address.
SFR Types
As mentioned in the chart itself, the SFRs that have a blue background are SFRs
related to the I/O ports. The 8051 has four I/O ports of 8 bits, for a total of 32 I/O
lines. Whether a given I/O line is high or low and the value read from the line are
controlled by the SFRs in green.
The SFRs with yellow backgrouns are SFRs which in some way control the
operation or the configuration of some aspect of the 8051. For example, TCON
controls the timers, SCON controls the serial port.
The remaining SFRs, with green backgrounds, are "other SFRs." These SFRs can be
thought of as auxillary SFRs in the sense that they don't directly configure the 8051
but obviously the 8051 cannot operate without them. For example, once the serial
port has been configured using SCON, the program may read or write to the serial
port using the SBUF register.
Programming Tip: The SFRs whose names appear in red in the chart
above are SFRs that may be accessed via bit operations (i.e., using the
SETB and CLR instructions). The other SFRs cannot be accessed using
Prepared by: Vivek Joshi(08MTES17) 61
bit operations. As you can see, all SFRs that whose addresses are
divisible by 8 can be accessed with bit operations.
SFR Descriptions
This section will endeavor to quickly overview each of the standard SFRs found in
the above SFR chart map. It is not the intention of this section to fully explain the
functionality of each SFR--this information will be covered in separate chapters of
the tutorial. This section is to just give you a general idea of what each SFR does.
Programming Tip: While the 8051 has four I/O port (P0, P1, P2, and
P3), if your hardware uses external RAM or external code memory (i.e.,
your program is stored in an external ROM or EPROM chip or if you
are using external RAM chips) you may not use P0 or P2. This is
because the 8051 uses ports P0 and P2 to address the external memory.
Thus if you are using external RAM or code memory you may only use
ports P1 and P3 for your own use.
SP (Stack Pointer, Address 81h): This is the stack pointer of the microcontroller.
This SFR indicates where the next value to be taken from the stack will be read from
in Internal RAM. If you push a value onto the stack, the value will be written to the
address of SP + 1. That is to say, if SP holds the value 07h, a PUSH instruction will
push the value onto the stack at address 08h. This SFR is modified by all instructions
which modify the stack, such as PUSH, POP, LCALL, RET, RETI, and whenever
interrupts are provoked by the microcontroller.
PCON (Power Control, Addresses 87h): The Power Control SFR is used to
control the 8051's power control modes. Certain operation modes of the 8051 allow
the 8051 to go into a type of "sleep" mode which requires much less power. These
modes of operation are controlled through PCON. Additionally, one of the bits in
PCON is used to double the effective baud rate of the 8051's serial port.
TMOD (Timer Mode, Addresses 89h): The Timer Mode SFR is used to configure
the mode of operation of each of the two timers. Using this SFR your program may
configure each timer to be a 16-bit timer, an 8-bit autoreload timer, a 13-bit timer, or
two separate timers. Additionally, you may configure the timers to only count when
an external pin is activated or to count "events" that are indicated on an external pin.
SCON (Serial Control, Addresses 98h, Bit-Addressable): The Serial Control SFR
is used to configure the behavior of the 8051's on-board serial port. This SFR
controls the baud rate of the serial port, whether the serial port is activated to receive
data, and also contains flags that are set when a byte is successfully sent or received.
SBUF (Serial Control, Addresses 99h): The Serial Buffer SFR is used to send and
receive data via the on-board serial port. Any value written to SBUF will be sent out
the serial port's TXD pin. Likewise, any value which the 8051 receives via the serial
port's RXD pin will be delivered to the user program via SBUF. In other words,
SBUF serves as the output port when written to and as an input port when read from.
Programming Tip: While the 8051 has four I/O port (P0, P1, P2, and
P3), if your hardware uses external RAM or external code memory (i.e.,
your program is stored in an external ROM or EPROM chip or if you
are using external RAM chips) you may not use P0 or P2. This is
because the 8051 uses ports P0 and P2 to address the external memory.
Thus if you are using external RAM or code memory you may only use
ports P1 and P3 for your own use.
II.5
ACALL
Operation: ACALL
Function: Absolute Call Within 2K Block
Syntax: ACALL code address
The new value for the Program Counter is calculated by replacing the least-
significant-byte of the Program Counter with the second byte of the ACALL
instruction, and replacing bits 0-2 of the most-significant-byte of the Program
Counter with 3 bits that indicate the page. Bits 3-7 of the most-significant-byte of
the Program Counter remain unchaged.
ADD
Operation: ADD, ADDC
Function: Add Accumulator, Add Accumulator With Carry
Syntax: ADD A, operand
ADDC A, operand
Description: Description: ADD and ADDC both add the value operand to the
value of the Accumulator, leaving the resulting value in the Accumulator. The
value operand is not affected. ADD and ADDC function identically except that
Example: ADD A, R0
ADDC A,R0
AJMP
Operation: AJMP
Function: Absolute Jump Within 2K Block
Syntax: AJMP code address
Description: AJMP unconditionally jumps to the indicated code address. The new
value for the Program Counter is calculated by replacing the least-significant-byte
of the Program Counter with the second byte of the AJMP instruction, and
replacing bits 0-2 of the most-significant-byte of the Program Counter with 3 bits
that indicate the page of the byte following the AJMP instruction. Bits 3-7 of the
most-significant-byte of the Program Counter remain unchaged.
ANL
Operation: ANL
Function: Bitwise AND
Syntax: ANL operand1, operand2
Example: ANL A, R1
CJNE
Operation: CJNE
Function: Compare and Jump If Not Equal
Syntax: CJNE operand1,operand2,reladdr
Description: CJNE compares the value of operand1 and operand2 and branches to
the indicated relative address if operand1 and operand2 are not equal. If the two
Prepared by: Vivek Joshi(08MTES17) 67
operands are equal program flow continues with the instruction following the
CJNE instruction.
The Carry bit (C) is set if operand1 is less than operand2, otherwise it is cleared.
CLR
Operation: CLR
Function: Clear Register
Syntax: CLR register
Description: CLR clears (sets to 0) all the bit(s) of the indicated register. If the
register is a bit (including the carry bit), only the specified bit is affected. Clearing
the Accumulator sets the Accumulator's value to 0.
Example: CLR B
CPL
Operation: CPL
Function: Complement Register
Syntax: CPL operand
Example: CPL A
CPL P3.0
DA
Operation: DA
Function: Decimal Adjust Accumulator
Syntax: DA A
Example: DA A
Example: DEC R0
DIV
Operation: DIV
Function: Divide Accumulator by B
Syntax: DIV AB
Description: Divides the unsigned value of the Accumulator by the unsigned value
of the "B" register. The resulting quotient is placed in the Accumulator and the
remainder is placed in the "B" register.
Example: DIV AB
DJNZ
Operation: DJNZ
Function: Decrement and Jump if Not Zero
Syntax: DJNZ register,reladdr
In the case of "INC DPTR", the value two-byte unsigned integer value of DPTR is
incremented. If the initial value of DPTR is 65535 (0xFFFF Hex), incrementing the
value will cause it to reset to 0. Again, the Carry Flag is NOT set when the value of
DPTR "rolls over" from 65535 to 0.
Example: INC R0
JB
Operation: JB
Function: Jump if Bit Set
Syntax: JB bit addr, reladdr
JBC
Operation: JBC
Function: Jump if Bit Set and Clear Bit
Syntax: JB bit addr, reladdr
Description: JBC will branch to the address indicated by reladdr if the bit
indicated by bit addr is set. Before branching to reladdr the instruction will clear
the indicated bit. If the bit is not set program execution continues with the
instruction following the JBC instruction.
JC
Operation: JC
Description: JC will branch to the address indicated by reladdr if the Carry Bit is
set. If the Carry Bit is not set program execution continues with the instruction
following the JC instruction.
Example: JC Label
JMP
Operation: JMP
Function: Jump to Data Pointer + Accumulator
Syntax: JMP @A+DPTR
JNB
Operation: JNB
Function: Jump if Bit Not Set
Syntax: JNB bit addr,reladdr
JNC
Operation: JNC
Function: Jump if Carry Not Set
Syntax: JNC reladdr
Description: JNC branches to the address indicated by reladdr if the carry bit is
not set. If the carry bit is set program execution continues with the instruction
following the JNB instruction.
JNZ
Operation: JNZ
JZ
Operation: JZ
Function: Jump if Accumulator Zero
Syntax: JNZ reladdr
Example: JZ Label
LCALL
Operation: LCALL
Function: Long Call
Syntax: LCALL code addr
LJMP
Operation: LJMP
Function: Long Jump
Syntax: LJMP code addr
Description: MOV copies the value of operand2 into operand1. The value of
operand2 is not affected. Both operand1 and operand2 must be in Internal RAM.
No flags are affected unless the instruction is moving the value of a bit into the
carry bit in which case the carry bit is affected or unless the instruction is moving a
value into the PSW register (which contains all the program flags).
Example: MOV A, R0
MOVC
Operation: MOVC
Function: Move Code Byte to Accumulator
Syntax: MOVC A,@A+register
Description: MOVC moves a byte from Code Memory into the Accumulator. The
Code Memory address from which the byte will be moved is calculated by
summing the value of the Accumulator with either DPTR or the Program Counter
(PC). In the case of the Program Counter, PC is first incremented by 1 before being
summed with the Accumulator.
MOVX
Operation: MOVX
Function: Move Data To/From External Memory (XRAM)
Syntax: MOVX operand1,operand2
Description: MOVX moves a byte to or from External Memory into or from the
Accumulator. If operand1 is @DPTR, the Accumulator is moved to the 16-bit
External Memory address indicated by DPTR. This instruction uses both P0 (port
0) and P2 (port 2) to output the 16-bit address and data. If operand2 is DPTR then
the byte is moved from External Memory into the Accumulator.
MUL
Operation: MUL
Function: Multiply Accumulator by B
Syntax: MUL AB
The Overflow Flag (OV) is set if the result is greater than 255 (if the most-
significant byte is not zero), otherwise it is cleared.
NOP
Operation: NOP
Function: None, waste time
Syntax: No Operation
Description: NOP, as it's name suggests, causes No Operation to take place for
one machine cycle. NOP is generally used only for timing purposes.
Absolutely no flags or registers are affected.
ORL
Operation: ORL
Function: Bitwise OR
Syntax: ORL operand1,operand2
Description: ORL does a bitwise "OR" operation between operand1 and operand2,
leaving the resulting value in operand1. The value of operand2 is not affected. A
logical "OR" compares the bits of each operand and sets the corresponding bit in
the resulting byte if the bit was set in either of the original operands, otherwise the
resulting bit is cleared.
Example: ORL A, R0
Description: POP "pops" the last value placed on the stack into the iram addr
specified. In other words, POP will load iram addr with the value of the Internal
RAM address pointed to by the current Stack Pointer. The stack pointer is then
decremented by 1.
PUSH
Operation: PUSH
Function: Push Value Onto Stack
Syntax: PUSH
Description: PUSH "pushes" the value of the specified iram addr onto the stack.
PUSH first increments the value of the Stack Pointer by 1, then takes the value
stored in iram addr and stores it in Internal RAM at the location pointed to by the
incremented Stack Pointer.
RET
Operation: RET
Function: Return From Subroutine
Syntax: RET
RETI
Operation: RETI
Function: Return From Interrupt
Syntax: RETI
Description: RETI is used to return from an interrupt service routine. RETI first
enables interrupts of equal and lower priorities to the interrupt that is terminating.
Program execution continues at the address that is calculated by popping the
topmost 2 bytes off the stack. The most-significant-byte is popped off the stack
first, followed by the least-significant-byte.
RL
Operation: RL
Function: Rotate Accumulator Left
Syntax: RL A
Description: Shifts the bits of the Accumulator to the left. The left-most bit (bit 7)
of the Accumulator is loaded into bit 0.
RLC
Operation: RLC
Function: Rotate Accumulator Left Through Carry
Syntax: RLC A
Description: Shifts the bits of the Accumulator to the left. The left-most bit (bit 7)
of the Accumulator is loaded into the Carry Flag, and the original Carry Flag is
loaded into bit 0 of the Accumulator. This function can be used to quickly multiply
a byte by 2.
RR
Operation: RR
Function: Rotate Accumulator Right
Syntax: RR A
Description: Shifts the bits of the Accumulator to the right. The right-most bit (bit
0) of the Accumulator is loaded into bit 7.
RRC
Operation: RRC
Function: Rotate Accumulator Right Through Carry
Syntax: RRC A
Description: Shifts the bits of the Accumulator to the right. The right-most bit (bit
0) of the Accumulator is loaded into the Carry Flag, and the original Carry Flag is
loaded into bit 7. This function can be used to quickly divide a byte by 2.
SETB
Operation: SETB
Function: Set Bit
Prepared by: Vivek Joshi(08MTES17) 76
Syntax: SETB bit addr
SJMP
Operation: SJMP
Function: Short Jump
Syntax: SJMP reladdr
Description: SJMP jumps unconditionally to the address specified reladdr. Reladdr
must be within -128 or +127 bytes of the instruction that follows the SJMP
instruction.
SUBB
Operation: SUBB
Function: Subtract from Accumulator With Borrow
Syntax: SUBB A,operand
Description: SUBB subtract the value of operand from the value of the
Accumulator, leaving the resulting value in the Accumulator. The value operand is
not affected.
SWAP
Operation: SWAP
Function: Swap Accumulator Nibbles
Syntax: SWAP A
Description: SWAP swaps bits 0-3 of the Accumulator with bits 4-7 of the
Accumulator. This instruction is identical to executing "RR A" or "RL A" four
times.
II.6
Addressing Modes
An "addressing mode" refers to how you are addressing a given memory location. In
summary, the addressing modes are as follows, with an example of each:
Immediate Addressing MOV A,#20h
Direct Addressing MOV A,30h
Indirect Addressing MOV A,@R0
External Direct MOVX A,@DPTR
Code Indirect MOVC A,@A+DPTR
Immediate Addressing
MOV A,#20h
This instruction uses Immediate Addressing because the Accumulator will be loaded
with the value that immediately follows; in this case 20 (hexidecimal).
Immediate addressing is very fast since the value to be loaded is included in the
instruction. However, since the value to be loaded is fixed at compile-time it is not
very flexible.
Direct Addressing
MOV A,30h
This instruction will read the data out of Internal RAM address 30 (hexidecimal) and
store it in the Accumulator.
Direct addressing is generally fast since, although the value to be loaded isnt
included in the instruction, it is quickly accessable since it is stored in the 8051s
Internal RAM. It is also much more flexible than Immediate Addressing since the
value to be loaded is whatever is found at the given address--which may be variable.
Also, it is important to note that when using direct addressing any instruction which
refers to an address between 00h and 7Fh is referring to Internal Memory. Any
instruction which refers to an address between 80h and FFh is referring to the SFR
control registers that control the 8051 microcontroller itself.
The obvious question that may arise is, "If direct addressing an address from 80h
through FFh refers to SFRs, how can I access the upper 128 bytes of Internal RAM
that are available on the 8052?" The answer is: You cant access them using direct
addressing. As stated, if you directly refer to an address of 80h through FFh you will
Prepared by: Vivek Joshi(08MTES17) 78
be referring to an SFR. However, you may access the 8052s upper 128 bytes of
RAM by using the next addressing mode, "indirect addressing."
Indirect Addressing
MOV A,@R0
This instruction causes the 8051 to analyze the value of the R0 register. The 8051
will then load the accumulator with the value from Internal RAM which is found at
the address indicated by R0.
For example, lets say R0 holds the value 40h and Internal RAM address 40h holds
the value 67h. When the above instruction is executed the 8051 will check the value
of R0. Since R0 holds 40h the 8051 will get the value out of Internal RAM address
40h (which holds 67h) and store it in the Accumulator. Thus, the Accumulator ends
up holding 67h.
Indirect addressing always refers to Internal RAM; it never refers to an SFR. Thus,
in a prior example we mentioned that SFR 99h can be used to write a value to the
serial port. Thus one may think that the following would be a valid solution to write
the value 1 to the serial port:
This is not valid. Since indirect addressing always refers to Internal RAM these two
instructions would write the value 01h to Internal RAM address 99h on an 8052. On
an 8051 these two instructions would produce an undefined result since the 8051
only has 128 bytes of Internal RAM.
External Direct
External Memory is accessed using a suite of instructions which use what I call
"External Direct" addressing. I call it this because it appears to be direct addressing,
but it is used to access external memory rather than internal memory.
There are only two commands that use External Direct addressing mode:
Prepared by: Vivek Joshi(08MTES17) 79
MOVX A,@DPTR
MOVX @DPTR,A
As you can see, both commands utilize DPTR. In these instructions, DPTR must
first be loaded with the address of external memory that you wish to read or write.
Once DPTR holds the correct external memory address, the first command will
move the contents of that external memory address into the Accumulator. The
second command will do the opposite: it will allow you to write the value of the
Accumulator to the external memory address pointed to by DPTR.
External Indirect
External memory can also be accessed using a form of indirect addressing which I
call External Indirect addressing. This form of addressing is usually only used in
relatively small projects that have a very small amount of external RAM. An
example of this addressing mode is:
MOVX @R0,A
Once again, the value of R0 is first read and the value of the Accumulator is written
to that address in External RAM. Since the value of @R0 can only be 00h through
FFh the project would effectively be limited to 256 bytes of External RAM. There
are relatively simple hardware/software tricks that can be implemented to access
more than 256 bytes of memory using External Indirect addressing; however, it is
usually easier to use External Direct addressing if your project has more than 256
bytes of External RAM.
Programming Examples
Prog.1 Putting data into registers A, B, R0 and R2.
ORG 0000H
MOV A, #10H
MOV B, #20
MOV R0, #30H
MOV R2, #40
END
Prog.2 To Put 10 + 19 and put the result in R0 register. 25 - 16 and put the result in
R1 register, 14 * 7 and put the result in R2 register and15 / 3 AND put the result in
R3 register.
ORG 0000H
MOV A,#10H
ADD A, #19H
Prepared by: Vivek Joshi(08MTES17) 80
MOV R0,A
MOV A,#25H
SUBB A,#16H
MOV R1,A
MOV A,#14H
MOV B,#7H
MUL AB
MOV R2,A
MOV A,#15H
MOV B,#3H
DIV AB
MOV R3,A
END
Prog.3 To add 22H, 44H, 88H and store the result in location 50H.
ORG 0000H
MOV A,40H
ADD A,41H
ADD A,42H
MOV 50H,A
END
MOV A,#0F0H
ADD A,#21H ; CY bit is SET
CLR C ; CY bit is RESET
MOV A,#0FH
ADD A, #03H ; AC bit is SET
CLR AC ; AC bit is RESET
MOV A,#60H
ADD A,#21H ; OV bit is SET
CLR OV ; OV bit is RESET
MOV A,#70H ; P bit is SET
Prepared by: Vivek Joshi(08MTES17) 81
CLR P ; CLR P does not RESET P bit.
MOV A,#03H ; P bit is RESET.
END
4. Now press F11(or you may click on the tool shown in figure) and see the change
in the registers as per the program. In this program values of accumulator will
change after the execution of instructions 7, 8 and 9 of the program.
Exercise:
1. Write an assembly program to toggle P1.0 with certain amount of delay.
2. Write an assembly program to toggle all the bits of P0 with delay.
3. Write an assembly program to get data from P0 and put its complement on P1.
Prepared by: Vivek Joshi(08MTES17) 83
4. Write an assembly program to add all the data present at 40h to 45h.
5. Write an assembly program to find the factorial 5 and to show it on a port.
6. Write an assembly program to set all the bits of P2 one by one with delay.
7. Write an assembly program to put 0 to 255 on P3 with certain delay.
8. Write an assembly program to multiply accumulator with the data of P1.
9. Write an assembly program to find greater of two no.s of two ports.
10.Write an assembly program to perform BCD addition.
II.7
8051 Programming in C
C Modifications
The Keil C compiler has made some modifications to an otherwise ANSI-compliant
implementation of the C programming language. These modifications were made
solely to facilitate the use of a higher-level language like C for writing programs on
micro controllers.
Variable Types
The Keil C compiler supports most C variable types and adds several of its own.
Standard Types
The evaluation version of the Keil C compiler supports the standard ANSI C
variable types, with the exception of the floating-point types. These types are
summarized below.
Type Bits Bytes Range
char 8 1 -128 to +127
unsigned char 8 1 0 to 255
enum 16 2 -32,768 to +32,767
short 16 2 -32,768 to +32,767
unsigned short 16 2 0 to 65,535
int 16 2 -32,768 to +32,767
unsigned int 16 2 0 to 65,535
long 32 4 -2,1e10 to+2,1e10
unsigned long 32 4 0 to 4,294,697,295
Prepared by: Vivek Joshi(08MTES17) 84
Keil Types
To support a micro controller and embedded systems applications, Keil added
several new types to their compiler. These are summarized in the table below.
Type Bits Bytes Range
bit 1 0 0 to 1
sbit 1 0 0 to 1
sfr 8 1 0 to 255
sf16 16 2 0 to 65,535
A Basic C Program
To send 0 to 255 on port 0.
void main()
{
unsigned char i;
while (1)
{
for (i = 0; i <= 255; i++)
P0=i;
}
#Program to send out the value 56H serially one bit at a time via P1.0. The
LSB should go first.
sbit mybit=P1^0;
sbit reg=B^0;
void main()
{
unsigned char conbyte=0x56;
unsigned char x;
B=conbyte;
for(x=0;x<8;x++)
{
mybit=reg;
B=B>>1;
}
Exercise
Write a C program to send out the value 56H serially one bit at a time via P1.0.
The MSB should go first.
#Program to bring out the value serially one bit at a time via P1.0. The LSB
should come first.
sbit mybit=P1^0;
sbit reg=B^7;
void main()
{
unsigned char x;
for(x=0;x<8;x++)
{
Reg=mybit;
B=B>>1;
}
}
II.8
I/O Port Programming
Pin Description of 8051
10 uF 31
EA/VPP
30 pF 19 X1
11.0592 MHz
8.2 K
X2
18
30 pF
9 RST
C2
XTAL2
30pF
C1
XTAL1
30pF
GND
Timers
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, or 3) Generating baud rates for the serial port.
The three timer uses are distinct so we will talk about each of them separately. The
first two uses will be discussed in this chapter while the use of timers for baud rate
generation will be discussed in the chapter relating to serial ports.
How does a timer count? The answer to this question is very simple: A timer always
counts up. It doesnt matter whether the timer is being used as a timer, a counter, or a
baud rate generator: A timer is always incremented by the microcontroller.
Obviously, one of the primary uses of timers is to measure time. We will discuss this
use of timers first and will subsequently discuss the use of timers to count events.
When a timer is used to measure time it is also called an "interval timer" since it is
measuring the time of the interval between two events.
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. As you will recall from the previous chapter, a single machine cycle consists
of 12 crystal pulses. Thus a running timer will be incremented:
11,059,000 / 12 = 921,583
.0542 seconds have passed. In plain English, about half of a tenth of a second, or
one-twentieth of a second.
Obviously its not very useful to know .0542 seconds have passed. If you want to
execute an event once per second youd have to wait for the timer to count from 0 to
50,000 18.45 times. How can you wait "half of a time?" You cant. So we come to
another important calculation.
Lets say we want to know how many times the timer will be incremented in .05
seconds. We can do simple multiplication:
This tells us that it will take .05 seconds (1/20th of a second) to count from 0 to
46,079. Actually, it will take it .049999837 seconds--so were off by .000000163
seconds--however, thats close enough for government work. Consider that if you
were building a watch based on the 8051 and made the above assumption your
watch would only gain about one second every 2 months. Again, I think thats
accurate enough for most applications--I wish my watch only gained one second
every two months!
Obviously, this is a little more useful. If you know it takes 1/20th of a second to
count from 0 to 46,079 and you want to execute some event every second you
simply wait for the timer to count from 0 to 46,079 twenty times; then you execute
your event, reset the timers, and wait for the timer to count up another 20 times. In
this manner you will effectively execute your event once per second, accurate to
within thousandths of a second.
Thus, we now have a system with which to measure time. All we need to review is
how to control the timers and initialize them to provide us with the information we
need.
Timer SFRs
As mentioned before, the 8051 has two timers which each function essentially the
same way. One timer is TIMER0 and the other is TIMER1. The two timers share
Prepared by: Vivek Joshi(08MTES17) 92
two SFRs (TMOD and TCON) which control the timers, and each timer also has two
SFRs dedicated solely to itself (TH0/TL0 and TH1/TL1).
Weve given SFRs names to make it easier to refer to them, but in reality an SFR has
a numeric address. It is often useful to know the numeric address that corresponds to
an SFR name. The SFRs relating to timers are:
When you enter the name of an SFR into an assembler, it internally converts it to a
number. For example, the command:
MOV TH0,#25h
moves the value 25h into the TH0 SFR. However, since TH0 is the same as SFR
address 8Ch this command is equivalent to:
MOV 8Ch,#25h
Timer 0 has two SFRs dedicated exclusively to itself: TH0 and TL0. Without
making things too complicated to start off with, you may just think of this as the
high and low byte of the timer. That is to say, when Timer 0 has a value of 0, both
TH0 and TL0 will contain 0. When Timer 0 has the value 1000, TH0 will hold the
high byte of the value (3 decimal) and TL0 will contain the low byte of the value
(232 decimal). Reviewing low/high byte notation, recall that you must multiply the
high byte by 256 and add the low byte to calculate the final value. That is to say:
Timer 1 works the exact same way, but its SFRs are TH1 and TL1.
Lets first talk about our first control SFR: TMOD (Timer Mode). The TMOD SFR is
used to control the mode of operation of both timers. Each bit of the SFR gives the
microcontroller specific information concerning how to run a timer. The high four
bits (bits 4 through 7) relate to Timer 1 whereas the low four bits (bits 0 through 3)
perform the exact same functions, but for timer 0.
Timer mode "0" is a 13-bit timer. This is a relic that was kept around in the 8051 to
maintain compatability with its predecesor, the 8048. Generally the 13-bit timer
mode is not used in new development.
When the timer is in 13-bit mode, TLx will count from 0 to 31. When TLx is
incremented from 31, it will "reset" to 0 and increment THx. Thus, effectively, only
13 bits of the two timer bytes are being used: bits 0-4 of TLx and bits 0-7 of THx.
This also means, in essence, the timer can only contain 8192 values. If you set a 13-
bit timer to 0, it will overflow back to zero 8192 machine cycles later.
Again, there is very little reason to use this mode and it is only mentioned so you
wont be surprised if you ever end up analyzing archaeic code which has been passed
down through the generations (a generation in a programming shop is often on the
order of about 3 or 4 months).
Timer mode "1" is a 16-bit timer. This is a very commonly used mode. It functions
just like 13-bit mode except that all 16 bits are used.
TLx is incremented from 0 to 255. When TLx is incremented from 255, it resets to 0
and causes THx to be incremented by 1. Since this is a full 16-bit timer, the timer
may contain up to 65536 distinct values. If you set a 16-bit timer to 0, it will
overflow back to 0 after 65,536 machine cycles.
Timer mode "2" is an 8-bit auto-reload mode. What is that, you may ask? Simple.
When a timer is in mode 2, THx holds the "reload value" and TLx is the timer itself.
Thus, TLx starts counting up. When TLx reaches 255 and is subsequently
incremented, instead of resetting to 0 (as in the case of modes 0 and 1), it will be
reset to the value stored in THx.
For example, lets say TH0 holds the value FDh and TL0 holds the value FEh. If we
were to watch the values of TH0 and TL0 for a few machine cycles this is what wed
see:
As you can see, the value of TH0 never changed. In fact, when you use mode 2 you
almost always set THx to a known value and TLx is the SFR that is constantly
incremented.
Whats the benefit of auto-reload mode? Perhaps you want the timer to always have a
value from 200 to 255. If you use mode 0 or 1, youd have to check in code to see if
the timer had overflowed and, if so, reset the timer to 200. This takes precious
instructions of execution time to check the value and/or to reload it. When you use
mode 2 the microcontroller takes care of this for you. Once youve configured a timer
in mode 2 you dont have to worry about checking to see if the timer has overflowed
nor do you have to worry about resetting the value--the microcontroller hardware
will do it all for you.
The auto-reload mode is very commonly used for establishing a baud rate which we
will talk more about in the Serial Communications chapter.
While Timer 0 is in split mode, the real Timer 1 (i.e. TH1 and TL1) can be put into
modes 0, 1 or 2 normally--however, you may not start or stop the real timer 1 since
the bits that do that are now linked to TH0. The real timer 1, in this case, will be
incremented every machine cycle no matter what.
The only real use I can see of using split timer mode is if you need to have two
separate timers and, additionally, a baud rate generator. In such case you can use the
real Timer 1 as a baud rate generator and use TH0/TL0 as two separate timers.
Finally, theres one more SFR that controls the two timers and provides valuable
information about them. The TCON SFR has the following structure:
A new piece of information in this chart is the column "bit address." This is because
this SFR is "bit-addressable." What does this mean? It means if you want to set the
bit TF1--which is the highest bit of TCON--you could execute the command:
... or, since the SFR is bit-addressable, you could just execute the command:
SETB TF1
This has the benefit of setting the high bit of TCON without changing the value of
any of the other bits of the SFR. Usually when you start or stop a timer you dont
want to modify the other values in TCON, so you take advantage of the fact that the
SFR is bit-addressable.
Initializing a Timer
Now that weve discussed the timer-related SFRs we are ready to write code that will
initialize the timer and start it running.
We must first initialize the TMOD SFR. Since we are working with timer 0 we will
be using the lowest 4 bits of TMOD. The first two bits, GATE0 and C/T0 are both 0
since we want the timer to be independent of the external pins. 16-bit mode is timer
mode 1 so we must clear T0M1 and set T0M0. Effectively, the only bit we want to
turn on is bit 0 of TMOD. Thus to initialize the timer we execute the instruction:
MOV TMOD,#01h
Timer 0 is now in 16-bit timer mode. However, the timer is not running. To start the
timer running we must set the TR0 bit We can do that by executing the instruction:
SETB TR0
Upon executing these two instructions timer 0 will immediately begin counting,
being incremented once every machine cycle (every 12 crystal pulses).
There are two common ways of reading the value of a 16-bit timer; which you use
depends on your specific application. You may either read the actual value of the
timer as a 16-bit number, or you may simply detect when the timer has overflowed.
If your timer is in an 8-bit mode--that is, either 8-bit AutoReload mode or in split
timer mode--then reading the value of the timer is simple. You simply read the 1-
byte value of the timer and youre done.
However, if youre dealing with a 13-bit or 16-bit timer the chore is a little more
complicated. Consider what would happen if you read the low byte of the timer as
255, then read the high byte of the timer as 15. In this case, what actually happened
was that the timer value was 14/255 (high byte 14, low byte 255) but you read
15/255. Why? Because you read the low byte as 255. But when you executed the
next instruction a small amount of time passed--but enough for the timer to
increment again at which time the value rolled over from 14/255 to 15/0. But in the
process youve read the timer as being 15/255. Obviously theres a problem there.
The solution? Its not too tricky, really. You read the high byte of the timer, then read
the low byte, then read the high byte again. If the high byte read the second time is
Prepared by: Vivek Joshi(08MTES17) 98
not the same as the high byte read the first time you repeat the cycle. In code, this
would appear as:
Another much simpler alternative is to simply turn off the timer run bit (i.e. CLR
TR0), read the timer value, and then turn on the timer run bit (i.e. SETB TR0). In
that case, the timer isnt running so no special tricks are necessary. Of course, this
implies that your timer will be stopped for a few machine cycles. Whether or not this
is tolerable depends on your specific application.
Often it is necessary to just know that the timer has reset to 0. That is to say, you are
not particularly interest in the value of the timer but rather you are interested in
knowing when the timer has overflowed back to 0.
Whenever a timer overflows from its highest value back to 0, the microcontroller
automatically sets the TFx bit in the TCON register. This is useful since rather than
checking the exact value of the timer you can just check if the TFx bit is set. If TF0
is set it means that timer 0 has overflowed; if TF1 is set it means that timer 1 has
overflowed.
We can use this approach to cause the program to execute a fixed delay. As youll
recall, we calculated earlier that it takes the 8051 1/20th of a second to count from 0
to 46,079. However, the TFx flag is set when the timer overflows back to 0. Thus, if
we want to use the TFx flag to indicate when 1/20th of a second has passed we must
set the timer initially to 65536 less 46079, or 19,457. If we set the timer to 19,457,
1/20th of a second later the timer will overflow. Thus we come up with the
following code to execute a pause of 1/20th of a second:
The 8051 provides another cool toy that can be used to time the length of events.
For example, let's say we're trying to save electricity in the office and we're
interested in how long a light is turned on each day. When the light is turned on, we
want to measure time. When the light is turned off we don't. One option would be to
connect the lightswitch to one of the pins, constantly read the pin, and turn the timer
on or off based on the state of that pin. While this would work fine, the 8051
provides us with an easier method of accomplishing this.
Looking again at the TMOD SFR, there is a bit called GATE0. So far we've always
cleared this bit because we wanted the timer to run regardless of the state of the
external pins. However, now it would be nice if an external pin could control
whether the timer was running or not. It can. All we need to do is connect the
lightswitch to pin INT0 (P3.2) on the 8051 and set the bit GATE0. When GATE0 is
set Timer 0 will only run if P3.2 is high. When P3.2 is low (i.e., the lightswitch is
off) the timer will automatically be stopped.
Thus, with no control code whatsoever, the external pin P3.2 can control whether or
not our timer is running or not.
We've discussed how a timer can be used for the obvious purpose of keeping track
of time. However, the 8051 also allows us to use the timers to count events.
How can this be useful? Let's say you had a sensor placed across a road that would
send a pulse every time a car passed over it. This could be used to determine the
volume of traffic on the road. We could attach this sensor to one of the 8051's I/O
lines and constantly monitor it, detecting when it pulsed high and then incrementing
our counter when it went back to a low state. This is not terribly difficult, but
Prepared by: Vivek Joshi(08MTES17) 100
requires some code. Let's say we hooked the sensor to P1.0; the code to count cars
passing would look something like this:
JNB P1.0,$ ;If a car hasn't raised the signal, keep waiting
;The line is high which means the car is on the sensor right
JB P1.0,$
now
INC COUNTER ;The car has passed completely, so we count it
As you can see, it's only three lines of code. But what if you need to be doing other
processing at the same time? You can't be stuck in the JNB P1.0,$ loop waiting for a
car to pass if you need to be doing other things. Of course, there are ways to get
around even this limitation but the code quickly becomes big, complex, and ugly.
Luckily, since the 8051 provides us with a way to use the timers to count events we
don't have to bother with it. It is actually painfully easy. We only have to configure
one additional bit.
Let's say we want to use Timer 0 to count the number of cars that pass. If you look
back to the bit table for the TCON SFR you will there is a bit called "C/T0"--it's bit
2 (TCON.2). Reviewing the explanation of the bit we see that if the bit is clear then
timer 0 will be incremented every machine cycle. This is what we've already used to
measure time. However, if we set C/T0 timer 0 will monitor the P3.4 line. Instead of
being incremented every machine cycle, timer 0 will count events on the P3.4 line.
So in our case we simply connect our sensor to P3.4 and let the 8051 do the work.
Then, when we want to know how many cars have passed, we just read the value of
timer 0--the value of timer 0 will be the number of cars that have passed.
So what exactly is an event? What does timer 0 actually "count?" Speaking at the
electrical level, the 8051 counts 1-0 transitions on the P3.4 line. This means that
when a car first runs over our sensor it will raise the input to a high ("1") condition.
At that point the 8051 will not count anything since this is a 0-1 transition. However,
when the car has passed the sensor will fall back to a low ("0") state. This is a 1-0
transition and at that instant the counter will be incremented by 1.
It is important to note that the 8051 checks the P3.4 line each instruction cycle (12
clock cycles). This means that if P3.4 is low, goes high, and goes back low in 6
clock cycles it will probably not be detected by the 8051. This also means the 8051
event counter is only capable of counting events that occur at a maximum of 1/24th
the rate of the crystal frequency. That is to say, if the crystal frequency is 12.000
Mhz it can count a maximum of 500,000 events per second (12.000 Mhz * 1/24 =
500,000). If the event being counted occurs more than 500,000 times per second it
will not be able to be accurately counted by the 8051.
void Tdelay();
void main()
{
while(1)
{
P1=0x55;
Tdelay();
P1=0xAA;
Tdelay();
}
}
void Tdelay()
{
TMOD=0x01;
TL0=0x00;
TH0=0x35;
TR0=1;
while(TF0==0);
TR0=0;
TF0=0;
}
FFFFH-3500H=CAFFH=51967+1=51968
51968x1.085us=56.384 ms is the approximate delay.
#C program to toggle only bit P1.5 continuously every 50ms using Timer0,
mode1(16bit) to create delay.
void Tdelay();
sbit mybit=P1^5;
void main()
{
while(1)
{
mybit=~mybit;
Tdelay();
}
}
Prepared by: Vivek Joshi(08MTES17) 102
void Tdelay()
{
TMOD=0x01;
TL0=0xFD;
TH0=0x4B;
TR0=1;
while(TF0==0);
TR0=0;
TF0=0;
Exercise:
1. Write a C program to toggle all bits of P2 continuously every 500ms. Use
timer 1, mode 1 to create delay.
2. Write a C program to toggle pin1.5 continuously every 250ms. Use timer 0,
mode 2 (8 bit auto reload) to create delay.
3. Write a C program to create a square wave of 2500Hz at P2.7. Use timer 1,
mode 2.
}while(TF1==0);
TR1=0;
TF1=0;
}
}
II.10
Interrupts
As the name implies, an interrupt is some event which interrupts normal program
execution.
As stated earlier, 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 occured. Once complete, control would be returned to the original program. The
main program never even knows it was interrupted.
The ability to interrupt normal program execution when certain events occur makes
it much easier and much more efficient to handle certain conditions. If it were not
for interrupts we would have to manually check in our main program whether the
timers had overflown, whether we had received another character via the serial port,
or if some external event had occured. Besides making the main program ugly and
hard to read, such a situation would make our program inefficient since wed be
burning precious "instruction cycles" checking for events that usually dont happen.
For example, lets say we have a large 16k program executing many subroutines
performing many tasks. Lets also suppose that we want our program to
JNB TF0,SKIP_TOGGLE
CPL P3.0
CLR TF0
SKIP_TOGGLE: ...
Since the TF0 flag is set whenever timer 0 overflows, the above code will toggle
P3.0 every time timer 0 overflows. This accomplishes what we want, but is
inefficient. The JNB instruction consumes 2 instruction cycles to determine that the
flag is not set and jump over the unnecessary code. In the event that timer 0
overflows, the CPL and CLR instruction require 2 instruction cycles to execute. To
make the math easy, lets say the rest of the code in the program requires 98
instruction cycles. Thus, in total, our code consumes 100 instruction cycles (98
instruction cycles plus the 2 that are executed every iteration to determine whether
or not timer 0 has overflowed). If were in 16-bit timer mode, timer 0 will overflow
every 65,536 machine cycles. In that time we would have performed 655 JNB tests
for a total of 1310 instruction cycles, plus another 2 instruction cycles to perform the
code. So to achieve our goal weve spent 1312 instruction cycles. So 2.002% of our
time is being spent just checking when to toggle P3.0. And our code is ugly because
we have to make that check every iteration of our main program loop.
Luckily, this isnt necessary. Interrupts let us forget about checking for the condition.
The microcontroller itself will check for the condition automatically and when the
condition is met will jump to a subroutine (called an interrupt handler), execute the
code, then return. In this case, our subroutine would be nothing more than:
CPL P3.0
RETI
First, youll notice the CLR TF0 command has disappeared. Thats because when the
8051 executes our "timer 0 interrupt routine," it automatically clears the TF0 flag.
Youll also notice that instead of a normal RET instruction we have a RETI
instruction. The RETI instruction does the same thing as a RET instruction, but tells
the 8051 that an interrupt routine has finished. You must always end your interrupt
handlers with RETI.
Thus, every 65536 instruction cycles we execute the CPL instruction and the RETI
instruction. Those two instructions together require 3 instruction cycles, and weve
accomplished the same goal as the first example that required 1312 instruction
cycles. As far as the toggling of P3.0 goes, our code is 437 times more efficient! Not
to mention its much easier to read and understand because we dont have to
remember to always check for the timer 0 flag in our main program. We just setup
Prepared by: Vivek Joshi(08MTES17) 105
the interrupt and forget about it, secure in the knowledge that the 8051 will execute
our code whenever its necessary.
The same idea applies to receiving data via the serial port. One way to do it is to
continuously check the status of the RI flag in an endless loop. Or we could check
the RI flag as part of a larger program loop. However, in the latter case we run the
risk of missing characters--what happens if a character is received right after we do
the check, the rest of our program executes, and before we even check RI a second
character has come in. We will lose the first character. With interrupts, the 8051 will
put the main program "on hold" and call our special routine to handle the reception
of a character. Thus, we neither have to put an ugly check in our main code nor will
we lose characters.
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.
In other words, we can configure the 8051 so that when Timer 0 Overflows or when
a character is sent/received, the appropriate interrupt handler routines are called.
By consulting the above chart we see that whenever Timer 0 overflows (i.e., the TF0
bit is set), the main program will be temporarily suspended and control will jump to
Setting Up Interrupts
By default at powerup, all interrupts are disabled. This means that even if, for
example, the TF0 bit is set, the 8051 will not execute the interrupt. Your program
must specifically tell the 8051 that it wishes to enable interrupts and specifically
which interrupts it wishes to enable.
Your program may enable and disable interrupts by modifying the IE SFR (A8h):
As you can see, each of the 8051s interrupts has its own bit in the IE SFR. You
enable a given interrupt by setting the corresponding bit. For example, if you wish to
enable Timer 1 Interrupt, you would execute either:
MOV IE,#08h
or
SETB ET1
Both of the above instructions set bit 3 of IE, thus enabling Timer 1 Interrupt. Once
Timer 1 Interrupt is enabled, whenever the TF1 bit is set, the 8051 will automatically
put "on hold" the main program and execute the Timer 1 Interrupt Handler at
address 001Bh.
However, before Timer 1 Interrupt (or any other interrupt) is truly enabled, you must
also set bit 7 of IE. Bit 7, the Global Interupt Enable/Disable, enables or disables all
interrupts simultaneously. That is to say, if bit 7 is cleared then no interrupts will
occur, even if all the other bits of IE are set. Setting bit 7 will enable all the
interrupts that have been selected by setting other bits in IE. This is useful in
program execution if you have time-critical code that needs to execute. In this case,
Prepared by: Vivek Joshi(08MTES17) 107
you may need the code to execute from start to finish without any interrupt getting in
the way. To accomplish this you can simply clear bit 7 of IE (CLR EA) and then set
it after your time-criticial code is done.
So, to sum up what has been stated in this section, to enable the Timer 1 Interrupt
the most common approach is to execute the following two instructions:
SETB ET1
SETB EA
Thereafter, the Timer 1 Interrupt Handler at 01Bh will automatically be called
whenever the TF1 bit is set (upon Timer 1 overflow).
Polling Sequence
The 8051 automatically evaluates whether an interrupt should occur after every
instruction. When checking for interrupt conditions, it checks them in the following
order:
• External 0 Interrupt
• Timer 0 Interrupt
• External 1 Interrupt
• Timer 1 Interrupt
• Serial Interrupt
This means that if a Serial Interrupt occurs at the exact same instant that an External
0 Interrupt occurs, the External 0 Interrupt will be executed first and the Serial
Interrupt will be executed once the External 0 Interrupt has completed.
Interrupt Priorities
The 8051 offers two levels of interrupt priority: high and low. By using interrupt
priorities you may assign higher priority to certain interrupt conditions.
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.
When an interrupt is triggered, the following actions are taken automatically by the
microcontroller:
Take special note of the third step: If the interrupt being handled is a Timer or
External interrupt, the microcontroller automatically clears the interrupt flag before
An interrupt ends when your program executes the RETI (Return from Interrupt)
instruction. When the RETI instruction is executed the following actions are taken
by the microcontroller:
• Two bytes are popped off the stack into the Program Counter to restore
normal program execution.
• Interrupt status is restored to its pre-interrupt status.
Serial Interrupts
Serial Interrupts are slightly different than the rest of the interrupts. This is due to the
fact that there are two interrupt flags: RI and TI. If either flag is set, a serial interrupt
is triggered. As you will recall from the section on the serial port, the RI bit is set
when a byte is received by the serial port and the TI bit is set when a byte has been
sent.
This means that when your serial interrupt is executed, it may have been triggered
because the RI flag was set or because the TI flag was set--or because both flags
were set. Thus, your routine must check the status of these flags to determine what
action is appropriate. Also, since the 8051 does not automatically clear the RI and TI
flags you must clear these bits in your interrupt handler.
JNB
INT_SERIAL: ;If the RI flag is not set, we jump to check TI
RI,CHECK_TI
;If we got to this line, its because the RI bit
MOV A,SBUF
*was* set
CLR RI ;Clear the RI bit after weve processed it
;If the TI flag is not set, we jump to the exit
CHECK_TI: JNB TI,EXIT_INT
point
;Clear the TI bit before we send another
CLR TI
character
MOV SBUF,#A ;Send another character to the serial port
EXIT_INT: RETI
One very important rule applies to all interrupt handlers: Interrupts must leave the
processor in the same state as it was in when the interrupt initiated.
Remember, the idea behind interrupts is that the main program isnt aware that they
are executing in the "background." However, consider the following code:
After the above three instructions are executed, the accumulator will contain a value
of 35h.
But what would happen if right after the MOV instruction an interrupt occured.
During this interrupt, the carry bit was set and the value of the accumulator was
changed to 40h. When the interrupt finished and control was passed back to the main
program, the ADDC would add 10h to 40h, and additionally add an additional 1h
because the carry bit is set. In this case, the accumulator will contain the value 51h at
the end of execution.
In this case, the main program has seemingly calculated the wrong answer. How can
25h + 10h yield 51h as a result? It doesnt make sense. A programmer that was
unfamiliar with interrupts would be convinced that the microcontroller was damaged
in some way, provoking problems with mathematical calculations.
What has happened, in reality, is the interrupt did not protect the registers it used.
Restated: An interrupt must leave the processor in the same state as it was in when
the interrupt initiated.
What does this mean? It means if your interrupt uses the accumulator, it must insure
that the value of the accumulator is the same at the end of the interrupt as it was at
the beginning. This is generally accomplished with a PUSH and POP sequence. For
example:
The guts of the interrupt is the MOV instruction and the ADD instruction. However,
these two instructions modify the Accumulator (the MOV instruction) and also
modify the value of the carry bit (the ADD instruction will cause the carry bit to be
set). Since an interrupt routine must guarantee that the registers remain unchanged
by the routine, the routine pushes the original values onto the stack using the PUSH
instruction. It is then free to use the registers it protected to its hearts content. Once
the interrupt has finished its task, it pops the original values back into the registers.
When the interrupt exits, the main program will never know the difference because
the registers are exactly the same as they were before the interrupt executed.
• PSW
• DPTR (DPH/DPL)
• PSW
• ACC
• B
• Registers R0-R7
Remember that PSW consists of many individual bits that are set by various 8051
instructions. Unless you are absolutely sure of what you are doing and have a
complete understanding of what instructions set what bits, it is generally a good idea
to always protect PSW by pushing and popping it off the stack at the beginning and
end of your interrupts.
Note also that most assemblers (in fact, ALL assemblers that I know of) will not
allow you to execute the instruction:
PUSH R0
This is due to the fact that depending on which register bank is selected, R0 may
refer to either internal ram address 00h, 08h, 10h, or 18h. R0, in and of itself, is not a
valid memory address that the PUSH and POP instructions can use.
Thus, if you are using any "R" register in your interrupt routine, you will have to
push that registers absolute address onto the stack instead of just saying PUSH R0.
For example, instead of PUSH R0 you would execute:
Prepared by: Vivek Joshi(08MTES17) 112
PUSH 00h
Of course, this only works if youve selected the default register set. If you are using
an alternate register set, you must PUSH the address which corresponds to the
register you are using.
Interrupts are a very powerful tool available to the 8051 developer, but when used
incorrectly they can be a source of a huge number of debugging hours. Errors in
interrupt routines are often very difficult to diagnose and correct.
If you are using interrupts and your program is crashing or does not seem to be
performing as you would expect, always review the following interrupt-related
issues:
• Register Protection: Make sure you are protecting all your registers, as
explained above. If you forget to protect a register that your main program is
using, very strange results may occur. In our example above we saw how
failure to protect registers caused the main program to apparently calculate
that 25h + 10h = 51h. If you witness problems with registers changing values
unexpectedly or operations producing "incorrect" values, it is very likely that
you've forgotten to protect registers. ALWAYS PROTECT YOUR
REGISTERS.
• Forgetting to restore protected values: Another common error is to
push registers onto the stack to protect them, and then forget to pop them off
the stack before exiting the interrupt. For example, you may push ACC, B,
and PSW onto the stack in order to protect them and subsequently pop only
ACC and PSW off the stack before exiting. In this case, since you forgot to
restore the value of "B", an extra value remains on the stack. When you
execute the RETI instruction the 8051 will use that value as the return
address instead of the correct value. In this case, your program will almost
certainly crash. ALWAYS MAKE SURE YOU POP THE SAME
NUMBER OF VALUES OFF THE STACK AS YOU PUSHED ONTO
IT.
• Using RET instead of RETI: Remember that interrupts are always
terminated with the RETI instruction. It is easy to inadvertently use the RET
instruction instead. However, the RET instruction will not end your
interrupt. Usually, using a RET instead of a RETI will cause the illusion of
your main program running normally, but your interrupt will only be
executed once. If it appears that your interrupt mysteriously stops executing,
verify that you are exiting with RETI.
#Program that continuously gets a single bit of data from P1.7 and sends it
to P1.0 while simultaneously creating a square wave of 200us period on pin
P2.5. Use timer 0 to create square wave.
Half period=100us
100/1.085=92 and TH0=256-92=164 or A4H
sbit SW=P1^7;
sbit IND=P1^0;
sbit Wave=P2^5;
void timer0() interrupt 1
{
Wave=~Wave;
}
void main()
{
SW=1;
TMOD=0x02;
TH0=0xA4;
IE=0x82;
while(1)
{
IND=SW;
}
}
Prepared by: Vivek Joshi(08MTES17) 114
Exercise
1. Write a C program to toggle all the bits of P1 and toggling should stop
whenever some interrupt comes at INT0.
2. Write a C program show 0 to 255 at P0…when ever an external switch is
pressed. Numbering should be reversed i. e. 255 to 0.
3. Write a C program to put a sequence 1, 2, 4, 8…at P0 simultaneously 1,3,
7, 15, 31… at P1 with delay of 500ms. Use timer 0, mode 1.
4. Write a C program to display the number on certain port for which the
controller was interrupted externally at INT1.
5. Write a C program to start P0 counting from 0 to 255 whenever first
external interrupt comes. And then P1 whenever second comes.
II.11
Serial Communication in 8051
One of the 8051s many powerful features is its integrated UART, otherwise known
as a serial port. The fact that the 8051 has an integrated serial port means that you
may very easily read and write values to the serial port. If it were not for the
integrated serial port, writing a byte to a serial line would be a rather tedious process
requring turning on and off one of the I/O lines in rapid succession to properly
"clock out" each individual bit, including start bits, stop bits, and parity bits.
However, we do not have to do this. Instead, we simply need to configure the serial
ports operation mode and baud rate. Once configured, all we have to do is write to
an SFR to write a value to the serial port or read the same SFR to read a value from
the serial port. The 8051 will automatically let us know when it has finished sending
the character we wrote and will also let us know whenever it has received a byte so
that we can process it. We do not have to worry about transmission at the bit level--
which saves us quite a bit of coding and processing time.
The first thing we must do when using the 8051s integrated serial port is, obviously,
configure it. This lets us tell the 8051 how many data bits we want, the baud rate we
will be using, and how the baud rate will be determined.
First, lets present the "Serial Control" (SCON) SFR and define what each bit of the
SFR represents:
(*) Note: The baud rate indicated in this table is doubled if PCON.7 (SMOD) is set.
The SCON SFR allows us to configure the Serial Port. Thus, well go through each
bit and review its function.
Bits SM0 and SM1 let us set the serial mode to a value between 0 and 3, inclusive.
The four modes are defined in the chart immediately above. As you can see,
selecting the Serial Mode selects the mode of operation (8-bit/9-bit, UART or Shift
Register) and also determines how the baud rate will be calculated. In modes 0 and 2
the baud rate is fixed based on the oscillators frequency. In modes 1 and 3 the baud
rate is variable based on how often Timer 1 overflows. Well talk more about the
various Serial Modes in a moment.
The next bit, REN, is "Receiver Enable." This bit is very straightforward: If you
want to receive data via the serial port, set this bit. You will almost always want to
set this bit.
The last four bits (bits 0 through 3) are operational bits. They are used when actually
sending and receiving data--they are not used to configure the serial port.
The TB8 bit is used in modes 2 and 3. In modes 2 and 3, a total of nine data bits are
transmitted. The first 8 data bits are the 8 bits of the main value, and the ninth bit is
taken from TB8. If TB8 is set and a value is written to the serial port, the datas bits
will be written to the serial line followed by a "set" ninth bit. If TB8 is clear the
ninth bit will be "clear."
The RB8 also operates in modes 2 and 3 and functions essentially the same way as
TB8, but on the reception side. When a byte is received in modes 2 or 3, a total of
nine bits are received. In this case, the first eight bits received are the data of the
serial byte received and the value of the ninth bit received will be placed in RB8.
TI means "Transmit Interrupt." When a program writes a value to the serial port, a
certain amount of time will pass before the individual bits of the byte are "clocked
out" the serial port. If the program were to write another byte to the serial port before
the first byte was completely output, the data being sent would be garbled. Thus, the
8051 lets the program know that it has "clocked out" the last byte by setting the TI
bit. When the TI bit is set, the program may assume that the serial port is "free" and
ready to send the next byte.
Finally, the RI bit means "Receive Interrupt." It funcions similarly to the "TI" bit,
but it indicates that a byte has been received. That is to say, whenever the 8051 has
received a complete byte it will trigger the RI bit to let the program know that it
needs to read the value quickly, before another byte is read.
In modes 1 and 3, the baud rate is determined by how frequently timer 1 overflows.
The more frequently timer 1 overflows, the higher the baud rate. There are many
ways one can cause timer 1 to overflow at a rate that determines a baud rate, but the
most common method is to put timer 1 in 8-bit auto-reload mode (timer mode 2) and
set a reload value (TH1) that causes Timer 1 to overflow at a frequency appropriate
to generate a baud rate.
To determine the value that must be placed in TH1 to generate a given baud rate, we
may use the following equation (assuming PCON.7 is clear).
But not quite... to achieve 19,200 baud we simply need to set PCON.7 (SMOD).
When we do this we double the baud rate and utilize the second equation mentioned
above. Thus we have:
Once the Serial Port has been propertly configured as explained above, the serial
port is ready to be used to send data and receive data. If you thought that configuring
the serial port was simple, using the serial port will be a breeze.
To write a byte to the serial port one must simply write the value to the SBUF (99h)
SFR. For example, if you wanted to send the letter "A" to the serial port, it could be
accomplished as easily as:
MOV SBUF,#A
Upon execution of the above instruction the 8051 will begin transmitting the
character via the serial port. Obviously transmission is not instantaneous--it takes a
measureable amount of time to transmit. And since the 8051 does not have a serial
output buffer we need to be sure that a character is completely transmitted before we
try to transmit the next character.
The 8051 lets us know when it is done transmitting a character by setting the TI bit
in SCON. When this bit is set we know that the last character has been transmitted
and that we may send the next character, if any. Consider the following code
segment:
Reading data received by the serial port is equally easy. To read a byte from the
serial port one just needs to read the value stored in the SBUF (99h) SFR after the
8051 has automatically set the RI flag in SCON.
For example, if your program wants to wait for a character to be received and
subsequently read it into the Accumulator, the following code segment may be used:
Prepared by: Vivek Joshi(08MTES17) 119
JNB RI,$ ;Wait for the 8051 to set the RI flag
MOV A,SBUF ;Read the character from the serial port
The first line of the above code segment waits for the 8051 to set the RI flag; again,
the 8051 sets the RI flag automatically when it receives a character via the serial
port. So as long as the bit is not set the program repeats the "JNB" instruction
continuously.
Once the RI bit is set upon character reception the above condition automatically
fails and program flow falls through to the "MOV" instruction which reads the
value.
#Program to send letter ‘A’ serially at baud rate 4800 continuously. Use 8 bit
data and 1 stop bit.
void main()
{
TMOD=0x20;
TH1=0xFA;
SCON=0x50;
TR1=1;
vhile(1)
{
SBUF=’A’;
While(TI==0);
TI=0;
}
}
void main()
{
TMOD=0x20;
TH1=0xFD;
SCON=0x50;
TR1=1;
while(1)
{
SerTx(‘Y’);
P1=mybyte;
RI=0;
}
}
Exercise
III.2
Decimal digit 0 1 2 3 4
BCD code 0000 0001 0010 0011 0100
Prepared by: Vivek Joshi(08MTES17) 123
Decimal digit 5 6 7 8 9
BCD code 0101 0110 0111 1000 1001
Your job for this lab is to design and test a circuit to convert a 4-bit BCD signal into
a 7-bit control signal according to the following figure and table:
74
LS
48
b3 b2 b1 b0 abcdefg
0000 0000001
0001 1001111
0010 0010010
0011 0000110
0100 1001100
0101 0100100
0110 0100000
0111 0001111
1000 0000000
1001 0000100
sfr adc=0x90;
sfr output=0xA0;
void main()
{
while(1)
{
output=adc;
}
}
Exercise
1. Write a C program to show the data from ADC to the seven segment display
2. Write a C program to get digital data corresponding to temperature of
surrounding and to display temperature on seven segment
3. What should be the step size and the Voltage at Vref/2 if one needs to convert
a voltage range of 0 to 3V into digital data.
III.4
DAC Interfacing
AD557
Modes of operation
UNIPOLAR 0 V TO 2.56 V OUTPUT RANGE
Figure 2 shows the configuration for the 0 V to 2.56 V fullscale output range.
Because of its precise factory calibration, the AD557 is intended to be operated
without user trims for gain and offset; therefore, no provisions have been made for
such user trims. If a small increase in scale is required, however, it may be
accomplished by slightly altering the effective gain of the output buffer. A resistor in
series with VOUT SENSE will increase the output range. Note that decreasing the
scale by putting a resistor in series with GND will not work properly due to the code
dependent currents in GND. Adjusting offset by injecting dc at GND is not
recommended for the same reason.
BIPOLAR –1.28 V TO +1.28 V OUTPUT RANGE
The AD557 was designed for operation from a single power supply and is thus
capable of providing only a unipolar 0 V to 2.56 V output range. If a negative supply
is available, bipolar output ranges may be achieved by suitable output offsetting and
scaling. Figure 3 shows how a ± 1.28 V output range may be achieved when a –5 V
power supply is available. The offset is provided by the AD589 precision 1.2 V
reference which will operate from a 5 V supply. The AD711 output amplifier can
provide the necessary ±1.28 V output swing from ±5 V supplies. Coding is
complementary offset binary.
Exercise
1. Write a program to pass digital data to DAC AD557 via port1 and check the
output using multimeter.
0x80
0xC0
1 Vss- Ground
2 Vcc - +5 Volt Supply
3 VEE- Power supply to control contrast
4 RS-Register Select, RS=0 to select command Register
RS=1 to select data register
5 R/W-Read/Write R/W=0 for write
R/W=1 for Read
6 E -I/O Enable
7-14- DB0-DB7 I/O The 8 bit data bus
15-16 Back light
#Program to send letters ‘A’, ‘B’ and ‘C’ to the LCD using delays.
sfr ldata=0x90;
sbit rs=P2^0;
sbit rw=P2^1;
sbit en=P2^2;
void delay(int);
void main()
{
lcdcmd(0x38);
delay(25);
lcdcmd(0x0e);
delay(25);
lcdcmd(0x01);
delay(25);
lcdcmd(0x86);
delay(25);
lcddata(‘a’);
delay(10);
lcddata(‘b’);
delay(25);
lcddata(‘c’);
delay(25);
Prepared by: Vivek Joshi(08MTES17) 131
}
Exercise
1. Write a C program to display your name on LCD.
2. Write a C program to display “SOEX” Scrolling leftward on LCD.
3. Write a C program to display name of all your friends one by one. To change
the name, use a switch.
4. Write a C program to accept data from a port(say P1) and show its decimal,
hexadecimal octal and binary values on LCD.
5. Write a C program to display numbers from 00 to 99 one by one at same place
of LCD.
There are many kind of stepper motors. Unipolar type, Bipolar type, Single-phase
type, Multi-phase type... Single-phase stepper motor is often used for quartz watch.
This section will explain the operation principle of the 2-phase unipolar PM type
stepper motor.
In the PM type stepper motor, a permanent magnet is used for rotor and coils are put
on stator. The stepper motor model which has 4-poles is shown in the figure on the
left. In case of this motor, step angle of the rotor is 90 degrees.
As for four poles, the top and the bottom and either side are a pair. coil, coil and
coil, coil correspond respectively. For example, coil and coil are put to the upper
and lower pole. coil and coil are rolled up for the direction of the pole to become
opposite when applying an electric current to the coil and applying an electric
current to the coil. It is similar about and , too.
The turn of the motor is controlled by the electric current which pours into , ,
Prepared by: Vivek Joshi(08MTES17) 135
and . The rotor rotational speed and the direction of the turn can be controlled by
this control.
These section demonstrates how to read a HEX keypad, these are a standard device
with 16 keys connected in a 4x4 matrix, giving the characters 0-9 and A-F. You can
also use a 4x3 keypad, which gives the numbers 0-9, * and #.
As the switches are all interconnected, we need a way to differentiate between the
different ones - the four resistors on the interface board pull lines COL1 to COL4
high, these four lines are the ones which are read in the program. So in the absence
of any switch been pressed these lines will all read high. The four ROW connections
are connected to output pins, and if these are set high the switches will effectively do
nothing - connecting a high level to a high level, results in a high level.
In order to detect a switch we need to take the ROW lines low, so if we take all
the ROW lines low - what happens?. Assuming we press button 1, this joins COL1
with ROW1, as ROW1 is now at a low level, this will pull COL1 down resulting in a
low reading on COL1. Unfortunately if we press button 4, this joins COL1 with
ROW2, as ROW2 is at a low level this also results in a low reading at COL1. This
The way round this is to only switch one ROW at a time low, so assuming we set
ROW1 low we can then read just the top row of buttons, button 1 will take COL1
low, button2 will take COL2 low, and the same for buttons '3' and 'F' in COL3 and
COL4. The twelve lower buttons won't have any effect as their respective ROW
lines are still high. So to read the other buttons we need to take their respective
ROW lines low, taking ROW2 low will allow us to read the second row of buttons
(4, 5, 6, and E), again as the other three ROW lines are now high the other 12
buttons have no effect. We can then repeat this for the last two ROW's using ROW3
and ROW4, so we read four buttons at a time, taking a total of four readings to read
the entire keypad - this is a common technique for reading keyboards, and is called
'Keyboard Scanning'.
One obvious problem is what happens if you press more than one key at a time?,
there are a number of ways to deal with this, one way would be to check for multiple
key presses and ignore them, a simpler way (and that used in the examples) is to
accept the first key you find which is pressed. You will find that various commercial
products deal with this situation in similar ways, some reject multiple key presses,
and some just accept the first one.
while(1)
{
ROW=0xFE;
colloc=COL;
colloc&=0x0F;
if(colloc!=0x0F)
{
rowlock=0;
break;
}
ROW=0xFD;
colloc=COL;
colloc&=0x0F;
if(colloc!=0x0F)
{
rowlock=1;
break;
}
ROW=0xFB;
colloc=COL;
colloc&=0x0F;
if(colloc!=0x0F)
{
rowlock=2;
break;
}
ROW=0xF7;
colloc=COL;
Prepared by: Vivek Joshi(08MTES17) 139
colloc&=0x0F;
rowlock=3;
break;
}
if(colloc==0x0E)
P1=keypad[rowloc][0];
if(colloc==0x0D)
P1=keypad[rowloc][1];
if(colloc==0x0B)
P1=keypad[rowloc][2];
if(colloc==0x07)
P1=keypad[rowloc][3];
}
}
void delay(int del)
{
vor(i=0;i<=125;i++)
vor(j=0;j<=del;j++);
}
Exercise
1. Write a C program to manage the count of how many times a key is being pressed
2. Write a C program to display the pressed key on LCD.
The RS232 connector was originally developed to use 25 pins. In this DB25
connector pinout provisions were made for a secondary serial RS232 communication
channel. In practice, only one serial communication channel with accompanying
handshaking is present. Only very few computers have been manufactured where
both serial RS232 channels are implemented. Examples of this are the Sun
SparcStation 10 and 20 models and the Dec Alpha Multia. Also on a number of
Telebit modem models the secondary channel is present. It can be used to query the
modem status while the modem is on-line and busy communicating. On personal
computers, the smaller DB9 version is more commonly used today. The diagrams
show the signals common to both connector types in black. The defined pins only
present on the larger connector are shown in red. Note, that the protective ground is
assigned to a pin at the large connector where the connector outside is used for that
purpose with the DB9 connector version.
The pinout is also shown for the DEC modified modular jack. This type of connector
has been used on systems built by Digital Equipment Corporation; in the early days
one of the leaders in the mainframe world. Although this serial interface is
differential (the receive and transmit have their own floating ground level which is
not the case with regular RS232) it is possible to connect RS232 compatible devices
with this interface because the voltage levels of the bit streams are in the same range.
Where the definition of RS232 focussed on the connection of DTE, data terminal
equipment (computers, printers, etc.) with DCE, data communication equipment
(modems), MMJ was primarily defined for the connection of two DTE's directly.
Seven Segment
1. First select
File>External
Module
Setting>LED.
In the window
appears first
uncheck No
Seven
Segment
Display
chkbox.
Select Non-
multiplexed
radio button,
Color of
segment and
BCD option
as shown in
figure. And
click on
Selection of Port Lines and Number of Digits.
5.
6. Now load the corresponding hex file and run the simulation as explained
before.
Prepared by: Vivek Joshi(08MTES17) 148
LCD
1. First select File>External Module Settings>LCD
2. Set the things as shown in figure and click on Port Line Selection.
3. Configure the LCD as shown in figure(i.e. as per your program) and click OK.
V.1 ARM
The ARM architecture (previously, the Advanced RISC Machine, and prior to that
Acorn RISC Machine) is a 32-bit RISC processor architecture developed by ARM
Limited that is widely used in a number of embedded designs. Because of their
power saving features, ARM CPUs are dominant in the mobile electronics market,
where low power consumption is a critical design goal.
Today, the ARM family accounts for approximately 75% of all embedded 32-bit
RISC CPUs, making it one of the most prolific 32-bit architectures in the world.
ARM CPUs are found in all corners of consumer electronics, from portable devices
(PDAs, mobile phones, media players, handheld gaming units, and calculators) to
computer peripherals (hard drives, desktop routers). Important branches in this
family include Marvell's XScale and the Texas Instruments OMAP series.
• Load/store architecture
• No support for misaligned memory accesses (now supported in ARMv6 cores)
• Orthogonal instruction set
• Large 16 × 32-bit register file
• Fixed instruction width of 32 bits to ease decoding and pipelining, at the cost
of decreased code density
• Mostly single-cycle execution
To compensate for the simpler design, compared with contemporary processors like
the Intel 80286 and Motorola 68020, some unique design features were used:
Newer ARM processors have a compressed instruction set, called Thumb, that
uses a 16-bit-wide instruction encoding (but still processes 32-bit data). In Thumb,
the smaller opcodes have less functionality. For example, only branches can be
conditional, and many opcodes cannot access all of the CPU's registers. However,
the shorter opcodes give improved code density overall, even though some
operations require more instructions. Particularly in situations where the memory
port or bus width is constrained to less than 32 bits, the shorter Thumb opcodes
allows greater performance than with 32-bit code because of the more efficient use
of the limited memory bandwidth. Typically embedded hardware has a small range
of addresses of 32-bit datapath and the rest are 16 bits or narrower (e.g. the Game
Boy Advance). In this situation, it usually makes sense to compile Thumb code and
hand-optimise a few of the most CPU-intensive sections using the (non-Thumb)
32-bit instruction set, placing them in the limited 32-bit bus width memory.
The first processor with a Thumb instruction decoder was the ARM7TDMI. All
ARM9 and later families, including XScale have included a Thumb instruction
decoder.
Jazelle
A technology called Jazelle DBX (Direct Bytecode eXecution) allows some ARM
architectures to execute Java bytecode in hardware as another execution state
alongside the existing ARM and Thumb states. It provides acceleration for some
bytecodes while calling out to special software for others.
The first processor with Jazelle technology was the ARM926EJ-S[6]: Jazelle being
denoted by the 'J' in the CPU name. It is used by mobile phone manufacturers to
speed up execution of Java ME games and applications.
Register Windows
32 Registers, Procedure Entry & Exit
Advantage: Less Memory Accesses
In ARM Shadow Registers used to handle Exceptions are of similar concepts
Reason for Rejecting this feature:
Large Chip Area (Cost grounds)
♦ In user level programs uses CPSR to store the condition code bits
– N Negative
– C Carry
– Z Zero
– V Overflow
♦ The bottom bits are protected by the user level program
– I, F, T, mode[4:0]
3 2 2
8 7 6 5 4 0
1 8 7
NZCV unused IF T mode
Memory System
Prepared by: Vivek Joshi(08MTES17) 154
♦ Memory may be viewed as linear array of bytes number from 0 to 2^32 –1
♦ Data Bytes may be 8-bit (B), 16-bit (HW), or 32-bit (W)
♦ Words are always aligned at 4-byte boundaries i.e least two bits are zero
♦ Half Words are aligned on even boundaries
Load/Store Architecture
Mov Instructions
MOV r0, r2 r0 := r2
MVN r0, r2 r0 := not r2
Compare Instructions
Shift Instructions
Memory Organization
• Uses different word sizes and address space sizes for instruction and data
• A Sharc instruction consists of 48 bits; and an address of 32 bits.
• Sharc family include significant amount of on-chip memory
• Internal memory is evenly divided between program memory and data
memory.
• More memory can be added off-chip.
I0 M0 L0 B0 M8 B8
I8 L8
I1 M1 L1 B1 B9
I9 M9 L9
I2 M2 L2 B2 M1 B1
I3 I10 L10 0
M3 L3 B3 0 B1
I11 M1 L11 1
1
M1 B1
I4 M4 L4 B4 I12 L12
2 2
B1
I5 M5 L5 B5 I13 M13 L13 3
B1
I6 M6 L6 B6 I14 M14 L14 4
B1
I7 M7 L7 B7 I15 M15 L15 5
V.3 PIC
Microchip manufacture a series of microcontrollers called PIC. There are many
different flavours available, some basic low memory types, going right up through to
ones that have Analogue - To- Digital converters and even PWM built in. We are
going to concentrate on the 16F84 PIC. Once you have learnt how to program one
type of PIC, learning the rest is easy.
There are several ways of programming the PIC - using BASIC, C, or Assembly
Language. We are going to show you the Assembly Language. Don't be put off by
this. There are only 35 instructions to learn, and it is the cheapest way to program
the PICs, as you do not need any extra software other than the freebies.
RA0 To RA4
RA is a bidirectional port. That is, it can be configured as an input or an output.
The number following RA is the bit number (0 to 4). So, we have one 5-bit
directional port where each bit can be configured as Input or Output.
RB0 To RB7
RB is a second bidirectional port. It behaves in exactly the same way as RA, except
there are 8 - bits involved.
MCLR
This pin is used to erase the memory locations inside the PIC (i.e. when we want to
re-program it). In normal use it is connected to the positive supply rail.
INT
This is an input pin which can be monitored. If the pin goes high, we can cause the
program to restart, stop or any other single function we desire. We won't be using
this one much.
The Registers
A register is a place inside the PIC that can be written to, read from or both. Think
of a register as a piece of paper where you can look at and write information on.
The figure below shows the register file map inside the PIC16F84. Don’t worry if
you haven’t come across anything like this before, it is only to show where the
different bits and pieces are inside the PIC, and will help explain a few of the
commands.
STATUS
These are located at addresses 85h and 86h respectively. To program a pin to be an
output or an input, we simply send a 0 or a 1 to the relevant bit in the register. Now,
this can either be done in binary, or hex. We personally use both, as the binary does
help visualize the port. If you are not conversant with converting from binary to hex
and vice versa, then use a scientific calculator.
So, on Port A we have 5 pins, and hence 5 bits. If We wanted to set one of the pins
to input, We send a ‘1’ to the relevant bit. If We wanted to set one of the pins to an
output, We set the relevant bit to ‘0’. The bits are arranges in exactly the same way
as the pins, in other words bit 0 is RA0, bit 1 is RA1, bit 2 is RA2 and so on. Let’s
take an example. If We wanted to set RA0, RA3 and RA4 as outputs, and RA1 and
RA2 as inputs, We send this: 00110 (06h). Note that bit zero is on the right, as
shown:
Bit Number 4 3 2 1 0
Binary 0 0 1 1 0
To send one of our output pins high, we simply send a ‘1’ to the corresponding bit
in our PORTA or PORTB register. The same format follows as for the TRISA and
TRISB registers. To read if a pin is high or low on our port pins, we can perform a
check to see if the particular corresponding bit is set to high (1) or set to low (0)
Before We give an example code, We need to explain just two more register – w and
f.
The W register is a general register in which you can put any value that you wish.
Once you have assigned a value to W, you can add it to another value, or move it. If
you assign another value to W, its contents are overwritten.
V.4 AVR
The Atmel AVRTM is a family of 8-bit RISC microcontrollers produced by Atmel.
The AVR architecture was conceived by two students at the Norwegian Institute of
Technology (NTH) and further refined and developed at Atmel Norway, the Atmel
daughter company founded by the two chip architects.
Memory
All these memories are on the same chip as the CPU core. Each kind of memory is
separated from each other, in different locations on the chip. Address 0 in data
memory is distinct from address 0 in program flash and address 0 in EEPROM.
Program Memory
All AVR microcontrollers have some amount of 16 bit wide non-volatile flash
memory for program storage, from 1KB up to 256KB (or, 512-128K typical
program words). The program memory holds the executable program opcodes and
static data tables. Program memory is linearly addressed, and so mechanisms like
page banking or segment registers are not required to call any function, regardless
of its location in program memory.
AVRs cannot use external program memory; the flash memory on the chip is the
only program memory available to the AVR core.
The flash program memory can be reprogrammed using a programming tool, the
most popular being those that program the chip in situ and are called in-system
programmers (ISP). Atmel AVRs can also be reprogrammed with a high-voltage
parallel or serial programmer, and via JTAG (again, in situ) on certain chips. The
flash memory in an AVR can be re-programmed at least 10,000 times.
Many of the newer AVRs (MegaAVR series) have the capability to self-program
the flash memory. This functionality is used mainly by bootloaders.
Data Memory
Data Memory includes the registers, the I/O registers, and internal SRAM.
The AVR has thirty-two general purpose eight-bit registers (R0 to R31), six of
which can be used in pairs as sixteen-bit pointers (X, Y, and Z).
All AVR microcontrollers have some amount of RAM, from 32 bytes up to several
KB. This memory is byte addressable. The register file (both general and special
purpose) is mapped into the first addresses and thus accessible also as RAM. Some
of the tiniest AVR microcontrollers have only the register file as their RAM.
The data address space consists of the register file, I/O registers, and SRAM. The
working registers are mapped in as the first thirty-two memory spaces (000016-
001F16) followed by the reserved space for up to 64 I/O registers (002016-005F16).
The actual usable SRAM starts after both these sections (address 006016). (Note
Prepared by: Vivek Joshi(08MTES17) 163
that the I/O register space may be larger on some more extensive devices, in which
case the beginning address of SRAM will be higher.) Even though there are
separate addressing schemes and optimized opcodes for register file and I/O
register access, they can still be addressed and manipulated as if they were SRAM.
The I/O registers (and the program counter) are reset to their default starting values
when a reset occurs. The registers and the rest of SRAM have initial random
values, so typically one of the first things a program does is clear them to all zeros
or load them with some other initial value.
The registers, I/O registers, and SRAM never wear out, no matter how many times
they are written.
Some of the higher pin-count AVR microcontrollers allow for external expansion
of the data space, addressable up to 64KB. When enabled, external SRAM is
overlaid by internal SRAM; an access to address 000016 in the data space will
always resolve to on-chip memory. Depending on the amount of on-chip SRAM
present in the particular AVR, anywhere from 512 bytes to several KB of external
RAM will not be accessible. This usually does not cause a problem.
The support circuitry required is described in the datasheet for any device that
supports external data memory, such as the Mega 162, in the "External Memory
Interface" section. The support circuitry is minimal, consisting of a '573 or similar
latch, and potentially some chip select logic. The SRAM chip select may be tied to
a logic level that permanently enables the chip, or it may be driven by a pin from
the AVR. For an SRAM of 32KB or less, one option is to use a higher-order
address line to drive the chip select line to the SRAM.
EEPROM Storage
Almost all AVR microcontrollers have internal EEPROM memory for non-volatile
data storage. Only the Tiny11 and Tiny28 have no EEPROM.
EEPROM memory is not directly mapped in either the program or data space, but
is instead accessed indirectly as a peripheral, using I/O registers. Many compilers
available for the AVR hide some or all of the details of accessing EEPROM. IAR's
C compiler for the AVR recognizes the compiler-specific keyword __eeprom on a
variable declaration. Thereafter, a person writes code to read and write that
variable with the same standard C syntax as normal variables (in RAM), but the
compiler generates code to access the EEPROM instead of regular data memory.
Many of the AVRs have errata about writing to EEPROM address 0 under certain
power conditions (usually during brownout), and so Atmel recommends that
programs not use that address in the EEPROM.
Fuse Settings
A Fuse is an EEPROM bit that controls low level features and pin assignments.
Fuses are not accessible by the program; they can only be changed by a chip
programmer. Fuses control features which must be set before the chip can come
out of reset and begin executing code.
Reset
The AVR's RESET pin is an active-low input that forces a reset of the processor
and its integrated peripherals. The line can be driven by an external power-on reset
generator, a voltage supervisor (which asserts RESET when the power supply
voltage drops below a predefined threshold), or another component in a larger
system. For example, if the AVR is managing a few sensors and servos as part of a
large integrated system, another controller might observe some condition that
justifies resetting the AVR; it could do so by asserting the AVR's RESET line.
AVRs also include a watchdog timer, which can reset the processor when it times
out. The watchdog timer must be reset periodically to prevent it from timing out.
Failure to reset the watchdog timer is usually an indication that the program code
Prepared by: Vivek Joshi(08MTES17) 165
has failed (locked up, entered an infinite loop, or otherwise gone astray), and the
processor should be reset. On some AVRs the watchdog can be programmed to
issue an interrupt instead of resetting the processor. This functionality can be used
to wake up the AVR from a sleep mode.
The RESET pin is used for in-system serial programming, as a GPIO, or for
debugWIRETM low pin count debugging, depending on the chip and the
programming of the fuse bits. If the reset functionality of that pin is disabled, it
cannot be recovered by in-system serial programming, and another method such as
high-voltage programming must be used.
Interrupts
AVRs support multiple interrupt sources, both internal and external. An interrupt
could be from an internal peripheral reaching a certain state (i.e. character received
on UART), or from an external event like a certain level on a pin. Each interrupt
source causes a jump to a specific location in memory. That location is expected to
contain either a RETI (Return from Interrupt) instruction to essentially ignore the
interrupt, or a jump to the actual interrupt handler.
Most AVRs have at least one dedicated external interrupt pin (INT0). Older AVRs
can trigger an interrupt on a high or low level, or on a falling edge. Newer AVRs
add more options, such as triggering on the rising edge or either edge.
Additionally, many of the newer AVRs implement pin-change interrupts for all
pins in groups of eight, eliminating the need for polling the pins. The pin-change
interrupt handler must examine the state of the pins that are associated with that
interrupt vector, and determine what action to take.
Due to button bounce issues, it is considered poor design to connect a push button
or other user input directly to an interrupt pin; some debouncing or other signal
conditioning must be interposed so that the signal from the button does not violate
the setup and hold times required on the interrupt pins.
General Purpose I/O, or GPIO, pins are the digital I/O for the AVR family. These
pins are true push-pull outputs. The AVR can drive a high or low level, or
configure the pin as an input with or without a pull-up. GPIOs are grouped into
"ports" of up to 8 pins, though some AVRs do not have enough pins to provide all
8 pins in a particular port, e.g. the Mega48/88/168 does not have a PortC7 pin.
Control registers are provided for setting the data direction, output value (or pull-
up enabled), and for reading the value on the pin itself. An individual pin can be
accessed using bitwise manipulation instructions.
Prepared by: Vivek Joshi(08MTES17) 166
Each port has 3 control registers associated with it, DDRx, PORTx, and PINx.
Each bit in those registers controls one GPIO pin, i.e. bit 0 in DDRA controls the
data direction for PortA0 (often abbreviated PA0), and bit 0 in PORTA will control
the data (or pullup) for PA0.
The DDR (Data Direction Register) controls whether the pin is an input or an
output. When the pin is configured as an output, the corresponding bit in the PORT
register will control the drive level to the pin, high or low. When the pin is
configured as an input, the bit in the PORT register controls whether a pull-up is
enabled or disabled on that pin. The PIN (Port Input) register was read-only on
earlier AVRs, and was used to read the value on the port pin, regardless of the data
direction. Newer AVRs allow a write to the PIN register to toggle the
corresponding PORT bit, which saves a few processor cycles when bit-banging an
interface.
Timer/Counters
All AVRs have at least one 8-bit timer/counter. For brevity, a timer/counter is
usually referred to as simply a timer.
Some of the Tiny series have only one 8-bit timer. At the high end of the Mega
series, there are chips with as many as six timers (two 8-bit and four 16-bit).
The basic operation of a timer is to count up to FF16 (or FFFF16), roll over to zero,
and set an overflow bit, which may cause an interrupt if enabled. The interrupt
routine reloads the timer with the desired value in addition to any other processing
required.
The value of a timer can be read back at any time, even while it is running. (There
is a specific sequence documented in the datasheets to read back a 16-bit timer so
that a consistent result is returned, since the AVR can only move 8 bits at a time.)
A timer can be halted temporarily by changing its clock input to "disabled," then
resumed by re-selecting the previous clock input.
PWM
Many of the AVRs include a compare register for at least one of the timers. The
compare register can be used to trigger an interrupt and/or toggle an output pin (i.e.
Prepared by: Vivek Joshi(08MTES17) 167
OC1A for Timer 1) when the timer value matches the value in the compare
register. This may be done separately from the overflow interrupt, enabling the use
of pulse-width modulation (PWM).
Some AVRs also include options for phase-correct PWM, or phase- and
frequency-correct PWM.
The Clear Timer on Compare (CTC) mode allows for the timer to be cleared when
it matches a value in the compare register, before the timer overflows. Clearing the
timer prior to overflow manipulates the timer resolution, allowing for greater
control of the output frequency of a compare match. It can also simplify the
counting of an external event.
The ATtiny26 is unique in its inclusion of a 64MHz high-speed PWM mode. The
64MHz clock is generated from a PLL, and is independent of, and asynchronous
to, the processor clock.
Some AVRs also include complementary outputs suitable for controlling some
motors. A dead-time generator (DTG) inserts a delay between one signal falling
and the other signal rising so that both signals are never high at the same time. The
high-end AT90PWM series allows the dead time to be programmed as a number of
system clock cycles, while other AVRs with this feature simply use 1 clock cycle
for the dead time.
Serial Communication
Finally, there is also the possibility to use additional logic to implement a serial
communication function. For example, most AVRs don't support the USB bus
(some later ones do so, however). When using an AVR which doesn't support USB
directly, a circuit designer can add USB functionality with a fixed-function chip
such as the FTDI232 USB to RS232 converter chip, or a general-purpose USB
interface such as the PDIUSB11. Adding additional electronics is in fact necessary
for some supported communication protocols, e.g. standard-compliant RS232
communication requires adding voltage level converters like the MAX232.
Universal
Can be used in a lot of different serial communication scenarios
Synchronous
Can be used for synchronous serial communication (sender and receiver are
synchronised by a particular clock signal)
Asynchronous
Can be used for asynchronous serial communication (sender and receiver are
not explicitly synchronised via a clock signal, but synchronise on the data
signal).
Receiver
The hardware in the AVR can receive serial data
Transmitter
The hardware can send serial data
Earlier AVRs had a UART that did not support synchronous serial communication,
hence the absence of the "S" in the acronym.
With the right line interface an AVR's USART can, for example, be used to
communicate with RS-232, RS-485, MIDI, LIN bus, or CANbus devices, to name
some of the popular protocols.
See Robotics: Computer Control: The Interface: Networks for more details.
RS-232 Signalling
The RS-232 specification calls for a negative voltage to represent a "1" bit, and a
positive voltage to represent a "0" bit. The spec allows for levels from +3 to +15V,
and -3 to -15V, but +/-12V is commonly seen. The AVR does not have the ability
to drive a negative output voltage on any GPIO pin, and so a level converter, such
as the MAX232, is used to talk to PCs and strict RS-232 devices. See Serial
Programming:RS-232 Connections for more detail on RS-232 wiring.
RS-232 has a relatively short maximum cable length. For longer cabling distances,
consider using RS-485 signaling on your USART.
TWI is a variant of Phillips' I²C bus interface. I²C consists of two wires, known as
SDA (serial data) and SCL (serial clock), which use open-drain drivers and
therefore require pull-ups to a logic-1 state. I²C uses a common ground, so all
devices on the bus should be at the same ground potential to avoid ground loops.
TWI uses 7 bit addressing, which allows for multiple devices to connect to the bus.
Many TWI devices have at least the top four bits of the address hard-coded, and
the remaining bits configurable by some means such as connecting dedicated
address pins to power or ground; this often allows for only 2-8 model X devices on
the bus. The AVR's TWI hardware can act as Master or Slave, and can meet the
400Kbit/s spec.
Conceptually, SPI is a bidirectional shift register; as bits are shifted out on either
MISO or MOSI, bits are shifted in on the other line. The master always controls
the clock.
An SPI slave has a Slave Select (SS) signal, which signals to the slave that it
should respond to messages from the master. SS is almost always active-low. If
there is only one master and one slave, the slave's SS line could be tied low, and
the master would not need to drive it. If there are two or more slaves, then the
master must use a separate slave select signal to each slave. The downside of this
approach is that the master can only address as many slaves as it has extra outputs
(without the use of a separate decoder).
The pins used for the SPI bus are also used as a way of programming the chip via
ISP (In System Programming)(Except on the mega128).
Universal Serial Interface Some AVRs, particularly in the Tiny family, provide a
Universal Serial Interface (USI) instead of an SPI. The USI is capable of operating
as an SPI, but also as an I2C controller, and with a little extra effort, a USART.
The bit length of the transfer is configurable, as is the clock driver. The clock can
be driven by software, by the timer 0 overflow, or by an external source.
The datasheet for a particular AVR provides a block diagram of the SPI or USI
controller on that chip.
SPI, RS-232, I2C, and other serial interfaces only define the method by which bits
and bytes are transmitted; they correspond to layer 1 in the OSI model, the physical
layer. The bytes could be anything: temperature readings (in Centigrade or
Fahrenheit, depending on your sensor), readings from a pressure sensor, control
signals to turn off a pump, or the bytes of a JPEG image. Some of this meaning
may be assigned by the use of a serial communications protocol.
Analog Interfaces
[Analog to Digital
Analog to digital conversion uses digital number to represent the proportion of the
analog signal sampled. For example, by applying a 3V to the input of an ADC with
a full-scale range of 5 V, will result as a digital output of 60% of the full range of
the digital output. The digital number can be represented in 8 or 10 bits by the
ADC. An 8 bit converter will provide output from 0 to 28 − 1, or 255. 10 bits will
provide output from 0 to 210 − 1 = 1023.
AVRs with an ADC have several analog inputs which are connected to the ADC
via an analog multiplexer. Only one analog input can be converted at any given
time. The ADC controller provides a method for sequentially converting the inputs,
Prepared by: Vivek Joshi(08MTES17) 172
so that an AVR can easily cycle through multiple sources thousands of times a
second. AVRs can run ADC conversions continuously in the background, or use a
special "ADC sleep" mode to halt the processor while a conversion is taking place,
to minimize voltage disturbances from the rest of the MCU.
Nearly all AVR microcontrollers feature an Analog Comparator which can be used
to implement an ADC on those AVRs which do not have an ADC, or if all of the
ADC inputs are already in use. Atmel provides sample code and documentation for
using the comparator as a low-speed ADC. The signal to be measured is connected
to the inverted input, and a reference signal is connected to the non-inverting input.
The AVR generates an interrupt when the signal falls below or rises above the
reference value.
A common use for the analog comparator is sensing battery voltage, to alert the
user to a low battery.
LCD Driver
In larger models like the ATMega169 (as seen in the AVR Butterfly), an LCD
driver is integrated. The LCD driver commandeers several ports of the AVR to
drive the column/row connections of a display. One particular trait of Liquid
Crystal that must be taken care of is that no DC bias is put through it. DC bias, or
having more electrons passing one way than the other when pumping AC,
chemically breaks apart the liquid crystal. The AVR's LCD module uses precise
timing to drive pixels forwards and backwards equally.
USB Interface
The AT90USB series includes an on-chip USB controller. Some models are
"function" only, while others have On-The-Go functionality to act as either a USB
host (for interfacing with other slave devices) or as a USB slave (for interfacing
with a USB master).
AVRs without built-in USB can use an external chip such as the PDIUSB12, or for
a low-speed and minimal functionality device, a firmware-only approach.
Prepared by: Vivek Joshi(08MTES17) 173
Two firmware-only USB drivers are obdev, which is available under an Open
Source compliant license with some restrictions, and USBtiny, which is licensed
under the GPL.
Although these software implementation provide a very cheap way to add USB
connectivity, they are limited to low-speed transfers, and tie up quite some AVR
resources. Other hardware ICs which translate USB signals to RS-232 (serial) for
the AVRs are available, from vendors such as FDTI. These ICs have the advantage
of offloading the strenuous task of managing the USB connection with the
disadvantage of being limited to the speed of the AVR's serial port.
Temperature Sensor
Some newer models have a built in temperature sensor hooked up to the ADC.
V.5
MOTOROL68HC11
Registers
• Hold Data
• Hold address
• Varies form uP to uP
Prepared by: Vivek Joshi(08MTES17) 174
Arithmetic Logic Unit (ALU)
Control Unit
Software
Can be written in high (C/C++) or low (assembly) languages
• Programs will be written in assembly language
• Assembly is a mnemonic representation of the instruction
• LDAA - “LoaD the Accumulator A”
• Assembly language is NOT portable to other processors!!
CPU Registers
• General purpose A and B
• 8 bit registers
• Most instruction deal with the A and B registers
• Can be “combined” to form the D register
• 16 bits
• 16 bit registers
• Used mainly in addressing operations
• Used as pointers to memory
• Can be used for limited arithmetic operations
CPU Registers
VI
RTOS (Real Time Operating System)
Features of RTOS
• Used for real time programming to meet hard and soft real time
constraints.
Additional support-
Naming basics
VI.3 VxWorks
Features
VI.4
Symbian
While all this sounds great, this is to the price of a little compromise: binary
compatibility has been broken. Which means that an existing application won't run
on Symbian OS v9 unless it has been specifically recompiled for this version (and
reciprocally: a Symbian OS v9 application must be recompiled using an older SDK
to be able to run on current phones).
Here are a few details we could get on Symbian OS v9. A lot more will probably be
announced next week at 3GSM in Cannes....
More Multimedia
The user interface framework has been enhanced to enable richer User Interface with
themes, animations, effects... The first snapshot we got from UIQ 3.0 looks really
promising and no doubt that Series 60 will also take benefit of this. The audio
capabilities are not left behind with the long awaited multi-channel audio support
and the stereo bluetooth headset support. Add the support of USB mass storage and
full OMA DRM 2.0, and you will get the ultimate phone for the music lover.
Imaging support has been enhanced and number of pixels of the camera is not more
limited.
More business
Enterprise users have not been left away. The new Symbian OS v9 incorporate
several new features of interest for big companies and operators.
The first one is the new device management framework. Whether you like it or
not, your boss may now be able to access and configure remotely your phone (over-
the-air diagnostics, re-programming, application installation/deinstallation).
Symbian OS v9 is compatible with core OMA Device Management v1.1.2 services
as well as OMA Client Provisionning v1.1.
IMAP mail support has been slightly enhanced, allowing you to filter and sort your
mail by name.
Prepared by: Vivek Joshi(08MTES17) 180
Calendaring application can now accept meeting invitations from MS Outlook and
Lotus Notes.
More Security
With the increasing popularity of the Symbian platform, the year 2004 has seen the
birth of wireless malware. While none of the Cabir, Skulls, Velasco where really
dangerous, Symbian Ltd has taken the threat seriously and introduced a new security
framework:
sensitive APIs are only available to certified applications
some APIs are available silently to certified applications but require manual user
confirmation for the others (ex "Do you allow the running application to send a SMS
?").
Most (60%) of the APIs remain freely accessible to every applications.
Technically speaking, each process will have a set of "Trusted Capabilities". Each of
these defining a access right granted to the application (access network, access user
personal data, access Bluetooth,...).
The second security feature is called data-caging. This prevents unauthorized access
to date written on the file system and will be implemented at two different levels:
system directories won't be accessible anymore to applications (unless you have
very high capabilities).
each application can create a secure directory to store its sensitive information
(registration information, credit card details,...) and other applications won't be able
to access it.
To develop applications that makes use of the protected APIs, one will need a
developer certificates that allow the application to access the APIs on a predefined
set of phones. This certificate is unfortunately not free (Symbian Lts is aiming at less
than 50 Euros but you also need a ACS Publisher Id which is 400$ / year]) :
hoobyists and students will probably have to stick to "free" APIs....
The move to this new security framework will not be totally transparent. And if
Symbian claims that 50% of the API have been untouched by this changed, that
leaves another 50%... According to Martin Grauballe, those changes will fall into
two categories. The first will be to replace APIs, such as the inter-process
communications API, which have been removed with secure alternatives. The
second will be smaller changes to account for the "securitization" of other APIs.