When you move beyond blinking LEDs with delay() and start building motor controllers, digital audio synthesizers, or precision sensor interfaces, you must interact directly with hardware timers. Understanding how to calculate prescaler and compare register values is a fundamental rite of passage for embedded engineers. Below, we break down one of the most common exam and interview problems in embedded systems, using practical microcontroller examples to bridge the gap between textbook theory and bench-level reality.

The Problem Statement: Generating Exact 50Hz PWM

Exam Problem:
You are programming an ATmega328P microcontroller (as found on the Arduino Uno) running at a 16 MHz external crystal oscillator. You need to generate a precise 50 Hz square wave (20 ms period) to drive a standard RC servo motor using Timer1 in Clear Timer on Compare Match (CTC) mode.

Given:
  • System Clock ($f_{clk}$) = 16,000,000 Hz
  • Target Frequency ($f_{pwm}$) = 50 Hz
  • Timer1 is a 16-bit register (maximum value 65,535)
  • Available Timer1 Prescalers ($N$): 1, 8, 64, 256, 1024
Find: The optimal prescaler value ($N$) and the exact Output Compare Register value ($OCR1A$). Show all algebraic steps and justify your prescaler choice.

Step-by-Step Algebraic Solution

Which Method Applies and Why

This problem requires the timer clock division and modulo counting method. In CTC mode, the timer increments on every clock tick (after prescaling) until it matches the value in the $OCR1A$ register. Upon matching, the timer resets to zero and toggles the output pin. Because the timer counts from 0 up to and including OCR1A, the total number of ticks per cycle is $OCR1A + 1$. The governing equation for the output frequency is:

$$f_{pwm} = \frac{f_{clk}}{N \times (1 + OCR1A)}$$

The Trap in This Problem

Warning: The Dual Trap
1. The Off-By-One Error: Beginners often forget the +1 in the denominator. Because the counter starts at 0, an OCR1A value of 99 yields 100 ticks, not 99. Dropping the +1 results in a frequency slightly higher than intended.
2. Register Overflow: If you blindly choose a prescaler of $N=1$ without checking the math, your calculated $OCR1A$ will exceed 65,535, overflowing the 16-bit hardware register and causing catastrophic timing errors.

Algebraic Rearrangement and Calculation

First, we rearrange the governing equation to solve for $OCR1A$:

$$1 + OCR1A = \frac{f_{clk}}{f_{pwm} \times N}$$

$$OCR1A = \frac{f_{clk}}{f_{pwm} \times N} - 1$$

Next, we test the available prescalers ($N$) to find one that yields an integer $OCR1A$ value between 0 and 65,535.

Test 1: Prescaler $N = 1$

$$OCR1A = \frac{16,000,000}{50 \times 1} - 1$$

$$OCR1A = 320,000 - 1 = 319,999$$

Result: 319,999 > 65,535. This overflows the 16-bit register. $N=1$ is invalid.

Test 2: Prescaler $N = 8$

$$OCR1A = \frac{16,000,000}{50 \times 8} - 1$$

$$OCR1A = \frac{16,000,000}{400} - 1$$

$$OCR1A = 40,000 - 1 = 39,999$$

Result: 39,999 is well within the 16-bit limit (max 65,535). This is a valid, high-resolution solution.

Test 3: Prescaler $N = 64$ (For Comparison)

$$OCR1A = \frac{16,000,000}{50 \times 64} - 1$$

$$OCR1A = \frac{16,000,000}{3,200} - 1$$

$$OCR1A = 5,000 - 1 = 4,999$$

Result: Valid. However, $N=8$ is preferred because a higher $OCR1A$ value (39,999 vs 4,999) provides finer granularity if you later decide to adjust the duty cycle or slightly tweak the frequency in software.

Final Answer: Use Prescaler $N = 8$ and set $OCR1A = 39,999$.

Answer Sanity Check

Always verify your answer by plugging the values back into the original equation and checking the order of magnitude and units.

$$f_{pwm} = \frac{16,000,000 \text{ Hz}}{8 \times (1 + 39,999)}$$

$$f_{pwm} = \frac{16,000,000}{8 \times 40,000}$$

$$f_{pwm} = \frac{16,000,000}{320,000} = 50 \text{ Hz}$$

Units check: $\frac{\text{cycles/second}}{\text{(cycles/tick)} \times \text{ticks}} = \frac{1}{\text{second}} = \text{Hz}$. The math holds perfectly. For deeper register-level configuration details, refer to the official Microchip ATmega328P Datasheet, specifically Section 16 on 16-bit Timer/Counter1.

How to Verify the Answer Independently

Math on a whiteboard is only half the battle; bench verification is where engineering actually happens. To verify this independently without relying on software serial prints (which introduce latency and jitter), use a digital storage oscilloscope (DSO) or a dedicated logic analyzer like the Saleae Logic Pro 16.

  1. Probe Setup: Connect your scope probe to the hardware PWM output pin (Digital Pin 9 on the Uno for Timer1 Channel A). Ensure the probe ground clip is attached to the microcontroller GND, not just the USB shield.
  2. Timebase Configuration: Set the oscilloscope horizontal timebase to 5.00 ms/division. A 20 ms period will span exactly four horizontal divisions.
  3. Triggering: Set the trigger to 'Normal' mode, rising edge, at 2.5V (assuming 5V logic).
  4. Measurement Verification: Use the scope's automated cursors to measure the Period and Positive Width.
    • Expected Period: 20.00 ms (± 0.05 ms depending on crystal tolerance).
    • Expected High Time: 10.00 ms (if configured for 50% duty cycle).
Bench Tip: If your measured frequency is 50.2 Hz instead of 50.0 Hz, do not blame your algebra. Standard Arduino boards use a ceramic resonator for the 16 MHz clock, which has a tolerance of ±0.5%. For exact 50.000 Hz, you must use a board with a temperature-compensated crystal oscillator (TCXO) or measure the actual clock frequency with a frequency counter and adjust $OCR1A$ accordingly.

FAQ: Common Questions on Microcontroller Examples

What are some real-world microcontroller examples where timer math is critical?

Timer math extends far beyond servo control. In digital power supplies, you must calculate exact ADC sampling triggers synchronized to the PWM switching frequency to avoid switching noise (often requiring sub-microsecond precision). In ultrasonic anemometers or time-of-flight LiDAR sensors, input capture timers measure the exact microsecond delta between a trigger pulse and an echo return. Another classic example is generating baud rates for UART communication; a miscalculated timer prescaler for the baud rate generator will result in framing errors and dropped packets at high speeds like 115,200 baud.

How do ESP32 microcontroller examples handle PWM differently than AVR?

The ESP32 abandons the manual prescaler and compare-register math used in the ATmega328P. Instead, it utilizes the LEDC (LED Control) peripheral. When writing ESP32 microcontroller examples in the Arduino IDE or ESP-IDF, you do not calculate register values manually. You call ledcSetup(channel, freq, resolution), and the underlying hardware abstraction layer (HAL) configures the APB clock dividers and 20-bit timers automatically. For instance, requesting a 50 Hz signal at 16-bit resolution on an ESP32 running an 80 MHz APB clock is handled entirely by the Espressif LEDC API. However, understanding the AVR math is still crucial for debugging when the ESP32 HAL throws resolution-limit errors at high frequencies.

Why do my microcontroller examples drift over time when using the internal oscillator?

If you attempt these timer calculations on an ATtiny85 or an AVR chip running on its internal 8 MHz RC oscillator, your 50 Hz signal will drift. Internal RC oscillators are highly sensitive to ambient temperature and VCC voltage fluctuations (VCC droop under load shifts the frequency). A 2% drift in the base clock translates directly to a 2% drift in your PWM frequency. For a standard RC servo, a 2% shift in the 20 ms period (0.4 ms) might push a 1.5 ms center-pulse to 1.53 ms, causing the servo to physically creep or jitter. Always use an external quartz crystal or ceramic resonator for timing-critical microcontroller examples.