Bird
Raised Fist0
Arduinoprogramming~10 mins

Interrupt-driven button handling in Arduino - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Interrupt-driven button handling
Setup Interrupt
↓
Wait for Button Press
↓
Interrupt Triggered?
No→Wait
Yes↓
Run ISR (Interrupt Service Routine)
↓
Handle Button Press
↓
Return to Main Loop
The program sets up an interrupt for the button pin, waits for a press, then runs a special function (ISR) immediately when pressed, handling the event quickly before returning to normal.
Execution Sample
Arduino
volatile bool buttonPressed = false;

void setup() {
  pinMode(2, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), buttonISR, FALLING);
}

void buttonISR() {
  buttonPressed = true;
}

void loop() {
  if (buttonPressed) {
    // Handle button press event
    buttonPressed = false;
  }
}
This code sets up an interrupt on pin 2 to detect button presses and sets a flag when pressed.
Execution Table
StepEventInterrupt Triggered?ISR Called?buttonPressed ValueMain Loop Action
1Program startsNoNofalseSetup pins and interrupt
2Waiting for button pressNoNofalseIdle or other tasks
3Button pressed (pin 2 FALLING)YesYestrueISR sets buttonPressed to true
4Return to main loopNoNotrueMain loop detects buttonPressed true, handles event
5ButtonPressed flag resetNoNofalseMain loop resets buttonPressed after handling
6Waiting for next pressNoNofalseIdle or other tasks
ExitProgram runs continuouslyNoNofalse or trueLoop continues waiting for interrupts
💡 Program runs indefinitely, responding to button presses via interrupts.
Variable Tracker
VariableStartAfter ISR CallAfter Main Loop HandlingFinal
buttonPressedfalsetruefalsefalse
Key Moments - 3 Insights
Why does buttonPressed change to true immediately when the button is pressed?
Because the interrupt triggers the ISR right away, setting buttonPressed to true as shown in step 3 of the execution_table.
Why do we use 'volatile' for buttonPressed?
Because buttonPressed is changed inside an ISR and read in the main loop, 'volatile' tells the compiler not to optimize it away, ensuring correct updates as seen in variable_tracker.
What happens if we don't reset buttonPressed after handling?
The main loop will think the button is still pressed and may repeatedly handle the event, as shown in step 4 and 5 where resetting is necessary.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, what is the value of buttonPressed right after the ISR is called?
Afalse
Btrue
Cundefined
Dnull
💡 Hint
Check row 3 in the execution_table where ISR sets buttonPressed to true.
At which step does the main loop reset buttonPressed to false?
AStep 2
BStep 3
CStep 5
DStep 4
💡 Hint
Look at the Main Loop Action column in step 5 of the execution_table.
If we remove 'volatile' from buttonPressed, what might happen?
AbuttonPressed might not update correctly in main loop
BButton won't trigger interrupt
CISR won't run
DProgram will crash
💡 Hint
Refer to key_moments about why 'volatile' is needed for variables changed in ISR.
Concept Snapshot
Interrupt-driven button handling:
- Use attachInterrupt(pin, ISR, mode) to detect button presses.
- ISR runs immediately on event, sets a flag.
- Use 'volatile' for variables shared with ISR.
- Main loop checks flag and handles event.
- Reset flag after handling to avoid repeated triggers.
Full Transcript
This example shows how Arduino uses interrupts to handle button presses efficiently. The program sets up an interrupt on pin 2 to detect when the button is pressed (falling edge). When pressed, the interrupt triggers an Interrupt Service Routine (ISR) that sets a flag variable 'buttonPressed' to true immediately. The main loop then checks this flag to perform actions and resets it after handling. The 'volatile' keyword is important to ensure the variable updates correctly between ISR and main code. This method allows quick response to button presses without constantly checking the button state in the main loop.

Practice

(1/5)
1. What is the main advantage of using interrupts for button handling on an Arduino?
easy
A. The Arduino can react immediately when the button is pressed without waiting.
B. It makes the button press slower but more reliable.
C. It allows the button to be pressed multiple times at once.
D. It disables other parts of the program while the button is pressed.

Solution

  1. Step 1: Understand what interrupts do

    Interrupts pause the main program to run a special function immediately when an event happens, like a button press.
  2. Step 2: Compare interrupt behavior to normal checking

    Without interrupts, the program must keep checking the button, which can delay response. Interrupts react instantly.
  3. Final Answer:

    The Arduino can react immediately when the button is pressed without waiting. -> Option A
  4. Quick Check:

    Interrupts = Immediate reaction [OK]
Hint: Interrupts react instantly, no waiting needed [OK]
Common Mistakes:
  • Thinking interrupts slow down button response
  • Believing interrupts disable other code permanently
  • Confusing interrupts with polling multiple presses
2. Which of the following is the correct syntax to attach an interrupt to pin 2 that calls the function buttonPressed on a FALLING edge?
easy
A. attachInterrupt(digitalPinToInterrupt(2), buttonPressed, FALLING);
B. attachInterrupt(2, buttonPressed, RISING);
C. attachInterrupt(buttonPressed, 2, FALLING);
D. attachInterrupt(2, FALLING, buttonPressed);

Solution

  1. Step 1: Recall attachInterrupt syntax

    The correct syntax is attachInterrupt(digitalPinToInterrupt(pin), ISR_function, mode).
  2. Step 2: Match parameters to the question

    Pin is 2, function is buttonPressed, mode is FALLING edge.
  3. Final Answer:

    attachInterrupt(digitalPinToInterrupt(2), buttonPressed, FALLING); -> Option A
  4. Quick Check:

    attachInterrupt(pin, function, mode) = attachInterrupt(digitalPinToInterrupt(2), buttonPressed, FALLING); [OK]
Hint: Use digitalPinToInterrupt(pin) for correct pin number [OK]
Common Mistakes:
  • Swapping function and pin arguments
  • Using pin number directly without digitalPinToInterrupt
  • Mixing up trigger modes like RISING and FALLING
3. What will be the output on the serial monitor after pressing the button once in this code?
volatile bool pressed = false;

void setup() {
  Serial.begin(9600);
  pinMode(2, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), buttonISR, FALLING);
}

void loop() {
  if (pressed) {
    Serial.println("Button pressed!");
    pressed = false;
  }
}

void buttonISR() {
  pressed = true;
}
medium
A. Compilation error due to volatile variable
B. Button pressed! (printed repeatedly forever)
C. No output at all
D. Button pressed! (printed once)

Solution

  1. Step 1: Understand ISR and flag usage

    The ISR sets the volatile flag 'pressed' to true when the button is pressed.
  2. Step 2: Check loop behavior

    The loop prints "Button pressed!" once when 'pressed' is true, then resets it to false, so it prints only once per press.
  3. Final Answer:

    Button pressed! (printed once) -> Option D
  4. Quick Check:

    ISR sets flag, loop prints once [OK]
Hint: ISR sets flag; loop prints once per press [OK]
Common Mistakes:
  • Thinking the message prints repeatedly without reset
  • Assuming volatile causes errors
  • Ignoring that flag resets after printing
4. Identify the error in this interrupt-driven button code:
volatile int count = 0;

void setup() {
  Serial.begin(9600);
  pinMode(3, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(3), countPresses, FALLING);
}

void loop() {
  Serial.println(count);
  delay(1000);
}

void countPresses() {
  count++;
}
medium
A. Using delay() in loop causes missed interrupts
B. Modifying a multi-byte variable without disabling interrupts
C. Incrementing a non-volatile variable in ISR
D. attachInterrupt() called with wrong pin number

Solution

  1. Step 1: Check variable type and ISR safety

    'count' is volatile int (multi-byte). Incrementing it in ISR and reading in loop can cause inconsistent values.
  2. Step 2: Understand atomicity issue

    Incrementing multi-byte variables is not atomic; main code reading 'count' may see partial updates causing errors.
  3. Final Answer:

    Modifying a multi-byte variable without disabling interrupts -> Option B
  4. Quick Check:

    Multi-byte variable access must be atomic [OK]
Hint: Use atomic operations or disable interrupts for multi-byte vars [OK]
Common Mistakes:
  • Ignoring atomicity of multi-byte variables
  • Thinking delay() blocks interrupts
  • Assuming attachInterrupt pin is wrong without checking
5. You want to count how many times a button connected to pin 4 is pressed, but only if the button is pressed and held for at least 2 seconds. Which approach best uses interrupts to achieve this?
hard
A. Poll the button state in loop without interrupts and count presses.
B. Use attachInterrupt on RISING edge to increment count immediately on press.
C. Use attachInterrupt on FALLING edge to start a timer, then check duration in loop before incrementing count.
D. Use attachInterrupt on CHANGE edge and increment count inside ISR.

Solution

  1. Step 1: Understand requirement for press duration

    Counting only if pressed for 2 seconds means timing the press length, not just detecting press.
  2. Step 2: Use interrupt to detect press start and timer in loop

    Interrupt on FALLING edge detects press start; loop checks if button held 2 seconds before counting.
  3. Final Answer:

    Use attachInterrupt on FALLING edge to start a timer, then check duration in loop before incrementing count. -> Option C
  4. Quick Check:

    Interrupt detects press start; loop checks hold time [OK]
Hint: Interrupt starts timer; loop checks hold duration [OK]
Common Mistakes:
  • Incrementing count immediately without timing
  • Using CHANGE edge causing multiple triggers
  • Polling without interrupts misses instant detection
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard