Arduino Timers: Complete Usage Guide

ampheoampheo
3 min read

Core Concept: Arduino microcontrollers (ATmega328P/ATmega2560) contain dedicated hardware timers that handle time-sensitive operations independently of the CPU.


1. Available Timers by Board

BoardTimers (Resolution)Key Functions
Uno/Nano0 (8-bit), 1 (16-bit), 2 (8-bit)millis(), PWM, interrupts
Mega0-5 (4x 16-bit, 2x 8-bit)Advanced motor control, multiple PWM
ESP324x 64-bitWi-Fi/BLE coexistence

2. Critical Timer Applications

A. PWM Generation

  • Timer-controlled pins marked with ~ (3,5,6,9,10,11 on Uno)

  • Frequency adjustment example:

    cpp

      // Set Timer1 PWM to 4kHz (default ~490Hz)
      TCCR1B = (TCCR1B & 0b11111000) | 0x02;
    

B. Precise Event Scheduling

  • Hardware interrupts vs software delays:

    cpp

      // Hardware-timed (accurate)
      TIMSK1 |= (1 << OCIE1A); 
      OCR1A = 15999; // 1ms @ 16MHz/1 prescaler
    
      // Software delay (inaccurate)
      delay(1); // Varies with interrupts
    

C. Motor Control

  • Servo library uses Timer1 (conflicts with AnalogWrite on 9,10)

  • Advanced ESC control requires 16-bit timers


3. Register-Level Configuration

Timer1 Setup for 1Hz Interrupt:

cpp

void setupTimer1() {
  noInterrupts();
  TCCR1A = 0; // Clear control registers
  TCCR1B = 0;
  TCNT1 = 0;  // Reset counter

  // Compare match value for 1Hz
  OCR1A = 15624; // 16MHz/1024 prescaler - 1

  TCCR1B |= (1 << WGM12); // CTC mode
  TCCR1B |= (1 << CS12) | (1 << CS10); // 1024 prescaler
  TIMSK1 |= (1 << OCIE1A); // Enable interrupt
  interrupts();
}

4. Common Pitfalls & Solutions

  1. Resource Conflicts

    • Symptom: Servo jitter when using tone()

    • Fix: Use separate timers (Servo→Timer1, tone→Timer2)

  2. PWM Frequency Limitations

    • 8-bit timers max out at ~62.5kHz (16MHz/256)

    • Solution: Use 16-bit timers or clock dividers

  3. ISR Timing Drift

    • Always clear overflow flags:

cpp

    ISR(TIMER1_OVF_vect) {
      TIFR1 |= (1 << TOV1); // Clear flag
      // Your code
    }

5. Advanced Techniques

Phase-Correct PWM (for motor control):

cpp

TCCR1A = (1 << COM1A1) | (1 << WGM10);
TCCR1B = (1 << CS10); // No prescaling

Input Capture (for frequency measurement):

cpp

TCCR1B |= (1 << ICES1); // Rising edge capture
TIMSK1 |= (1 << ICIE1); // Enable capture interrupt

6. Performance Considerations

OperationCyclesAccuracy @16MHz
Timer ISR6-12±62.5ns
Software ISR50-200±6.25μs
millis() update4±250ns

7. Debugging Tips

  1. Verify timer clock source:

    cpp

     Serial.println(TCCR1B & 0x07); // Prescaler bits
    
  2. Check for overflow:

    cpp

     if(TIFR1 & (1 << TOV1)) { /* Handle overflow */ }
    

When to Use Which Timer

  • Timer0: System functions (don't modify)

  • Timer1: High-resolution control (16-bit)

  • Timer2: Audio applications (8-bit with async operation)

For time-critical applications (quadcopter flight controllers, digital signal processing), always use hardware timers instead of software timing functions.

0
Subscribe to my newsletter

Read articles from ampheo directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

ampheo
ampheo