| |
 |
The 8051
|
|
|
|
| |
|
| |
|
| |
The 8051 Timers |
| |
|
| |
The basic 8051 has two on-chip timers that can be used for
timing durations or for counting external events. |
| |
|
| |
Interval timing allows the programmer to perform operations
at specific instants in time. For example, in our LED flashing program the
LED was turned on for a specific length of time and then turned off for
a specific length of time. We achieved this through the use of time delays.
Since the microcontroller operates at a specific frequency, we could work
out exactly how many iterations of the time delay was needed to give us
the desired delay. |
| |
However, this is cumbersome and prone to error. And there
is another disadvantage; the CPU is occupied, stepping through the loops.
If we use the on-chip timers, the CPU could be off doing something more
useful while the timers take on the menial task of keeping track of time. |
| |
|
| |
|
| |
The Timers' SFRs |
| |
The 8051 has two 16-bit timers. The high byte for timer 1
(TH1) is at address 8DH while the low byte (TL1) is at 8BH. |
| |
The high byte for timer 0 (TH0) is at 8CH while the low byte
(TL0) is at 8AH. |
| |
|
| |
Both timers can be used in a number of different modes. The
programmer sets the timers to a specific mode by loading the appropriate
8-bit number into the Timer Mode Register (TMOD) which is at address 89H. |
| |
|
| |
|
| |
Timer Mode Register |
| |
|
| |
| TMOD |
| Bit |
Name |
Timer |
Description |
| 7 |
Gate |
1 |
Gate bit; when set, timer only runs while
INT-bar is high. This bit is used in conjunction with interrupts
and will be dealt with later. |
| 6 |
C/T-bar |
1 |
Counter/timer select bit; when set timer is an event
counter, when cleared timer is an interval timer. |
| 5 |
M1 |
1 |
Mode bit 1 |
| 4 |
M0 |
1 |
Mode bit 0 |
| 3 |
Gate |
0 |
Gate bit; when set, timer only runs while INT-bar
is high. |
| 2 |
C/T-bar |
0 |
Counter/timer select bit; when set timer is an event
counter, when cleared timer is an interval timer. |
| 1 |
M1 |
0 |
Mode bit 1 |
| 0 |
M0 |
0 |
Mode bit 0 |
|
| |
The functions of the 8-bits of TMOD are described in the
above table. The top four bits are for timer 1 and the bottom four bits
have the exact same function but for timer 0. |
| |
The Gate bits are used in conjunction with interrupts
and will be dealt with at a later stage. For the moment we can take it that
bits 7 and 3 are always cleared. |
| |
As mentioned above, the timers can be used for
counting external events or for timing intervals. If you wish the timer
to be an event counter you set the corresponding C/T-bar bit. Similarly,
if you wish it to be an interval timer you reset the corresponding C/T-bar
bit. |
| |
There are two mode bits (M1 and M0) for each timer. The table
below describes their function. |
| |
|
| |
| M1 |
M0 |
Mode |
Description |
| 0 |
0 |
0 |
13-bit timer mode (this mode exists simply to keep
the 8051 backwards compatible with its predecessor, the 8048, which
had a 13-bit timer) - we will not be using mode 0. |
| 0 |
1 |
1 |
16-bit timer mode |
| 1 |
0 |
2 |
8-bit auto-reload mode |
| 1 |
1 |
3 |
Split timer mode - this mode will be dealt with at a later stage |
|
| |
There are four timer modes, set by the bits M1 and M0. Mode
0 is not commonly used. Mode 3 we will deal with later. |
| |
|
| |
Mode 1 - 16-bit mode |
| |
The high byte (THx) is cascaded with the low byte (TLx) to
produce a 16-bit timer. This timer counts from 0000H to FFFFH - it has 216
(65,536) states. An overflow occurs during the FFFFH to 0000H transition,
setting the overflow flag (to be dealt with shortly). |
| |
|
| |
Mode 2- 8-bit auto-reload mode |
| |
The timer low byte (TLx) operates as an 8-bit timer (counting
to FFH) while the high-byte holds a reload value. When the timer overflows
from FFH, rather than starting again from 00H, the value in THx is loaded
into TLx and the count continues from there. |
| |
|
| |
|
| |
A diagrammatic representation of mode 1 and mode 2. (The
8051 Microcontroller, 3rd Edition - I. Scott MacKenzie) |
| |
|
| |
Timer Control Register |
| |
|
| |
| TCON |
| Bit |
Symbol |
Bit Address |
Description |
| 7 |
TF1 |
8FH |
Timer 1 overflow flag; set by hardware upon overflow, cleared
by software. |
| 6 |
TR1 |
8EH |
Timer 1 run-control bit; manipulated by software - setting starts
timer 1, resetting stops timer 1. |
| 5 |
TF0 |
8DH |
Timer 0 overflow flag; set by hardware upon overflow, cleared
by software. |
| 4 |
TR0 |
8CH |
Timer 0 run-control bit; manipulated by software - setting starts
timer 0, resetting stops timer 0. |
| 3 |
IE1 |
8BH |
The bottom four bits of TCON are used in conjunction
with interrupts - they will be dealt with at a later stage. |
| 2 |
IT1 |
8AH |
| 1 |
IE0 |
89H |
| 0 |
IT0 |
88H |
|
| |
The top four bits of TCON are the only ones that interest
us at the moment since the bottom four are used with interrupts. |
| |
|
| |
Bit 7 and bit 5 are the timer overflow flags (TFx). The overflow
flag is set by the hardware once an overflow occurs. For example, if timer
0 is in mode 1 (16-bit mode) then, during the state transition from FFFFH
to 0000H the overflow flag TF0 is set by the hardware. |
| |
|
| |
Bit 6 and bit 4 are the timer run-control bits (TRx). A timer
is started by setting TRx and stopped by clearing TRx. |
| |
|
| |
The TCON register is bit addressable because the programmer
needs ease of access to the individual bits. You may wish to test the contents
of TF1, to see when timer 1 overflows. Or you may wish to stop timer 0 without
effecting timer 1, as shown below. Clearing TR0 does not effect the other
seven bits of TCON. |
| |
CLR TR0
|
| |
|
| |
|
| |
Initialising the Timers |
| |
The timers are initialised (ie; put into a particular mode
of operation) by moving the appropriate value into the TMOD register. For
example, if you wished to use timer 0 as a 16-bit interval timer and timer
1 as an 8-bit auto-reload event counter you would load the following value
into TMOD. |
| |
|
| |
| |
bit |
value |
note |
| Timer 1 |
7 |
0 |
gate (set when using interrupts, reset otherwise) |
| 6 |
0 |
C/T-bar (0 because timer 1 is to be an interval timer) |
| 5 |
0 |
mode bits (01 for mode 1 - 16-bit) |
| 4 |
1 |
| Timer 0 |
3 |
0 |
gate (set when using interrupts, reset otherwise) |
| 2 |
1 |
C/T-bar (1 because timer 0 is to be an event counter) |
| 1 |
1 |
mode bits (10 for mode 2 - 8-bit auto-reload) |
| 0 |
0 |
|
| |
The instruction for initialising the timers as above would
therefore be: |
| |
MOV TMOD, #16H
|
| |
|
| |
(0001 0110bin = 16H) |
| |
|
| |
|
| |
Starting and Stopping the Timers |
| |
The run/control bits in the TCON register are used for starting
and stopping the timers. As shown in the TCON table above, bit 6 is the
run control bit for timer 1 while bit 4 is the run control bit for timer
0. The following two instructions start timer 0 and timer 1 respectively. |
| |
|
| |
SETB TR0
SETB TR1
|
| |
|
| |
Setting the run control bit starts the timer. To stop the
timer, you clear the corresponding run control bit |
| |
|
| |
CLR TR0; stop timer 0
CLR TR1; stop timer 1
|
| |
|
| |
|
| |
Reading the Timers on the Fly |
| |
Reading the current value of a timer when it is not running
is quite easy. You simply move the high byte and the low byte to the desired
memory location (usually a register). |
| |
MOV R7, TH0; move the hi-byte of timer 0 into R7
MOV R6, TL0; move the lo-byte of timer 0 into R6
|
| |
|
| |
However, to read the contents of a timer while it is running
(ie; on the fly) poses a problem. Let's say we put timer 0's current value
into R7 and R6, as shown above. The problem arises when the value in the
lo-byte goes from FFH to 00H immediately after we read the high byte. |
| |
For example, let's say the high-byte is 08H and the low-byte
is FFH. The controller moves the high byte into R7. Then, before it gets
a chance to read the low byte, it changes from FFH to 00H. The controller
then moves this value into R6, getting an overall 16-bit reading of 0800H
when the value should have been 08FFH. |
| |
The solution is to read the high byte, then read the low
byte, then read the high byte again. If the two readings of the low-byte
are not the same repeat the procedure. The code for this method is detailed
below. |
| |
|
| |
| tryAgain: |
MOV A, TH0
MOV R6, TL0
CJNE A, TH0, tryAgain; if the first reading of the hi-byte (in A)
is not equal
|
to current
reading in the hi-byte (TH0) try again
|
MOV R7, A; if
both readings of the hi-byte are the same move the first reading
into R7
|
- the
overall reading is now in R7R6
|
|
| |
|
| |
|
| |
Clock Sources |
| |
As discussed earlier, both timers can be used either as interval
timers or event counters. The only difference between the timer as an interval
timer and an event counter is the clock source. The timers are triggered
by a negative edge to their clock inputs. |
| |
|
| |
When the timer is operating as an interval timer it is being
clocked by the internal clock (this internal clock, usually 12MHz, is actually
divided by twelve to yield a reasonable clock frequency for most applications
- therefore, the internal clocking signal is usually 1MHz). |
| |
|
| |
When the timer is operating as an event counter it is triggered
by an external source connected to pin T0 (port 3, pin 4) for timer 0 and
pin T1 (port 3, pin 5) for timer 1. In this way the timer can count events
rather than keep track of time. |
| |
For example, if a sensor on a conveyor belt system produces
a negative edge everytime an item on the belt passes by, this sensor could
be connected to pin T0. If timer 0 were then initialised as an event counter
and started, everytime an item passed in front of the sensor, a negative
edge would be generated on pin T0, thus triggering timer 0 which would proceed
to the next stage in its count sequence. In this way, timer 0 is counting
the number of items passing by on the conveyor belt. |
| |
|
| |
Generating Pulse Trains |
| |
We can very effectively use the timers where exact timing
conditions are necessary. For example, if we need to generate a 4KHz pulse
train on pin 5 of port 1, we could use either timer 0 or timer 1 in 8-bit
auto-reload interval timing mode. |
| |
Let's say we decide to use timer 0. We must first work out
the value that must be placed in the TMOD register to put timer 0 into the
desired mode. |
| |
|
| |
| |
bit |
value |
note |
| Timer 1 |
7 |
0 |
since we are not using timer 1 we can put all four
upper bits to 0 |
| 6 |
0 |
| 5 |
0 |
| 4 |
0 |
| Timer 0 |
3 |
0 |
gate (set when using interrupts, reset otherwise) |
| 2 |
0 |
C/T-bar (0 because timer 0 is to be an interval timer) |
| 1 |
1 |
mode bits (10 for mode 2 - 8-bit auto-reload) |
| 0 |
0 |
|
| |
Therefore, the value to be placed in TMOD is 02H. |
| |
|
| |
Mode 2 is the 8-bit auto-reload mode. The low byte of the
counter behaves like an 8-bit counter. The high-byte is used for storing
the reload value. When an overflow occurs (ie; state transition from FFH)
the timer does not revert to zero. Rather, the value in the high-byte is
placed in the low-byte and the sequence begins again from there. |
| |
If the high-byte contains 00H, then the timer behaves exactly
like an 8-bit timer, counting continuously from 00H to FFH and back to 00H
again. |
| |
As an interval timer, the clocking signal arrives every 1us
(microsecond). The 12MHz system clock is divided by 12 and then fed to the
timer. Therefore, the timer's clocking signal is 1MHz, resulting in a negative
edge every 1us (time = 1/frequency). |
| |
If the high byte contains 00H, the counter goes through the
full 256 states (00H to FFH). Therefore, an overflow occurs every 256us.
|
| |
We require a 4KHz pulse train on pin 5 of port 1; in other
words, P1.5 must toggle every 125us (4KHz signal - one cycle every 250us
- one half cycle every 125us). |
| |
We need to load the high byte with a suitable value to result
in an overflow every 125us. To find the value, we subtract the required
time from the maximum time (255us - 125us = 131). Changing this value to
HEX gives 83H. |
| |
|
| |
The code for generating the pulse train is detailed below: |
| |
|
| |
MOV TMOD, #02H;
set up timer 0 as 8-bit auto-reload interval timer
MOV TH0, #83H; put reload value into timer 0 hi-byte
SETB TR0; start timer 0
|
| waitForOverflow: |
JNB TF0, $;
repeat this line while timer 0 overflow flag is not set
CLR TF0; timer 0 overflow flag is set by hardware on transition
from FFH - the flag must be reset by software
|
CPL P1.5; complement
(invert) pin 5 on port 1 - this instruction toggles the specified
bit
JMP waitForOverflow; go back and wait for overflow again
|
|
| |
|
| |
Note: with the above program, P1.5 is at 1 for the same length
of time that it's at 0 (125us each), therefore the waveform has 50% duty
cycle. |
| |
|
| |
|
| |
A One Second Delay |
| |
One second is a very long time for a microcontroller. If
the microcontroller has a system clock frequency of 12 MHz then the longest
delay we can get from either of the timers is 65,536 usec. To generate delays
longer than this, we need to write a subroutine to generate a delay of (for
example) 50 ms and then call that subroutine a specific number of times.
To generate a 1 second delay we would call our 50 ms delay 20 times. |
| |
In the example below timer 1 is used. There is no particular
reason for this; timer 0 could have been used. |
| |
The value placed in the timer before it is started is 65,536
- 50,000 = 15,536. To get a delay of 50 ms (or 50,000 us) we start the timer
counting from 15,536. Then, 50,000 steps later it will overflow. Since each
step is 1 us (the timer's clock is 1/12 the system frequency) the delay
is 50,000 us. |
| |
|
| |
using 0
...
MOV TMOD, #10H; set up timer 1 as 16-bit interval timer
...
|
| |
| fiftyMsDelay: |
CLR TR1 ; stop
timer 1 (in case it was started in some other subroutine)
MOV TH1, #3CH
MOV TL1, #0B0H ; load 15,536 (3CB0H) into timer 1
SETB TR1 ; start timer 1
JNB TF1, $; repeat this line while timer 1 overflow flag is not
set
CLR TF1; timer 1 overflow flag is set by hardware on transition
from FFFFH - the flag must be reset by software
CLR TR1 ; stop timer 1
RET
|
| |
| oneSecDelay: |
PUSH PSW
PUSH AR0 ; save processor status
MOV R0, #20 ; move 20 (in decimal) into R0
|
| loop: |
CALL fiftyMsDelay
; call the 50 ms delay
DJNZ R0, loop ; 20 times - resulting in a 1 second delay
POP AR0
POP PSW ; retrieve processor status
RET
|
| |
| |
|
|
|
|
|
|
Copyright
(c) 2005-2006 NyCelt LLC
|
|