Though the previous few articles, I have explained some theories required for embedded projects, which include three longer articles on Interrupt – What is Interrupt, How Interrupt Works and Understanding Arduino Interrupts. If you have not read those articles and are not sure what I am talking about, then kindly read the three articles after testing the code in this guide.
Our target of this guide is to blink the LED and beep every 1 second with pauses upon button press. That means, our wish is when we upload the sketch to Arduino UNO, it will start to blink the LED and make a ko ko buzzer sound. When the ko ko buzzer sound will disturb you, pressing the push button once should instantly stop the thing. Again after a 10-second gap, the sketch will blink the LED and make a ko ko buzzer sound.
The thing sounds very easy. But unless you know the theories, I will show you that the thing will not become perfect. Improper programming can make the physical buttons of electronic gadgets not work correctly.
---
Interrupt is analogous to interfering with a human doing something important. Suppose you are reading this webpage and your cat is trying to grab your attention or Amazon delivery is ringing the doorbell. Their action will be interrupted in that case. If there are a lot of delivery men ringing the doorbell and you have a lot of cats, then your main action will become erratic.
For this project, you need:
- Arduino UNO R3 development board
- One Breadboard
- Few jumpers
- One LED
- One Pushbutton
- One 220 Ohm resistor
- One 1K Ohm resistor
- One buzzer
- A computer with Arduino IDE installed
The connection will be like the below illustration:

The push button must be connected with digital pin 2 of Arduino UNO. Because the chart of this above-mentioned article tells us that Arduino UNO board provides attachInterrupt function on D2 and D3. So, our option to attach push button is either digital pin 2 or digital pin 3. I have connected the LED to digital pin 13 and the buzzer to pin 8.
Now, play this simulation:
It works exactly in the way we have wanted. This is the correct method and this is the sketch:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | // Define pin numbers const int ledPin = 13; // LED connected to digital pin 13 const int buzzerPin = 8; // Buzzer connected to digital pin 8 const int buttonPin = 2; // Push button connected to digital pin 2 volatile bool buttonPressed = false; // Flag to indicate button press void setup() { pinMode(ledPin, OUTPUT); pinMode(buzzerPin, OUTPUT); pinMode(buttonPin, INPUT_PULLUP); // Enable internal pull-up resistor for button pin attachInterrupt(digitalPinToInterrupt(buttonPin), buttonInterrupt, FALLING); // Attach interrupt to button pin } void loop() { if (!buttonPressed) { // Blink LED and beep every 1 second digitalWrite(ledPin, HIGH); // Turn on the LED tone(buzzerPin, 1000); // Play a 1kHz tone on the buzzer delay(500); // Wait for 0.5 second digitalWrite(ledPin, LOW); // Turn off the LED noTone(buzzerPin); // Stop the tone delay(500); // Wait for 0.5 second } else { // Pause for 10 seconds upon button press digitalWrite(ledPin, LOW); // Turn off the LED noTone(buzzerPin); // Stop the tone delay(10000); // Pause for 10 seconds buttonPressed = false; // Reset buttonPressed flag after pause } } // Interrupt service routine for button press void buttonInterrupt() { buttonPressed = true; // Set the buttonPressed flag } |
In the variable declarations, we define integer variables to store the PINs for the LED, buzzer, and push button. volatile bool buttonPressed is a flag to indicate whether the button has been pressed.
In the setup() function, we set the pinMode for the LED and buzzer pins as OUTPUT and the button pin as INPUT_PULLUP to enable the internal pull-up resistor. We attach an interrupt to the button pin using attachInterrupt() function, specifying the interrupt service routine (ISR) buttonInterrupt() to be called on the falling edge (when the button is pressed).
In the loop function, if buttonPressed is false, indicating no button press, weblink the LED and beep every 1 second. If buttonPressed is true, indicating a button press, we pause for 10 seconds. During the pause, the LED remains off, and the buzzer remains silent. After the pause, we reset buttonPressed to false to prepare for the next button press.
Button Interrupt Function: The buttonInterrupt() function is an interrupt service routine (ISR) called whenever the button is pressed. Inside this function, we set the buttonPressed flag to true to indicate that the button has been pressed.
If we add millis() in a wrong manner, then the below will be the sketch. Test the sketch, it will behave erratically. It is not wrong to use millis(), micros() or delay() within an interrupt routine. The previous usage was logically simple, that is why it worked.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | // Define pin numbers const int ledPin = 13; // LED connected to digital pin 13 const int buzzerPin = 8; // Buzzer connected to digital pin 8 const int buttonPin = 2; // Push button connected to digital pin 2 volatile bool buttonPressed = false; // Flag to indicate button press unsigned long previousMillis = 0; // Variable to store previous millis value const unsigned long interval = 1000; // Interval for LED blinking and beeping (1 second) const unsigned long pauseDuration = 10000; // Duration of pause upon button press (10 seconds) void setup() { pinMode(ledPin, OUTPUT); pinMode(buzzerPin, OUTPUT); pinMode(buttonPin, INPUT_PULLUP); // Enable internal pull-up resistor for button pin attachInterrupt(digitalPinToInterrupt(buttonPin), buttonInterrupt, FALLING); // Attach interrupt to button pin } void loop() { unsigned long currentMillis = millis(); // Get the current time if (!buttonPressed) { // Blink LED and beep every 1 second if (currentMillis - previousMillis >= interval) { previousMillis = currentMillis; // Save the last time we blinked the LED digitalWrite(ledPin, !digitalRead(ledPin)); // Toggle the LED state if (digitalRead(ledPin)) { tone(buzzerPin, 1000); // Start playing a tone } else { noTone(buzzerPin); // Stop playing the tone } } } else { // Pause for 10 seconds upon button press if (currentMillis - previousMillis >= pauseDuration) { previousMillis = currentMillis; // Reset the previousMillis buttonPressed = false; // Reset the buttonPressed flag } } } // Interrupt service routine for button press void buttonInterrupt() { buttonPressed = true; // Set the buttonPressed flag } |
Because Arduino’s programming language (that is an implementation of C++) has a lot of abstraction, it is not always possible to explain what is happening (by people who are not engineers related to this field).
Probably before an interrupt handler begins, AVR hardware disables interrupts. Interrupts are written in C code in the Arduino and are not capable of correctly handling multiple overlapping executions within the same handler (that is called reentrant). The correct method is to rewrite the library in C to solve your issues, but that approach will consume time.
If you think that you’ll avoid interrupting and write a simple code, that will also behave erratically.