Arduino Timers: Complete Usage Guide


Core Concept: Arduino microcontrollers (ATmega328P/ATmega2560) contain dedicated hardware timers that handle time-sensitive operations independently of the CPU.
1. Available Timers by Board
Board | Timers (Resolution) | Key Functions |
Uno/Nano | 0 (8-bit), 1 (16-bit), 2 (8-bit) | millis() , PWM, interrupts |
Mega | 0-5 (4x 16-bit, 2x 8-bit) | Advanced motor control, multiple PWM |
ESP32 | 4x 64-bit | Wi-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
Resource Conflicts
Symptom: Servo jitter when using
tone()
Fix: Use separate timers (Servo→Timer1, tone→Timer2)
PWM Frequency Limitations
8-bit timers max out at ~62.5kHz (16MHz/256)
Solution: Use 16-bit timers or clock dividers
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
Operation | Cycles | Accuracy @16MHz |
Timer ISR | 6-12 | ±62.5ns |
Software ISR | 50-200 | ±6.25μs |
millis() update | 4 | ±250ns |
7. Debugging Tips
Verify timer clock source:
cpp
Serial.println(TCCR1B & 0x07); // Prescaler bits
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.
Subscribe to my newsletter
Read articles from ampheo directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
