Search code examples
arduinointerrupt

Problem with interruptions in Arduino Uno


I work with interruptions in Arduino UNO. In this project, I want to when the Door is opened the LED blink 10 times, and when the door is closed again, stop blinking the LED and exit the function. But in this code the LED only turn on and off once and it does not flash again. My other problem is that, when the door is opened or closed, sometimes the opened or closed word appears several times in the Series monitor.

const byte LED_Red = 13;
const byte DOOR_SENSOR = 2; // magnetic door sensor pin

volatile int SensorState = LOW; // 0 close - 1 open wwitch

void setup()
{
Serial.begin(9600);
pinMode(LED_Red, OUTPUT);
pinMode(DOOR_SENSOR, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(DOOR_SENSOR), DoAction, CHANGE);
}

void DoAction()
{
    SensorState = digitalRead(DOOR_SENSOR);
    if (SensorState == HIGH) {
    Serial.println("Opened");
    blinkLED(10, 500);
}
    else {
    Serial.println("Closed");
        }
}

void blinkLED(int repeats, int time)
{
    for (int i = 0; i < repeats; i++) {
        if (SensorState == HIGH) {
        digitalWrite(LED_Red, HIGH);
        delay(time);
        digitalWrite(LED_Red, LOW);
        delay(time);
    }
    else
        return;
}
}

void loop()
{
}

Solution

  • You can't simply put a delay() on an interrupt's function. You need to just set a flag when the door is opened and based on that start blinkLED inside the main loop.

    I also recommend you to use millis() function for an unblocking delay inside blinkLED function (e.g when you want to stop blinking while the door is closed).

    const byte LED_Red = 13;
    const byte DOOR_SENSOR = 2; // magnetic door sensor pin
    
    // flag to check door is opened
    volatile bool isOpened = false;
    
    //flag to check already blinked
    volatile bool isBlinked = false;
    
    void setup()
    {
        Serial.begin(9600);
        pinMode(LED_Red, OUTPUT);
        pinMode(DOOR_SENSOR, INPUT_PULLUP);
        attachInterrupt(digitalPinToInterrupt(DOOR_SENSOR), DoAction, CHANGE);
    }
    
    void DoAction()
    {
        if (digitalRead(DOOR_SENSOR) == HIGH)
        {
            //Serial.println("Opened");
            isOpened = true;
        }
        else
        {
            isOpened = false;
            isBlinked = false;
            //Serial.println("Closed");
        }
    }
    
    void blinkLED(int repeats, int time)
    {
        byte LEDState = LOW;
        unsigned long delay_start = millis();
        for (int i = 0; i < 2 * repeats; i++)
        {
            //Toggle LED state
            if (LEDState == HIGH)
                LEDState = LOW;
            else
                LEDState = HIGH;
            // set value
            digitalWrite(LED_Red, LEDState);
            // some unblocking delay
            while (millis() - delay_start < time)
            {
                // return if door is closed
                if (!isOpened)
                {
                    // turn off LED
                    digitalWrite(LED_Red, LOW);
                    return;
                }
            }
            delay_start = millis();
        }
        isBlinked = true;
    }
    
    void loop()
    {
        // Check isBlinked beacue don't want to blink again until door is closed
        if (isOpened && !isBlinked)
        {
            blinkLED(10, 500);
        }
    }