ROBOTECA FREE SAMPLE
Dashboard

A free lesson from Embedded Systems & Electronics: the whole module, nothing cut short.

LESSON · Embedded Systems

Interrupts & timers

Turn 1 30 min LESSON

ALearning Material

Naively, to react to an event you poll: loop forever asking "is the button pressed yet?" This wastes CPU and can miss fast events while you're busy elsewhere.

The naive way to react to an event is to poll. Loop forever asking 'is it pressed yet?', which wastes the CPU and can miss a fast event while you're busy doing something else. Interrupts invert that relationship: you tell the hardware 'when event X happens, immediately pause everything and run this small function, then resume', so the CPU does useful work (or sleeps) until the event actually occurs.

‍​‌‌​​‌‌​​‌‌‌​​‌​​‌‌​​‌​‌​‌‌​​‌​‌​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌​​​​‌​‌‌​‌‌​‌​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​‌​‌‍That power comes with strict rules, and getting them wrong produces baffling bugs. An interrupt service routine must be short (flag it and get out) because the rest of the system is frozen while it runs. And any variable shared between the ISR and your main code must be volatile, or the compiler may cache a stale copy in a register and never notice the ISR changed it. Interrupts, short ISRs, and volatile are the trio that make event-driven firmware both responsive and correct.

Interrupts invert this. You tell the hardware "when event X happens, immediately pause whatever you're doing and run this small function (an ISR, Interrupt Service Routine), then resume." The CPU does useful work (or sleeps) until the event actually occurs.

volatile bool pressed = false;     // shared with the ISR -> must be volatile

void buttonISR() {                 // runs the instant the pin changes
    pressed = true;                // do the minimum; flag and exit
}

void setup() {
    attachInterrupt(BUTTON_PIN, buttonISR, FALLING);  // trigger on HIGH->LOW
}

void loop() {
    if (pressed) {                 // main code reacts when convenient
        pressed = false;
        toggleLED();
    }
}

‍​‌‌​​‌‌​​‌‌‌​​‌​​‌‌​​‌​‌​‌‌​​‌​‌​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌​​​​‌​‌‌​‌‌​‌​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​‌​‌‍ISR rules (critical): - Keep ISRs short. Set a flag, copy a value, exit. No delays, no heavy work. The rest of the system is frozen while the ISR runs. - Shared variables must be volatile. It tells the compiler the value can change outside normal flow (in the ISR), so it always re-reads it from memory instead of caching it in a register.

Timers are hardware counters that tick from a clock. They enable precise timing without blocking: - Generate a periodic interrupt (e.g. "interrupt me every 1 ms") → the basis of fixed-rate control loops on bare metal. - Produce PWM (Pulse-Width Modulation). A square wave whose duty cycle (% of time HIGH) sets average power. 25% duty ≈ 25% brightness/speed. This is how MCUs dim LEDs and drive motors.

delay() vs timers. delay(1000) blocks the whole CPU for a second, nothing else runs. Real embedded code uses timer interrupts or a non-blocking "check the clock" pattern (millis()), so multiple things happen "at once."

Why it exists. A robot must react the instant something happens (a limit switch, an encoder edge, a deadline) while still doing other work. Polling wastes the CPU and misses fast events; interrupts and timers are how bare-metal code reacts immediately and keeps precise time without blocking.

‍​‌‌​​‌‌​​‌‌‌​​‌​​‌‌​​‌​‌​‌‌​​‌​‌​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌​​​​‌​‌‌​‌‌​‌​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​‌​‌‍Mental model. Polling is repeatedly opening the oven to check the food. An interrupt is a timer bell that calls you the instant it's done, so you can do other chores meanwhile. A PWM duty cycle is like rapidly flicking a light switch. Flick it on 30% of the time and it looks ~30% as bright.

Common misunderstandings.

  • "Do the real work inside the ISR." Keep ISRs tiny. Set a flag and exit; the whole system is frozen while an ISR runs.
  • "A normal variable shared with an ISR is fine." It must be volatile, or the compiler may cache a stale copy and never see the ISR's change.
  • "delay(1000) is a harmless pause." It blocks the entire CPU for a second. Use timers / millis() so other things keep running.

Connections. The "flag in the ISR, react in the loop" pattern is the seed of RTOS deferred-interrupt processing (Turn 2); volatile is the bare-metal cousin of C++'s std::atomic (concurrency); and timer-driven periodic interrupts are the fixed-rate loop from Python Turn 1. PWM duty cycle is how a PID output drives a real motor.

‍​‌‌​​‌‌​​‌‌‌​​‌​​‌‌​​‌​‌​‌‌​​‌​‌​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌​​​​‌​‌‌​‌‌​‌​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​‌​‌‍BImmediate Active Recall

QUERY

Polling vs interrupt. What's the core difference?

REVEAL
ANSWER

Polling repeatedly checks for an event, wasting CPU and risking misses; an interrupt lets hardware call your code the moment the event happens, so the CPU is free until then.

Did you recall it?
QUERY

Two golden rules for writing an ISR?

REVEAL
ANSWER

Keep it as short as possible (flag-and-exit, no delays/heavy work), and mark any variable shared with the main code as volatile‍​‌‌​​‌‌​​‌‌‌​​‌​​‌‌​​‌​‌​‌‌​​‌​‌​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌​​​​‌​‌‌​‌‌​‌​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​‌​‌‍.

Did you recall it?
QUERY

What is PWM duty cycle and what does it control?

REVEAL
ANSWER

The percentage of each period the signal is HIGH; it sets the average power delivered, e.g. LED brightness or motor speed.

Did you recall it?
‍​‌‌​​‌‌​​‌‌‌​​‌​​‌‌​​‌​‌​‌‌​​‌​‌​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌​​​​‌​‌‌​‌‌​‌​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​‌​‌‍QUERY

Why is delay(1000) bad in responsive embedded code?

REVEAL
ANSWER

It blocks the CPU entirely for the duration, so nothing else (other tasks, checks) can run; use timer interrupts / non-blocking millis() patterns instead.

Did you recall it?

CConceptual Questions

Answer each in your own words in the box, then reveal the model answer to compare. These ask why, not how, and your answers are saved.

PROMPT

Why are interrupts better than polling for reacting to a button or sensor event?

‍​‌‌​​‌‌​​‌‌‌​​‌​​‌‌​​‌​‌​‌‌​​‌​‌​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌​​​​‌​‌‌​‌‌​‌​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​‌​‌‍REVEAL MODEL ANSWER
MODEL ANSWER

Polling loops repeatedly asking 'has it happened yet?', burning CPU cycles and potentially missing a brief event while the code is busy elsewhere. An interrupt lets the CPU do other work or sleep, and the hardware diverts to the ISR the instant the event occurs, so it never misses the edge and wastes no cycles waiting. Efficiency plus guaranteed capture.

Compared to the model answer - did you get it?
PROMPT

Why must an ISR be kept short, flag and exit?

REVEAL MODEL ANSWER
‍​‌‌​​‌‌​​‌‌‌​​‌​​‌‌​​‌​‌​‌‌​​‌​‌​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌​​​​‌​‌‌​‌‌​‌​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​‌​‌‍MODEL ANSWER

While the ISR runs, the rest of the system is effectively frozen: the main code is paused and other interrupts may be blocked. Doing heavy work or calling delays inside an ISR starves everything else and can cause missed events or sluggish response. The correct pattern is to do the minimum (set a flag or copy a value) and exit, handling the real work back in the main loop.

Compared to the model answer - did you get it?
PROMPT

Why must a variable shared between an ISR and main code be declared volatile?

REVEAL MODEL ANSWER
‍​‌‌​​‌‌​​‌‌‌​​‌​​‌‌​​‌​‌​‌‌​​‌​‌​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌​​​​‌​‌‌​‌‌​‌​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​‌​‌‍MODEL ANSWER

volatile tells the compiler the value can change outside the normal program flow (inside the ISR), so it must re-read it from memory every time instead of caching it in a register. Without volatile, the main loop may keep using a stale cached copy and never see the ISR's update. A classic 'it never reacts' bug.

Compared to the model answer - did you get it?

DPractice Problems

P1 (easy). You need an LED to blink while also reading a sensor continuously. Should you use delay() or a timer/millis() approach? Why?

P2 (medium). A flag set in an ISR is sometimes ignored by the main loop even though the interrupt fired. What keyword was likely forgotten, and why does it matter?

‍​‌‌​​‌‌​​‌‌‌​​‌​​‌‌​​‌​‌​‌‌​​‌​‌​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌​​​​‌​‌‌​‌‌​‌​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​‌​‌‍P3 (harder). You want a motor at ~40% speed via PWM at 1 kHz. Conceptually, what duty cycle, and what does raising the frequency (not duty) change?

Solutionsclick to reveal

P1. A timer/millis() non-blocking approach. delay() would freeze the CPU during each blink interval, halting sensor reads; checking elapsed time lets both run "simultaneously."

P1Compared to this solution - did you get it right?

‍​‌‌​​‌‌​​‌‌‌​​‌​​‌‌​​‌​‌​‌‌​​‌​‌​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌​​​​‌​‌‌​‌‌​‌​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​‌​‌‍P2. volatile. Without it the compiler may cache the variable in a register and never see the ISR's update, so the main loop reads a stale value. volatile forces a fresh read from memory each time.

P2Compared to this solution - did you get it right?

P3. ~40% duty cycle (HIGH 40% of each period). Raising the frequency keeps the same average power but switches faster. Reducing audible whine/flicker and affecting motor smoothness/heating, without changing speed (duty does that).

‍​‌‌​​‌‌​​‌‌‌​​‌​​‌‌​​‌​‌​‌‌​​‌​‌​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌​​​​‌​‌‌​‌‌​‌​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​‌​‌‍P3Compared to this solution - did you get it right?

EFeynman Exercise

Explain interrupts to a beginner with the oven-bell analogy: why waiting by the oven (polling) wastes your time, and how a bell (interrupt) frees you. Then explain PWM by describing how flicking a switch on and off very fast can make a light look half as bright, and what "duty cycle" names in that picture.

REVEAL MODEL ANSWER
MODEL ANSWER

Polling is like getting up to check the front door every ten seconds in case someone's there. You get nothing else done and might still miss a quick knock. An interrupt is a doorbell: you go about your work and only stop, briefly, the instant it rings, then carry on. The rule is to answer the bell fast and get back to work, if you stand at the door chatting (a long ISR), the phone rings, the kettle boils, and everything else in the house grinds to a halt while you're stuck there.

‍​‌‌​​‌‌​​‌‌‌​​‌​​‌‌​​‌​‌​‌‌​​‌​‌​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌​​​​‌​‌‌​‌‌​‌​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​‌​‌‍Compared to the model answer - did you get it?

FError Analysis Framework

  • Heavy ISRs. Why: doing work in the ISR. Recognise: system stutters, missed interrupts. Avoid: flag-and-exit; process in main loop.
  • Missing volatile. Why: unaware of compiler caching. Recognise: main loop ignores ISR updates. Avoid: volatile on all ISR-shared data.
  • Blocking with delay(). Why: simplicity. Recognise: unresponsive system. Avoid: timers / millis() non-blocking patterns.
  • Confusing duty and frequency. Why: both "PWM knobs." Recognise: changing frequency to set speed. Avoid: duty = power, frequency = switching rate.

‍​‌‌​​‌‌​​‌‌‌​​‌​​‌‌​​‌​‌​‌‌​​‌​‌​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌​​​​‌​‌‌​‌‌​‌​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​‌​‌‍GMini Challenge

Your main loop does while(!pressed){} where pressed is set in a button ISR, but it never exits even when you press the button. What keyword is missing, and why does adding it fix the problem?

REVEAL MODEL ANSWER
MODEL ANSWER

pressed must be declared volatile. Without it, the compiler is allowed to read pressed once into a register at the top of the loop and reuse that cached value forever, so it never sees the ISR write the new value to memory. The loop spins on a stale copy. Marking it volatile forces a fresh read from memory on every check, so the loop sees the ISR's update and exits when the button is pressed.

‍​‌‌​​‌‌​​‌‌‌​​‌​​‌‌​​‌​‌​‌‌​​‌​‌​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌​​​​‌​‌‌​‌‌​‌​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​‌​‌‍Compared to the model answer - did you get it?

Quiz Check

A quick auto-graded check, separate from the recall cards above. Your score is pooled with the recall cards into this module's Mastery score, and completing this lesson requires the quiz submitted with pooled mastery at 80% or above.

QUIZAuto-graded check · feeds your mastery score
  1. The cardinal rule for an interrupt service routine (ISR) is:

  2. A variable shared between an ISR and the main loop must be:

  3. A 25% PWM duty cycle delivers about:

  4. delay(1000) in real embedded code is a problem because:

This is a free sample

Progress and the spaced-repetition reviews are part of the course. The full track continues from here.