Expert · Embedded C, system calls and careers · topic 57 of 60 · 25 min
Embedded patterns: interrupts, timing and constraints
Explanation
The super loop
int main(void) {
hardware_init();
for (;;) {
read_sensors();
update_state_machine();
update_outputs();
}
}Interrupts
An interrupt is a hardware signal (a byte arrived on the UART, a timer expired, a button was pressed) that makes the CPU pause the current code, run a special function called an interrupt service routine (ISR), and then resume exactly where it was. Interrupts let the device react within microseconds without constantly polling.
static volatile uint32_t ticks; /* shared with the ISR: volatile */
static volatile uint8_t button_pressed;
void SysTick_Handler(void) { /* called by hardware every 1 ms (name from the vendor) */
ticks++;
}
void EXTI0_IRQHandler(void) { /* button interrupt */
button_pressed = 1; /* just record it; do the work in the main loop */
/* clear the interrupt flag here, as the reference manual requires */
}
int main(void) {
for (;;) {
if (button_pressed) {
button_pressed = 0;
start_wash_cycle(); /* slow work happens outside the ISR */
}
}
}Timing without blocking
uint32_t last = 0;
for (;;) {
if (ticks - last >= 500) { /* every 500 ms, without stopping everything else */
last = ticks;
toggle_led();
}
poll_uart(); /* the loop keeps serving other jobs */
}Debouncing a button
A mechanical button "bounces": for a few milliseconds after pressing, its contact opens and closes many times, which the MCU sees as several presses. Debouncing means accepting a new state only after it has been stable for, say, 20 ms (in software) or adding a small RC filter (in hardware).
Constraints that shape embedded C
- Little RAM: avoid big local arrays (small stacks) and often avoid malloc entirely, because fragmentation over months of uptime can cause failure. Allocate statically at start-up.
- Real-time deadlines: an airbag controller or a motor driver must respond within microseconds or milliseconds; code paths must have predictable timing.
- Reliability: devices run for years without restarts; watchdog timers reset the MCU if the main loop ever hangs.
- Safety and standards: automotive code follows MISRA C and processes like ISO 26262; AUTOSAR provides a standard software architecture for car ECUs.
- RTOSes such as FreeRTOS and Zephyr add tasks, queues and timers when a super loop becomes too complex.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Embedded patterns: interrupts, timing and constraints · 1/6
In this lesson you will learn how firmware is structured.
Prefer a video by a teacher? Find free videos on “embedded c interrupts isr volatile super loop debounce tutorial” on YouTube ↗
In real life: A washing machine controller
A washing machine's controller runs a state machine (fill, wash, rinse, spin) in its main loop. A timer interrupt keeps time, a door-sensor interrupt stops the drum immediately if the door opens, and the motor speed is updated every 10 ms. No malloc is used; all buffers are static, and a watchdog resets the board if the loop ever stops.
typedef enum { IDLE, FILL, WASH, RINSE, SPIN, DONE } State;
static State state = IDLE;
void update_state_machine(void) {
switch (state) {
case FILL: if (water_level() >= TARGET_LEVEL) { valve_close(); state = WASH; } break;
case WASH: if (elapsed_ms() > WASH_MS) state = RINSE; break;
/* … */
default: break;
}
}Practice (0/3 done)
What should an interrupt service routine usually do?
The same software debounce algorithm in JavaScript, which runs here: write debounce(samples, stableCount) where samples is an array of raw button readings (0 or 1) taken every millisecond. The debounced state starts at samples[0] and changes only after the raw reading has differed from the current state for stableCount consecutive samples. Return the number of debounced 0→1 presses.
Design (on paper or in C on a PC) the firmware for a cold-storage alarm: a timer tick every 1 ms, a temperature sensor read every 1 s, an alarm buzzer that beeps if the temperature is above 8 °C for more than 5 minutes, and a button to silence it. Show the state machine, which parts run in ISRs and which in the main loop, and which variables are volatile.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- C on Linux: files and processes with system callsEmbedded C, system calls and careers · same module
- C interview questionsEmbedded C, system calls and careers · same module
- Timers: running code laterFrontend Web Development · JavaScript in the browser: DOM and events
- Memoization, debounce and throttleJavaScript Programming (language in depth) · Functional patterns and testing
- Design project: an online storeSQL and Databases · Schema design and normalisation
- CREATE TABLE and constraintsSQL and Databases · Databases and the relational model
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
Why do many embedded projects avoid malloc after start-up?
Answer: Fragmentation and unpredictable failures over long uptimes
Static allocation is predictable.
What does a watchdog timer do?
Answer: Resets the MCU if the software stops "kicking" it (for example after a hang)
A safety net for hangs.
What is button bounce?
Answer: Rapid open/close transitions for a few milliseconds after pressing
Debounce in software or hardware.
Which is a real-time operating system often used on microcontrollers?
Answer: FreeRTOS
Zephyr is another.
Which language is a natural next step after C for embedded and systems work?Related
Does volatile make a variable safe to share between threads?Related
Answer: No: it only prevents the compiler from optimising away accesses
Use atomics or locks for threads.
From Embedded C basics
How do you stop a timer started with const id = setInterval(tick, 1000)?Related
Answer: clearInterval(id)
Pass the id that setInterval returned to clearInterval.
In debounce, what does clearTimeout(timer) do on each call?Related
Answer: Cancels the previously scheduled call
Each new call cancels the waiting one and restarts the wait.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 3 more topics in “Embedded C, system calls and careers” before its exam: C on Linux: files and processes with system calls, C interview questions, Projects and careers with C.
- Module 12 exam: Embedded C, system calls and careers · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
- 60 topics left in the course before the final exam.