← Back to Embedded C series
🔌
8051
8051 · Prereq: lesson 8

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.

timerTMODTH/TLoverflowTFreload
Duration
~1.5 hours
Level
📊 Beginner
Prerequisite
🎯 Lesson 8
OUTCOME
Set Timer0/1 to Mode1, compute reload (65536−count), and poll TF for precise delays.

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

c
/* 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

BitRole
TR0/TR11 runs the timer (start)
TF0/TF1set on overflow (software clears)
c
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

c
#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

  1. Hand-compute TH/TL for 10ms·100ms at 12MHz and verify in pc_test
  2. Write a 1-second delay by counting twenty 50ms overflows
  3. Make the same delay with Timer1 and check the TMOD high-nibble setup
Example code / lecture materials

All lecture materials and example code (with homework and answers) are openly available on GitHub.

View on GitHub ↗