Embedded

8051 Timers Counters

By CourseTron Team ·  8 min read ·  Updated Oct 2026 💬 𝕏 in f
Table of Contents
    ? Print / Save as PDF

    In short: The 8051 has two 16-bit timer/counter blocks (Timer 0 and Timer 1) that either count machine cycles to measure time or count external pulses, with their behaviour set by the TMOD and TCON registers and their four operating modes (0–3).

    Timers and counters are the first piece of 8051 hardware that turns a bare microcontroller into something that can measure the real world. Whether you are generating a precise 1 ms tick, debouncing a switch, baud-rate-clocking a UART, or counting widgets off a conveyor, you are using the same two on-chip blocks. This article walks through how they are built, how you configure them, and how to compute a delay you can actually trust on a scope.

    One block, two personalities: timer vs counter

    Each block is a 16-bit up-counter. The only difference between timer mode and counter mode is where the clock pulses come from. In timer mode the register increments on the internal clock, specifically once every machine cycle. On the classic 8051 a machine cycle is 12 oscillator periods, so with a 12 MHz crystal the timer ticks once per microsecond. In counter mode the register increments on a 1→0 transition applied to the external pins T0 (P3.4) or T1 (P3.5).

    With a 12 MHz crystal, 1 machine cycle = 12 / 12 MHz = 1 µs. That single number is the key to every software delay you will ever compute on an 8051.

    Timer vs counter: the C/T switch OSC ÷ 12 machine cycle T0 / T1 pin external pulses C/T = 0 C/T = 1 C/T 16-bit counter THx : TLx TFx flag overflow FFFFh → 0000h roll-over sets TFx CourseTron · coursetron.com
    The C/T bit selects whether the 16-bit register is fed by the internal machine-cycle clock (timer) or by external pulses (counter). Overflow from FFFFh to 0000h sets the TFx flag.

    TMOD: setting the mode

    TMOD is a single 8-bit register (not bit-addressable) split into two identical nibbles, the upper for Timer 1 and the lower for Timer 0. Each nibble holds four controls:

    • GATE – when 1, the timer runs only while the external INTx pin is high (hardware-gated pulse-width measurement); when 0, software alone starts it.
    • C/T – 0 = timer (internal clock), 1 = counter (external pin).
    • M1 M0 – the two mode-select bits that pick modes 0 through 3.

    So to run Timer 0 as a 16-bit timer you write TMOD = 0x01 (lower nibble = 0001). To run Timer 1 as an 8-bit auto-reload timer for the UART you write the upper nibble 0x20. Because the nibbles are independent you usually OR the two halves together, e.g. TMOD = 0x21.

    TMOD register: two identical nibbles Upper nibble: Timer 1 Lower nibble: Timer 0 GATEbit 7C/Tbit 6M1bit 5M0bit 4GATEbit 3C/Tbit 2M1bit 1M0bit 0 Example TMOD = 0x21 → 0010 0001 Timer 1: mode 2 (8-bit auto-reload), Timer 0: mode 1 (16-bit) GATE = 0 and C/T = 0 in both: software-started internal timers CourseTron · coursetron.com
    TMOD holds one nibble per timer: GATE, C/T, M1 and M0. The value 0x21 selects mode 2 for Timer 1 and mode 1 for Timer 0.

    TCON: run control and flags

    TCON is bit-addressable, which matters because you flip its bits constantly. Its upper half belongs to the timers:

    • TR0 / TR1 – the run bits. Setting TR0 = 1 starts Timer 0; clearing it freezes the count in place.
    • TF0 / TF1 – the overflow flags, set by hardware when the counter rolls over FFFFh→0000h. In polled code you wait on TFx and clear it in software; if interrupts are enabled it vectors the CPU to the timer ISR and is cleared automatically.

    The lower half of TCON (IE0, IT0, IE1, IT1) handles the external interrupts and is covered in our companion piece on 8051 interrupts.

    The four operating modes

    ModeM1 M0StructureMax countTypical use
    00 013-bit (THx + 5 bits of TLx)8192Legacy 8048 compatibility
    10 1Full 16-bit65536General long delays
    21 08-bit with auto-reload from THx256UART baud rate, periodic tick
    31 1Timer 0 split into two 8-bit timers256 eachA third timer when you need one

    Mode 1 is the workhorse for one-shot delays up to ~65.5 ms at 12 MHz. Mode 2 is prized because after each overflow the hardware reloads TLx from THx with zero software overhead, giving a jitter-free periodic event; this is exactly why the UART uses Timer 1 in mode 2 to clock its baud rate. Mode 3 is a special trick: it freezes Timer 1's run control and turns Timer 0 into two separate 8-bit timers (TL0 using TR0/TF0, TH0 borrowing TR1/TF1), handy when a design is one timer short.

    Computing a timer-based delay

    Suppose you want a 50 ms delay on a 12 MHz part using Timer 0 in mode 1. At 1 µs per tick you need 50000 ticks. The counter counts up and overflows at 65536, so you preload it with the complement:

    count = 65536 − 50000 = 15536 = 0x3CB0 → TH0 = 0x3C, TL0 = 0xB0.

    The polled routine is simply: load TMOD, load TH0/TL0, set TR0, wait for TF0, then stop and clear:

    • TMOD = 0x01; — Timer 0, mode 1
    • TH0 = 0x3C; TL0 = 0xB0; — preload for 50000 counts
    • TR0 = 1; — start
    • while(TF0 == 0); — poll overflow
    • TR0 = 0; TF0 = 0; — stop and clear the flag

    For delays longer than 65.5 ms you simply loop this block, e.g. call a 50 ms routine twenty times for one second. For rock-steady periodic ticks you move to mode 2 with an interrupt so the reload and flag-clear cost nothing.

    Counter fills, then TFx fires THx:TLx counting 0x3CB0 up to 0xFFFF TFx overflow Preload = 65536 − 50000 = 15536 (0x3CB0) 50000 ticks at 1 µs each = 50 ms CourseTron · coursetron.com
    The register fills from its preload value; at the FFFFh→0000h roll-over the TFx flag pulses, signalling the end of the interval.

    Common pitfall: forgetting that the reload value is 2n − N, not N. Loading 50000 directly instead of 65536−50000 gives a 15.5 ms delay, not 50 ms — a classic lab bug.

    Modern design flows let you verify this behaviour before touching silicon: an 8051 soft-core written in Verilog can be simulated in Synopsys VCS or Siemens Questa, and the timer overflow checked against a testbench assertion, so the reload arithmetic is proven in regression rather than on a breadboard. If you want to go deeper into synthesisable microcontroller IP and verification, our partners at Avecas VLSI design services build and tape out exactly this kind of block.

    Timers, baud rates and interrupts together

    In real firmware the three subsystems interlock. Timer 1 in mode 2 generates the UART clock; Timer 0 in mode 1 or 2 raises an interrupt for your periodic scheduler tick; and the external-interrupt bits in TCON handle asynchronous events. Learning to read TMOD and TCON fluently is what lets you make all of this coexist without stepping on each other. See how the overflow flag becomes a vectored event in 8051 interrupts, and how the same timer clocks serial traffic in 8051 serial communication.

    Ready to master the 8051 hands-on, from registers to real firmware? Explore the full embedded systems track on our CourseTron courses page and build timer-driven projects in simulation and on hardware. Training-focused readers can also check ChipXpert's VLSI and embedded programs.

    Frequently asked questions

    Why does the timer tick once every 12 clock cycles?

    The original Intel 8051 divides the oscillator by 12 to form one machine cycle, and the timer increments per machine cycle. Many modern derivatives (such as Dallas/Maxim and Silicon Labs cores) offer a single-cycle or divide-by-1/4 option, so always check your datasheet before computing delays.

    What is the difference between TF0 polling and using an interrupt?

    Polling while(TF0==0) blocks the CPU until overflow and you must clear TF0 yourself. With the timer interrupt enabled, the overflow vectors to the ISR and TF0 is cleared by hardware, freeing the CPU to do other work between ticks.

    When would I use mode 2 over mode 1?

    Choose mode 2 for periodic events that must not drift, such as a baud-rate clock or a fixed-interval scheduler tick, because the auto-reload from THx happens in hardware with no software jitter. Mode 1 is better for arbitrary one-shot delays up to 65.5 ms.

    Can I count external events faster than the machine cycle?

    No. In counter mode the pin is sampled once per machine cycle, so a full high-then-low needs at least two machine cycles. The maximum reliable external count rate is therefore about 1/24 of the oscillator frequency (roughly 500 kHz at 12 MHz).

    Advertisement