| |
 |
The 8051
|
|
|
|
| |
|
| |
|
| |
Peripheral Interfacing |
| |
|
| |
The following topics are covered in this section: |
| |
|
| |
|
| |
Inputs |
| |
|
| |
Interfacing
Digital Inputs to TTL |
| |
Before we can discuss interfacing digital signals to TTL
inputs, we must remind ourselves of the voltage and current levels of a
TTL input. |
| |
|
| |
The logic levels for TTL inputs are as follows: |
| |
- HIGH - between 2 V and 5 V
- LOW - between 0 V and 0.8 V
|
| |
When a HIGH is applied to a TTL input it draws very little
current (about 40 uA). When a LOW is applied to a TTL input it sources approximately
1.6 mA. |
| |
|
| |
Therefore, when interfacing a digital input (which will be
either HIGH or LOW) to TTL we must ensure it meets the requirements of a
TTL input. |
| |
|
| |
The diagram below shows how to interface a digital input
(ie; either high or low) to TTL. |
| |
 |
| |
When the digital input is HIGH the transistor will be turned
on. This results in a direct path from the port pin to ground, therefore
the pin is logic 0. When the digital input is LOW the transistor is off
which means there is no path for current from the collector to the emitter,
therefore the port pin will read 5V. |
| |
This circuit results in logic inversion, but this should
not be a problem as inverting the port pin through software is very easy. |
| |
|
| |
When the transistor is on the port pin is connected directly
to ground. Therefore there is a path for the 1.6 mA from the port pin (TTL
current when input is LOW). The 10 K emitter resistor ensures the current
from the supply is kept low, an important consideration in battery powered
devices. |
| |
When the transistor is off the port pin is at 5 V (in reality
it will not be exactly 5V because a transistor is never fully off and a
small current will flow through the emitter resistor, resulting in a small
voltage drop across the resistor - but the voltage level on the resistor
will still be close to 5 V). Since there is very little current flowing,
power consumption is kept low. Also, as mentioned above, a TTL input draws
very little current when a HIGH is applied to it, so this circuit satisfies
the requirements of a TTL input and keeps power consumption at a minimum. |
| |
|
| |
The digital HIGH need not be TTL level inputs. |
| |
The HIGH voltage applied to the base of the transistor does
not have to be 5V. For example, the input circuit could be from temperature
sensor that produces a HIGH voltage when the temperature exceeds a certain
value. The voltage level from this circuit could be any voltage that is
high enough to turn on the transistor (say, 12V for example) and the value
of the base resistor can be calculated to suit. Because the voltage applied
to the emitter resistor is 5 V the digital HIGH from the sensor circuit
is level-shifted to suit a TTL input. |
| |
|
| |
|
| |
Switches |
| |
The circuit above is actually interfacing an electronic switch,
the transistor, to a TTL input. We can interface a physical switch in exactly
the same way, as shown below. |
| |
 |
| |
When the switch is open, no current flows through the resistor
and therefore the voltage on the microcontroller pin is 5 V. When the switch
is closed the pin is connected directly to ground. As before, when the TTL
input is HIGH practically no current flows in the circuit and when the input
is LOW there is a direct current for the 1.6 mA that may flow from the pin. |
| |
|
| |
Switch Bounce |
| |
When a physical switch is closed the contacts bounce open
and closed rapidly for about 20 to 30 ms, as illustrated below. |
| |
 |
| |
The opening of a switch is clean and without bounce. However,
when a switch is closed the contacts bounce open and closed for about 30
ms. While this is a very short time in human terms it is a very long time
for a microcontroller (the basic 8051 running on a system clock of 12 MHz
executes a 1-byte instruction in 1 us). Without switch debouncing, the microcontroller
would 'think' the switch was opened and closed many times. Imagine if a
push-button switch was being used to increment the output from a microcontrolled
power supply. If the switch was connected to the microcontroller without
switch bounce then a user pressing the switch once would actually result
in the output voltage being increased many times because the microcontroller
would respond as if the switch had been pressed many times. |
| |
|
| |
Hardware Switch Debounce |
| |
One method of hardware debounce is shown below. |
| |
  |
| |
As can be seen from the waveforms above, when the switch
is closed the capacitor voltage drops to 0 V. When the switch bounces open
the capacitor begins to charge back up to 5 V, but due to the RC constant,
it cannot charge beyond the schmitt trigger's HIGH reference voltage before
the switch bounces closed again. Once the switch closes, the capacitor again
drops to 0 V. Since the voltage on the capacitor never goes beyond the trigger's
HIGH reference voltage during the switch bounce, the output of the trigger
remains LOW and the switch bounce is not seen on the port pin. |
| |
When the switch is physically opened the capacitor has plenty
of time to charge beyond the trigger's HIGH reference voltage, at which
point the trigger output goes HIGH and this is seen on the port pin. |
| |
|
| |
Software Switch Debounce |
| |
Hardware debounce requires extra circuitry. With small devices,
this extra hardware may not be tolerated. In most cases, software debounce
is more than adequate. Software debounce simply incorporates a delay of
about 30 ms while the switch bounces. In other words, when a key press is
detected, the system delays for about 30 ms before processing the input.
By then the switch will have stopped bouncing and the microcontroller will
only process the initial switch contact. |
| |
 |
| |
Delaying for about 30 ms will not be noticed by the user,
but the microcontroller could do quite a bit of work in that time. Therefore,
in a multifunction system it is more efficient to initialise a timer and
start it so that it will overflow and generate an interrupt 30 ms after
the switch was pressed. In that way, the controller can be doing some other
work while the switch bounces. |
| |
 |
| |
In the above flow chart diagrams, processing the key press
is handled in the ISR. This may not be the case in a multifunction system.
It is more likely that the ISR would set a flag to let the main program
know that a key has been pressed (or, in an RTOS system, to move a process
from the waiting state to the ready state). |
| |
|
| |
|
| |
Keypads |
| |
Keypads are assembled in a matrix form, as illustrated below. |
| |
 |
| |
The above diagram shows a 4 X
4 keypad - 16 switches configured in 4 columns and 4 rows. |
| |
In the default state (all switches open) there is no connection
between the rows and columns. When a switch is pressed a connection between
the switch's row and the switch's column is made. |
| |
|
| |
Keypad Decoder |
| |
Many keypads are built with an onboard decoder that scans
the keypad and, if a key is pressed, returns a number identifying the key.
Alternatively, a keypad decoder chip can be purchased separately and interfaced
with a keypad. The diagram below shows a 4 X
4 keypad interfaced with such a decoder. |
| |
 |
| |
The decoder is shown connected to the 8051, as a suggestion.
Obviously, the outputs from the decoder don't need to go to the LSBs of
P1, nor does the data available line (DA) need to be connected to the external
0 interrupt line. However, the above configuration is one way of interfacing
a 4 X 4 keypad decoder to the 8051. |
| |
The decoder has 8 inputs; the 4 X inputs are connected to
the 4 keypad columns while the Y inputs are connected to the 4 keypad rows.
Not shown in the diagram are pins for connecting capacitors to the decoder.
These capacitors govern the rate at which the keypad is scanned. |
| |
When a key is pressed the 4-bit code for the key (there are
16 keys, therefore there are codes 0000 to 1111 in binary) appears on the
four output lines (and in this case will appear on the 4 LSBs of P1) and
the data available line (DA) goes LOW. If connected to an external interrupt
line (in this case, the INT0-bar line) the microcontroller will be interrupted
when a key is pressed. The ISR could then read the 4 LSBs of P1 and process
the data. |
| |
The decoder chip takes care of switch debounce, therefore
the programmer is freed from this responsibility, which is an advantage
of using a decoder chip. |
| |
|
| |
Software Decoder |
| |
The above decoder function can be implemented in software.
The keypad could be interfaced with the 8051 as detailed below. |
| |
 |
| |
With the above configuration, an interrupt is generated on
the INT0-bar line when a key is pressed. We will deal with how this works
in a moment. Firstly, let's see how the keyboard is scanned. |
| |
The steps are: |
| |
- Scan row 1
- Scan row 2
- Scan row 3
- Scan row 4
|
| |
Scanning a row is achieved by applying 0 V to the port pin
for that row and 5 V to the other three rows, then scanning each individual
column to see if one of them is LOW. If it is, then the key at the junction
between the current row and column being scanned is the pressed key. |
| |
- Clear row 1, set other 3
- Scan column 1
- Scan column 2
- Scan column 3
- Scan column 4
- Clear row 2, set other 3
- Scan column 1
- Scan column 2
- Scan column 3
- Scan column 4
- Clear row 3, set other 3
- Scan column 1
- Scan column 2
- Scan column 3
- Scan column 4
- Clear row 4, set other 3
- Scan column 1
- Scan column 2
- Scan column 3
- Scan column 4
|
| |
For example, let's say the key being pressed is key 6. When
scanning the first row, P1.0 will be cleared while the other 3 rows (P1.1,
P1.2 and P1.3) are set, as detailed in the diagram below. |
| |
 |
| |
Since no key in this row is closed there is no path for current
through any of the pull-up resistors and all 4 columns (on P1.4 to P1.7)
are HIGH. Therefore, the key pressed was not found while scanning row 1. |
| |
The diagram below illustrates scanning row 2. (Note that
key 6 is still closed.) |
| |
 |
| |
In this case, column 3 is connected through the closed switch
to row 2. Since row 2 is LOW, column 3 is LOW. |
| |
|
| |
A series of flowcharts for implementing software keypad scan
is given below: |
| |
|
| |
 |
| |
 |
| |
 |
| |
 |
| |
 |
| |
|
| |
The keypad is initialised in the main program; all rows are
cleared. Therefore, when a key is pressed, since all rows are LOW, then
one of the columns (the one containing the key that has been pressed) will
be connected to 0 V. This logic 0 into the AND gate will result in a logic
0 out. Since the output of the AND gate is connected to INT0-bar, a key
press will result in an external 0 interrupt. |
| |
|
| |
The keyPressedISR is the ISR for dealing with an external
0 interrupt. The first thing this ISR does is disable the external 0 interrupt
and call a 30 ms (typical) delay subroutine. When the delay subroutine returns
the key will have stopped bouncing and the keypad can now be scanned. |
| |
|
| |
In this example, the value of the key pressed (0 to 15) will
be stored in R0. Therefore, at the start of the scanKeypad subroutine R0
is set to 0. Row 1 is cleared while the other three rows are set. The columnScan
subroutine is then called. It tests the status of each column. If the first
column is 0 then, since we are currently scanning row 1, key 0 was pressed
and its value is in R0. Therefore the keyFound flag is set and the subroutine
returns. |
| |
If the first column is not 0, R0 is incremented (it now holds
1) and the next column is tested. If it is 0 then key 1 was pressed and
this value is in R0 - therefore the keyFound flag is set and the subroutine
returns. |
| |
This is repeated for all columns until the key is found. |
| |
If none of the four columns is 0 then the key pressed is
not in this row and the subroutine returns without setting the keyFound
flag. |
| |
|
| |
When columnScan returns, the keyFound flag is tested. If
it is not 1 then the key was not found and the scanKeypad subroutine continues
with the next row. Throughout this process, R0 is incremented so that when
the key is finally found R0 will contain the value of that key. |
| |
|
| |
When scanKeypad returns to the ISR the value of the key is
in R0. The ISR then calls a subroutine to wait for the key to be released.
If we do not wait for the key to be released and immediately enable the
external 0 interrupt, then the system will react as if the key was pressed
again. Even if a user presses and releases the key as quickly as possible,
the microcontroller will have executed the ISR and enabled the INT0 interrupt
before the user actually released the key. Therefore we wait for the user
to release the key before proceeding. |
| |
The waitForKeyRelease subroutine is quite simple. All four
rows are cleared so that no matter which key is pressed, one of the columns
will be 0 which will result in a 0 out of the AND gate to the INT0-bar line.
Therefore, while the key is held down this line will be 0. Once the key
is released then all four columns will be 1 resulting in a 1 at INT0-bar
and the subroutine returns. |
| |
|
| |
The external 0 interrupt flag (IE0) is then cleared because
it may have been set as the key bounces and as we scanned the keyboard (remember,
disabling an interrupt does not prevent the interrupt from occurring - a
0 on INT0 will still set the flag, IE0). If we did not clear this flag,
once we again enable the external 0 interrupt the system would again vector
to keyPressedISR. |
| |
The processKeyFlag is then set to alert the main program
to the fact that a key was pressed. The main program can then retrieve the
value of the key from R0 and process it in whatever way the system design
requires. |
| |
|
| |
Separate Debounce Interrupt |
| |
One of the problems with the above implementation is the
fact that the system is held in a 30 ms delay while the key bounces. The
microcontroller could be doing something a lot more useful in that time
(remember, a basic 8051 running on a system clock of 12 MHz could execute
30,000 1-byte instructions in that time). One way would be to set one of
the timers to overflow in 30 ms, enable the timer's interrupt, start the
timer and exit the keyPressedISR. The timer's ISR could then execute the
rest of the keypad scan process (ie; what's left in keyPressedISR above
goes into the timer's ISR instead). |
| |
|
| |
Doing Nothing While the Key is Held Down |
| |
In the above implementation the system is held up doing nothing
as it waits for the key to be released. Even in the short space of time
of an ordinary key press, the controller could be doing something useful,
but it is even more wasteful if you imagine a user holding the key down
for a long time. One solution with the 8051 would be to initialise the external
0 interrupt as negative-edge activated rather than low-level activated.
In this case, the waitForKeyRelease subroutine would not be needed at all.
Once the external 0 interrupt is again enabled in keyPressedISR another
external 0 interrupt could not occur until the key was released and another
(or the same one) pressed; only this would result in a negative edge on
INT0-bar. |
| |
Note: there is one other task performed by waitForKeyRelease
- in performing its function it resets all four rows. If this subroutine
is removed, as suggested, then the code for clearing the rows (ie; CLR P1.0;
CLR P1.1; CLR P1.2; CLR P1.3) must be included in keyPressedISR so that
the system is then ready for the next key press. |
| |
|
| |
|
| |
ADC Interfacing |
| |
The schematic symbol for a typical analogue-to-digital converter
is shown below. On the right is an illustration of how the ADC may be interfaced
with the 8051. |
| |
|
| |
The function of the ADC pins are as follows: |
| |
- CS-bar is the chip select
- INTR-bar is the interrupt line - goes low when a conversion is complete.
- RD-bar enables the data lines.
- WR-bar is cleared and then set to start a conversion.
|
| |
In the above example of interfacing the ADC to the 8051,
the CS-bar line is connected to ground to permanently enable the chip. The
INTR-bar line goes LOW once a conversion is complete, therefore it is connected
to one of the external interrupt pins on the 8051. In this way, the 8051
will be interrupted when a conversion is complete and data is ready for
reading. |
| |
The data lines are tri-state (hence the inverted triangle
symbol) which means this chip can be memory mapped and the data lines can
be connected directly to the data bus. In the above example the data lines
are connected to port 1, but since they are tri-state the port can also
be used for something else. Only when the conversion is complete is P2.0
cleared which enables the data lines and the analogue conversion appears
on port 1. |
| |
The WR-bar line is used for starting a conversion. Clearing
this line resets the internal successive-approximation register and the
8-bit shift register. When the line is set conversion begins. |
| |
Therefore, taking a reading from the ADC is a two step process:
|
| |
- Clear and then set WR-bar to initiate a conversion.
- Sometime later (typically 100 us), the INTR-bar line will go LOW to
indicate the conversion is complete. This will cause an external 0 interrupt
and it is up to the external 0 ISR to read the data by clearing P2.0
and reading the data from port 1.
|
| |
Using an interrupt allows the microcontroller to do some
work during the 100 us it takes to convert the analogue input into digital. |
| |
|
| |
|
| |
|
| |
Outputs |
| |
We will now look at interfacing output devices to microcontroller
ports, focusing on the following topics: |
| |
- LEDs
- 7-segment LED displays
- Multiplexing 7-segment LED displays
- DC motors
|
| |
|
| |
TTL Compatibility |
| |
When discussing interfacing to TTL inputs above, we noted
the current sinked by a TTL input when the input is HIGH is approximately
40 uA. Since the fan-out of TTL is 10, the maximum current sourced by a
TTL output HIGH is 400 uA. |
| |
The current sourced by a TTL input when the input is LOW
is 1.6 mA, therefore (with a fan-out of 10) the maximum current sinking
for a TTL output LOW is 16 mA. |
| |
|
| |
|
| |
LEDS |
| |
Therefore, when interfacing an LED to a TTL output, the maximum
current through the LED is 16 mA. The circuit below shows how to interface
an LED to a microcontroller port pin. |
| |
 |
|
 |
| Basic LED interface providing max. LED on current of 16 mA |
|
LED interface to provide extra LED on current |
| The value for the resistor is calculated to result in the desired
LED on current - most LEDs have a forward voltage drop of about 2
V. |
|
The values of both resistors are calculated, using the transistor
Bdc value, to achieve the desired LED on current. |
|
| |
|
| |
|
| |
As explained, this limits the LED on current to 16 mA, which
in most cases is adequate. However, if more current is required, the second
circuit shown above may be used. Note that both circuits result in the microcontroller
port pin sinking current when the LED is on, which is desirable as port
pins will sink a lot more current than they will source. |
| |
|
| |
|
| |
7-segment Displays |
| |
Interfacing a single 7-segment display to a microcontroller
port is done in the same manner as interfacing a single LED. Again, the
LEDs can be connected directly to the port pins or, if high current LEDs
are being used, they can be connected through p-n-p transistors. Both methods
are detailed below. |
| |
 |
|
 |
| Basic 7-segment display interface providing max. LED-on current
of 16 mA |
|
7-segment interface to provide extra LED-on current |
| |
|
The complete configuration for only one segment and the decimal
point is shown. However, the configuration for the other 6 segments
is exactly the same. |
|
| |
|
| |
|
| |
Multiplexing |
| |
It is often necessary to interface a number of 7-segment
displays to a microcontroller. Rather than use a separate port for each
display, all of the displays are connected to the same port and other port
pins are used for switching on one display at a time. |
| |
 |
| |
The procedure for displaying characters on the multiplexed
displays is as follows: |
| |
- Turn off displays 2, 3 and 4 (by setting the corresponding port pin
enable lines).
- Write character for display 1 to data port.
- Turn on display 1 by turning on its transistor (ie; clearing the port
pin enable for display 1).
- Turn off displays 1, 3 and 4.
- Write character for display 2 to data port.
- Turn on display 2.
- Turn off displays 1, 2 and 4.
- Write character for display 3 to data port.
- Turn on display 3.
- Turn off displays 1, 2 and 3.
- Write character for display 4 to data port.
- Turn on display 4.
- Go to step 1.
|
| |
Of course the microcontroller system will need to do some
work other than displaying data on the displays (for example, if the microcontroller
is part of a digital multimeter, it would need to perform the measurement
and format the data for outputting to the displays). Therefore, rather than
jumping immediately back to step 1 from step 9, the following may be done. |
| |
- Turn off displays 2, 3 and 4 (by setting the corresponding port pin
enable lines).
- Write character for display 1 to data port.
- Turn on display 1 by turning on its transistor (ie; clearing the port
pin enable for display 1).
- Turn off displays 1, 3 and 4.
- Write character for display 2 to data port.
- Turn on display 2.
- Turn off displays 1, 2 and 4.
- Write character for display 3 to data port.
- Turn on display 3.
- Turn off displays 1, 2 and 3.
- Write character for display 4 to data port.
- Turn on display 4.
- Turn off all 4 displays.
- Perform system operations (eg; in the case of a multimeter, perform
measurement and format data for output).
- Go to step 1.
|
| |
In step 9, all four displays are switched off. If this step
was not carried out display 4 would be on longer than the other three displays
(it would be on while the system operations were being carried out) and
might therefore appear brighter. |
| |
|
| |
|
| |
DC Motors |
| |
An interfacing method for turning on and off a DC motor via
a microcontroller is shown below. |
| |
 |
| |
However, the above circuit will only work for a 5 V motor.
If the supply voltage is changed (for example, if the supply is changed
to 12 V to run a 12 V motor) then the motor will be on all the time because
5 V applied to the base of the p-n-p transistor is not enough to turn it
off. |
| |
|
| |
To interface to larger motors the following circuit may be
used. |
| |
 |
| |
In the above example a 12 V DC motor is interfaced to a microcontroller.
When the port pin is set (ie; is equal to 5 V) the p-n-p transistor is off
which means the n-p-n transistor is also off. Therefore there is no path
for current through the motor and the motor is off. |
| |
When the port pin is cleared the p-n-p transistor is on.
This turns on the n-p-n transistor which allows current to flow through
the motor to ground; the motor is on. |
| |
The value of R2 needs to be carefully chosen; too high and
the current into the base of the n-p-n transistor will not be enough to
turn on the transistor, too low and the circuit draws too much current. |
| |
|
| |
Bi-directional DC Motor |
| |
A circuit diagram for interfacing a 12V DC motor to a microcontroller
in a way that allows the controller to not only turn on and off the motor
but also to set the direction in which the motor runs when it is on, is
given below. |
| |
 |
| |
The circuit is made up of a bridge. If both sides of the
motor are at the same voltage the motor is off. So, if T1 and T3 are on,
both sides of the motor are connected to 12 V and the motor is off. If T2
and T4 are on both sides of the motor are connected to ground and, again,
the motor is off. |
| |
If T1 and T4 are on then the left side of the motor is at
12 V and the right side is at ground, therefore the motor runs in one direction.
We will call this forward. |
| |
If T3 and T2 are on then the left side of the motor is at
ground and the right side is at 12 V, therefore the motor runs in the opposite
direction; ie, reverse. |
| |
|
| |
The circuit is designed so that T1 and T2 cannot be on at
the same time and T3 and T4 cannot be on at the same time. This is very
important; if T1 and T2 were on at the same time there would be a short
circuit between 12 V and ground and the transistors would burn out. The
same is true for T3 and T4. |
| |
|
| |
The truth table for the circuit with its two inputs, A
and B, is given below. |
| |
| A |
B |
Motor |
| 0 |
0 |
off |
| 0 |
1 (5 V) |
reverse |
| 1 (5 V) |
0 |
forward |
| 1 (5 V) |
1 (5 V) |
off |
|
| |
An explanation of the four entries in the table is given
below: |
| |
- Entry 1:
- With A at 0 (ie; ground) T5 is on which turns on T2; left side
of motor is at ground. A at 0 also means T6 is off. Since there
is no path for current through R3 and R4 there is no voltage drop
across them which in turn means the base of T1 is at 12 V, hence
it is off.
- The right-hand side of the circuit is a mirror image of the left,
therefore with B at 0, T4 is on and T3 is off - hence the right
side of the motor is also at ground; the motor is off.
- Entry 2:
- A is still at 0 which means T1 is still off and T2 is still on;
the left side of the motor is at ground.
- With B at 5 V (ie; logic 1 on the port pin which is being used
for B) T7 is off which means T4 is off. But T8 is on which generates
a path for current through T8 to ground and also through R9 to the
base of T3. There is a certain amount of voltage dropped across
R9, but the base of T3 is close enough to ground for T3 to turn
on; the right side of the motor is at 12 V.
- The motor is therefore on and we stated above that ground on the
left of the motor and 12 V on the right would be called reverse.
- Entry 3:
- This is the mirror image of entry 2, resulting in T1 on, T2 off,
T3 off and T4 on; hence the left side of the motor is at 12 V and
the right side is at ground - the motor runs forward.
- Entry 4:
- As in entry 3, with A at 5 V the left side of the motor is at
12 V.
- As in entry 2, with B at 5 V the right side of the motor is at
12 V.
- Therefore the motor is off.
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
Copyright
(c) 2005-2006 NyCelt LLC
|