09. Timer0/1 and Precise Delays
Lesson 7's software delay is imprecise and ties up the CPU. Precise time comes from a hardware timer — a counter that ticks independently of the CPU. We set 8051's Timer0/1 to 16-bit mode (Mode1) for exact delays. The keys: TMOD for mode, a reload value (65536−count) in TH/TL, and polling the overflow flag (TF). Reload math is verified on PC.
What you'll learn
- 1Explain the advantage of a hardware timer over software delay
- 2Set Timer0/1 mode via TMOD (Mode1=16-bit)
- 3Compute the reload value (TH/TL) for a desired delay
- 4Implement polling delay with TR (start) and TF (overflow flag)
- 5Make delays longer than the 16-bit limit by counting overflows
Introduction
A timer is a counter that increments every machine cycle. A standard 8051 has machine cycle = 12 clocks, so at 12MHz a machine cycle is 1µs. The 16-bit counter (TH:TL) rolls 0xFFFF→0x0000 and sets the overflow flag (TF).
Key concepts
1) TMOD — mode register
TMOD's low nibble is Timer0, high nibble Timer1. M1M0=01 is Mode1 (16-bit). Timer0 Mode1 = TMOD=0x01, Timer1 Mode1 = TMOD=0x10. Preserve the other timer: `TMOD &= 0xF0; TMOD |= 0x01;`.
2) Reload value
/* 50ms at 12MHz (1us/count) */
needed count = 50ms / 1us = 50000
reload = 65536 - 50000 = 15536 = 0x3CB0
TH0 = 0x3C; TL0 = 0xB0;
/* general: reload = 65536 - us, TH = reload>>8, TL = reload & 0xFF */3) TCON — start and flags, polling flow
| Bit | Role |
|---|---|
| TR0/TR1 | 1 runs the timer (start) |
| TF0/TF1 | set on overflow (software clears) |
set TMOD → load TH/TL → TF=0 → TR=1
→ while(TF==0) wait → TR=0 → TF=0 (clear)Polling ties up the CPU while waiting. To do other work meanwhile, use a timer interrupt (lesson 10).
Core example
#include <reg52.h>
sbit LED = P1 ^ 0;
static void delay_50ms(void) {
TMOD &= 0xF0; TMOD |= 0x01; /* Timer0 Mode1 */
TH0 = 0x3C; TL0 = 0xB0; /* 50ms @ 12MHz */
TF0 = 0; TR0 = 1; /* start */
while (TF0 == 0) { } /* wait for overflow */
TR0 = 0; TF0 = 0; /* stop·clear */
}
void main(void){ while(1){ LED = (bit)!LED; delay_50ms(); } }Reload check: 1000µs→0xFC18, 5000µs→0xEC78, 50000µs→0x3CB0.
Common mistakes
Q. Assigning TMOD = 0x01 wiped Timer1's config.
A. TMOD holds both timers. Change only that timer's bits: Timer0 is `TMOD &= 0xF0; TMOD |= 0x01;`.
Q. The first delay works, then it passes instantly.
A. You didn't re-clear TF. Mode1 isn't auto-reload, so reload TH/TL and clear TF=0 each time.
Q. I can't make a long delay like 1 second.
A. 16-bit (1µs) caps at ~65ms per shot. Make longer delays by counting short overflows (1s = 50ms × 20).
Summary
- A hardware timer makes precise time independent of the CPU
- TMOD sets mode (Mode1=16-bit); Timer0=low nibble, Timer1=high nibble
- reload = 65536 − count, TH=high·TL=low
- TR starts, poll TF for overflow, clear TF every time
- Make long delays by counting overflows
Exercises
- Hand-compute TH/TL for 10ms·100ms at 12MHz and verify in pc_test
- Write a 1-second delay by counting twenty 50ms overflows
- Make the same delay with Timer1 and check the TMOD high-nibble setup
All lecture materials and example code (with homework and answers) are openly available on GitHub.
View on GitHub ↗