BFM1143 Embedded System Programming - Week 4: Timers in Embedded Systems
Lesson Outcomes
Explain the role and configuration of timers and counters in Arduino (L3).
Apply PWM techniques to control actuators such as LEDs and motors (L3).
Analyze the effect of frequency, duty cycle, and prescalers on timer/PWM behavior (L4).
Design timer-based event scheduling and non-blocking delays (L5).
Why Timing is Crucial in Embedded Systems?
Required in operations like waiting for a sensor to stabilize or controlling the blink rate of an LED.
Example: A temperature sensor might require a delay between readings.
Allows multiple tasks to be executed at predictable intervals.
Example: Read sensor every , update LCD every , check button state every .
Generate digital square waves or analog-like signals using PWM.
Example: Generating a square wave to control an IR remote or tone for a buzzer.
Critical in systems like motor control, where missing a timing window may cause instability or failure.
Precise Delays
Task Scheduling
Waveform Generation
Real-Time Response
Why Not Just Use delay()?
delay(ms)is blockingFreezes the entire microcontroller—no other tasks can run until the delay is over.
Makes multitasking nearly impossible.
Inefficient
Wastes CPU cycles doing nothing.
Example: A
delay()pauses your entire system for 1 second.
Bad Practice for Complex Projects
As programs grow,
delay()leads to bugs, poor responsiveness, and inconsistent behavior.
Why Use Hardware Timers Instead?
Non-blocking Timing
Continue running other code while waiting for an event to occur (e.g., using
millis()or interrupts).
More Accurate
Hardware-based timing is less affected by other code delays or interruptions.
Versatile
Can be configured for:
Periodic interrupts
Event counting
PWM signal generation
Custom scheduling mechanisms
Example Real-World Applications
Digital Watch: Timer tracks milliseconds to update seconds, minutes, and hours.
PWM Fan Controller: Adjust speed using duty cycle.
Ultrasonic Sensor: Measures time between signal sent and received to calculate distance.
Smart Lights: Use timers to fade in/out brightness without freezing the rest of the program.
What is a Timer/Counter?
A Timer/Counter is a hardware peripheral built into microcontrollers that:
Timer Mode: Counts internal clock cycles (used for time-based operations).
Counter Mode: Counts external events/pulses (used for event-based triggering).
Timers operate independently from the CPU once configured, enabling non-blocking multitasking.
Non-blocking multitasking allows a system to perform multiple tasks concurrently without waiting for one task to complete before starting another, improving efficiency and responsiveness.
Timer vs Counter Modes
Feature | Timer Mode | Counter Mode |
|---|---|---|
Clock Source | Internal clock | External pin (e.g., T0, T1 on Arduino) |
Use Case | Delays, PWM, periodic interrupts | Event counting, frequency measurement |
Typical Input | System clock (e.g., 16 MHz) | Signal from external hardware/sensor |
Core Functionalities
Start/Stop
Enable or disable counting.
Prescaler
Divides the clock to slow down the count (e.g., divide ).
Compare Match
Triggers an action (e.g., interrupt) when the counter reaches a value.
Overflow
When the counter exceeds its maximum (e.g., 255 for 8-bit), it resets and may trigger an interrupt.
Clock and Prescaler Concepts
System Clock and Timers
Every microcontroller (like Arduino Uno) runs on a system clock—usually .
This clock signal feeds internal peripherals, including timers/counters.
Timers count these pulses to measure time or trigger events.
Without adjustment, a timer would increment 16 million times per second—way too fast for practical delays!
What is a Prescaler?
A prescaler is a hardware divider that slows down the input clock before it reaches the timer.
It divides the system clock by a fixed factor (e.g., 8, 64, 256), allowing for longer intervals between each timer increment.
Why Use a Prescaler?
To extend the range of timer-based delays or PWM frequencies.
To fine-tune the resolution and frequency of interrupts or waveforms.
To match timer behavior with the application (e.g., slower LED fading vs. fast sensor response).
Example Calculation
System clock =
Prescaler = 64
So, the timer ticks once every instead of every .
Timer input frequency =
If using an 8-bit timer (max count = 255):
Max delay = before overflow.
Use a higher prescaler or combine with overflow interrupts for longer delays.
Prescaler Options on Arduino Uno (ATmega328P)
Prescaler Value | Description |
|---|---|
1 | Fastest (no scaling) |
8 | Slower timing, more usable |
64 | Common for millisecond delays |
256 | Longer delays, lower resolution |
1024 | Longest delays, coarsest timing |
Timer Modes in Arduino Uno (ATmega328P)
The Arduino Uno, based on the ATmega328P microcontroller, has three timers: Timer0, Timer1, and Timer2.
These timers can be configured in different modes for various tasks such as timing, generating PWM signals, or creating delays.
The timers in the ATmega328P are essential for controlling and managing time-based operations.
Timer0
Timer0 (8-bit):
Bit width: 8-bit, range of 0 to 255
Common Use: Used by functions like
millis()anddelay()Resolution: Timer0 increments every clock cycle and is typically used for generating time intervals like milliseconds.
Timer1
Timer1 (16-bit):
Bit width: 16-bit, range of 0 to 65535
Common Use: Used for more precise timing and higher resolution, often in applications requiring a larger range (e.g., accurate time delays or PWM generation).
Resolution: Allows for finer control over timing since it can count up to 65535, compared to the 8-bit timers.
Timer2
Timer2 (8-bit):
Bit width: 8-bit, range of 0 to 255
Common Use: Similar to Timer0 but can be used for additional timing or PWM tasks in cases where Timer0 is already used by the Arduino core functions.
Resolution: Like Timer0, it can be used for shorter time intervals and simpler tasks.
Comparison of Timer0, Timer1, and Timer2
Feature | Timer0 (8-bit) | Timer1 (16-bit) | Timer2 (8-bit) |
|---|---|---|---|
Bit Width | 8-bit | 16-bit | 8-bit |
Range | 0 to 255 | 0 to 65535 | 0 to 255 |
Common Uses | Timekeeping, | Precise timing, PWM generation | Additional PWM or timing |
Resolution | 1 clock cycle (8-bit) | 1 clock cycle (16-bit) | 1 clock cycle (8-bit) |
Prescaler Options | Yes, 8-bit prescalers | Yes, 16-bit prescalers | Yes, 8-bit prescalers |
PWM Capability | Yes (for basic PWM) | Yes (higher resolution PWM) | Yes (additional PWM) |
Interrupts | Yes | Yes | Yes |
Typical Uses | General time delays | Precise time delays, square waves | PWM signal generation |
Example Functions |
| Square wave, high-precision PWM | PWM generation on extra pins |
Possible Issues When Timer is Wrongly Chosen
Issue | Consequence | Example |
|---|---|---|
Timer Conflict |
| Using Timer0 PWM |
PWM Resolution | Limited/wrong signal | 8-bit for PWM |
Inaccurate Timing | Imprecise intervals | Incorrect Delays |
Limited Timer F | Less flexibility | Running out |
Interrupt Issues | Poor task management | Wrong selection |
Best Practices
Choose the correct timer (Timer1 for PWM, Timer0 for timekeeping).
Be aware that Timer0 is shared by core functions like
millis()anddelay().Avoid using
delay()for real-time multitasking; use timers or interrupts.If high-resolution PWM is necessary, use Timer1 (16-bit).
If running out of timers, manage them properly.
Timer Modes
1. Normal Mode
Description: The timer counts from 0 to its maximum value and overflows back to 0.
Common Use: Basic counting and generating interrupts on overflow.
Overflow Behavior: When the timer overflows, it triggers an interrupt (if enabled).
Comparison of Normal Mode on Different Timers
Timer | Bit Width | Range (Counts) | Overflow Behavior | Common Use |
|---|---|---|---|---|
Timer0 | 8-bit | 0 to 255 | Overflows every 256 cycles | General-purpose timing |
Timer1 | 16-bit | 0 to 65,535 | Overflows every 65,536 cycles | High-precision timing |
Timer2 | 8-bit | 0 to 255 | Overflows every 256 clock cycles | Additional PWM |
2. CTC (Clear Timer on Compare Match) Mode
CTC mode allows the timer to count from 0 to a predefined value stored in the OCRn register.
When the timer's count matches the value in OCRn, it resets to 0 and can trigger an interrupt if enabled.
CTC is useful for creating precise time delays or frequencies, like generating PWM or creating time intervals.
When to Use CTC Mode?
Precise Time Delays: Blink an LED every 100ms.
PWM (Pulse Width Modulation): Create a PWM signal to dim an LED.
Generate Regular Interrupts: Read a sensor every 200ms.
Non-blocking Delays: Run background tasks while blinking an LED.
Generate Precise Frequencies: Generate a 1kHz tone for a buzzer.
3. Fast PWM Mode
Purpose: Used to generate high-frequency PWM signals for controlling devices like LEDs and motors.
How It Works:
The timer counts from 0 to 255 (for 8-bit timers) or 0 to 65535 (for 16-bit timers).
When the counter reaches a specific value in the OCRn register, the PWM output changes.
This repeats continuously, generating a fast PWM signal with a defined frequency and duty cycle.
Common Uses:
Controlling LED brightness: Vary the duty cycle to adjust how bright the LED appears.
Controlling motor speed: Adjust the duty cycle (higher duty cycle means faster motor speed).
When to use Fast PWM Mode:
Controlling LED Brightness: Adjust the brightness by changing the duty cycle.
Controlling Motor Speed: Change the motor speed by varying the duty cycle.
High-Frequency Signals: For tasks needing fast switching, like sensors or audio signals.
Power Efficiency: Ideal for low-power applications as it reduces energy use.
4. Phase Correct PWM Mode
Description:
Phase Correct PWM Mode counts up to the maximum value, then counts back down to 0. This gives a smoother, more gradual transition compared to Fast PWM, reducing electrical noise and providing more precise control.
Common Use:
Ideal for applications requiring smoother motor speed control or precise PWM signals (e.g., audio systems or low-noise motors).
How It Works:
The timer counts up from 0 to the maximum value.
After reaching the maximum value, it counts back down to 0.
This creates a smoother PWM waveform, reducing abrupt changes in the signal compared to Fast PWM.
Summary of Timer Modes
Mode | Common Use | Speed | Smoothness | Best For | Not Ideal For |
|---|---|---|---|---|---|
Normal Mode | Basic counting | Slow | Abrupt | Simple time intervals | PWM or smooth control |
CTC Mode | Time delays, waveform gen | Moderate | Moderate | Precise timing | Fast updates |
Fast PWM Mode | LED dimming, motor control | Fast | Moderate | High-speed PWM signals | Smooth transitions |
Phase Correct PWM | Motor control, precision PWM | Moderate | Smooth | Smooth, low-noise ctrl | High-speed tasks |
Understanding Timer Registers
In embedded systems, Timer Registers are crucial for controlling the behavior of timers, such as configuring modes (e.g., CTC, PWM), setting timer values, and enabling interrupts.
Understanding these registers is essential for advanced time management, event scheduling, and precise control over the microcontroller’s operations.
TCCRnA (Timer/Counter Control Register A)
Purpose:
Configures the timer's mode of operation (e.g., Normal, CTC, PWM).
Controls the output pins for PWM signals (e.g., controlling whether the output pin is toggled, cleared, or set).
Common Bits in TCCRnA:
WGMn3:0 (Waveform Generation Mode bits): These bits define the mode of operation of the timer.
COMnA1/0 & COMnB1/0 (Compare Match Output Mode bits): These bits control how the timer's output pin behaves when the counter reaches a certain value (useful for PWM).
TCCRnB (Timer/Counter Control Register B)
Purpose: Defines additional settings such as prescaler, clock source, and mode selection for timers.
Common Bits:
WGMn3:2 (Waveform Generation Mode Bits): These bits work with TCCRnA's WGMn1:0 bits to set the timer mode.
CSn2:0 (Clock Select Bits): These bits select the prescaler for the timer. The prescaler divides the timer's clock.
Common Prescaler Settings for CSn2:0
CSn2:0 | Prescaler Value | Timer Frequency |
|---|---|---|
000 | No prescaling (1) | Sys clock speed |
001 | Prescaler of 8 | Timer / 8 |
010 | Prescaler of 64 | Timer / 64 |
011 | Prescaler of 256 | Timer / 256 |
100 | Prescaler of 1024 | Timer / 1024 |
Output Compare Register (OCRn)
Purpose:
Used in CTC (Clear Timer on Compare Match) mode or PWM mode.
The timer compares the value in the OCRn register with the current value in TCNTn, and when they match, an interrupt is triggered or the timer is reset to zero.
Common Use:
CTC Mode: Used to define the value at which the timer will reset and trigger an interrupt.
PWM Mode: Used to set the duty cycle of the PWM waveform.
Timer Interrupt Mask Register (TIMSKn)
Purpose: Enables or disables interrupts for the timer. Each bit in the TIMSKn register corresponds to a specific interrupt associated with the timer.
Example:
TIMSK1 |= (1 << OCIE1A);– This enables the interrupt for Timer1's compare match A (when TCNT1 matches OCR1A).For example, enabling OCIE1A allows an interrupt when the Timer1 matches the value in OCR1A.
Timer Interrupt Flag Register (TIFRn)
Purpose: Contains flags that indicate when a timer event has occurred, such as a compare match or overflow. These flags are cleared when the interrupt service routine (ISR) is executed.
Example:
TIFR1 |= (1 << OCF1A);– This clears the Timer1 Compare Match A flag.For example, when a timer overflow occurs, the overflow flag is set in TIFRn.
Timer Overflow
Definition: An overflow occurs when the timer’s count reaches its maximum value and then wraps around (resets to 0).
8-bit timers have a maximum count of 255. When the timer reaches 255, it overflows back to 0.
16-bit timers have a maximum count of 65535. Once the timer reaches this value, it overflows and resets to 0.
Overflow Event: When the timer overflows, it triggers an interrupt (if enabled) or can be used to reset the timer for a continuous counting cycle.
Compare Match
Definition: A compare match occurs when the value of the timer (TCNTn) matches the value stored in the Output Compare Register (OCRn).
The compare match can occur in two ways: compare match A and compare match B (for timers with multiple compare registers, such as Timer1).
Timer Overflow: Occurs when the timer’s count exceeds its maximum value.
Compare Match: Occurs when the timer's value matches the OCRn register value.
What is a Counter (vs Timer)?
A counter is a specialized timer that counts external events or signals, whereas a timer counts clock cycles generated internally by the microcontroller’s clock source.
Timer: Counts internal clock cycles that are divided by a prescaler to extend the timer’s range.
Counter: Counts events that occur externally. These events might be generated by sensors, user input, or other devices.
Using millis() for Non-blocking Delay
Non-blocking delay is a technique used in embedded systems to avoid halting the execution of the program while waiting for a delay.
millis()is a built-in Arduino function that returns the number of milliseconds that have passed since the Arduino board was powered up or reset.delay()blocks the program for a specified time, preventing the execution of other code while waiting.millis()allows the program to continue executing while waiting for a certain time to pass, thus enabling non-blocking behavior.
Using micros() for Microsecond Precision
micros()is a built-in Arduino function that returns the number of microseconds since the Arduino board was powered up or reset.It provides a higher resolution than
millis(), which tracks time in milliseconds., so
micros()gives finer precision for time-sensitive applications.Key Characteristics of
micros()Resolution: Returns time in microseconds.
Overflow: Can overflow after approximately 70 minutes.
Precision: Useful for measuring short time intervals or controlling time-sensitive events.