Interrupting a 4 hour ordeal.

Hey Guys
Im relatively new to Arduino and I got asked to build a machine that reacts on Pulses received.I am using the Arduino NANO.
Trick is when ever a pulse is received it gets locked into a piece of code roughly 4 hours until fully executed.
Now the 1 interrupt pin also serves as the pin that gets the pulse.
If the Pin gets the Pulse it switches on the long duration of code, my Problem comes when I need it to stop with whatever its doing immediately by PULSING it again from the same source onto the same Pin
that started the 4 hour code.

Is there some way that I can avoid using interrupts or what should I make the interrupt do to make the code that is busy executing prior to the interrupt to stop?

So basically if it gets a Pulse it starts but at any given time I want to be able to pulse it again and it should stop or "Break;" the code its busy with and just exit on the Same pin.
The reason Im asking is because I cant seem to use any functions inside an Interrupt with Delays in them and I have read why but now im clueless with ways to dodge this problem.

Thanks allot guys.
Ard

Not much can be said without seeing the code.

Thanks for the reply.
Well theres not to much to say about the code since its really simple code but here it is.

const int led = 13;
const int Op1 = 8;
const int Op2 = 9;
const int Op3 = 10;
const int Op4 = 11;

const int int1 = 2; //Interrupt 0;

int lState = LOW;
int buttonState = 0;
long previousMillis = 0;
long inter = 1000;
long UniTime = 10000; 
int StateCheck =0;


void setup()
  {
    // digital pins=output
    pinMode(led, OUTPUT);
    pinMode(Op1, OUTPUT);
    pinMode(Op2, OUTPUT);
    pinMode(Op3, OUTPUT);
    pinMode(Op4, OUTPUT);
    pinMode(int1, INPUT);
    //attachInterrupt(0, stop1. HIGH);
    
  }
  
  void loop()
    {
      buttonState = digitalRead(int1);
      
      
      if (buttonState == LOW)
        {
          
            StateCheck =1;
          digitalWrite(Op1, HIGH);   
          delay(UniTime);               
          digitalWrite(Op1, LOW);    
          delay(1000);               
        
          digitalWrite(Op2, HIGH);   
          delay(UniTime);               
          digitalWrite(Op2, LOW);    
          delay(1000);
        
          digitalWrite(Op3, HIGH);   
          delay(UniTime);               
          digitalWrite(Op3, LOW);    
          delay(1000);
        
          digitalWrite(Op4, HIGH);   
          delay(UniTime);               
          digitalWrite(Op4, LOW);    
          delay(1000);
          StateCheck = 0;
          
          
           
           
  }
  }

Is there some way that I can make the interrupt check values and then execute functions depending on the value?
Because I was hoping to maybe make the button itself an interrupt instead of using "if (digitalRead(xx)) etc" and take things from there.For instance when it gets an interrupt while no code is currently running it should switch to some functions BUT if the code is indeed currently active it should do something else like break out of the functions it was currently in.
The StateCheck is a remnant of my attempt to set up a system like this.
One other thing is.It would be really cool to save the function that it needs to breaks, Current stage.I know I can do that using switch statements and increments but first things first.

When you call delay(10000) the mcu sits there doing nothing for 10 seconds. By nothing I mean no other code is running for a whole 10 seconds.

Answer this: how much time passes between two subsequent digitalRead()s ? That's the problem.

You need to throw away all those delay() calls and switch to non-blocking, state-based code. Which is simpler than it sounds. Start with the blink without delay example.

I will most definitely check in to the "non-blocking, state-based code" but for now I need to finish this off because I only have about 2 days to do this.
So this is a little Trial and error code that I have written.

Please tell me what you think and WHY this doesn't work.

I have added these and changed the function in the interrupts name to Check().
It does seem to do the one set of Code but while that code is running and StateCheck = 1 it still doesnt seem to break out of the code when the pin is made LOW again.

void setup()
{
 attachInterrupt(0, Check, LOW);
}


 void loop()
    {
       
  
    
        unsigned long currentMillis = millis();
 
          if(currentMillis - previousMillis > interval) {
            // save the last time you blinked the LED 
            previousMillis = currentMillis;   
        
            // if the LED is off turn it on and vice-versa:
            if (ledState == LOW)
              ledState = HIGH;
            else
              ledState = LOW;
        
            // set the LED with the ledState of the variable:
            digitalWrite(led, ledState);
        }
      
    }

    void Check()
{
  if (StateCheck == 0)
    {
      RUNcycle();
    }
    else if(StateCheck == 1)
     {
       BREAKcycle();
     }
  
  
}

void RUNcycle()
  {
       StateCheck = 1;
          digitalWrite(Op1, HIGH);   
          delay(UniTime);               
          digitalWrite(Op1, LOW);    
          delay(1000);               
        
          digitalWrite(Op2, HIGH);   
          delay(UniTime);               
          digitalWrite(Op2, LOW);    
          delay(1000);
        
          digitalWrite(Op3, HIGH);   
          delay(UniTime);               
          digitalWrite(Op3, LOW);    
          delay(1000);
        
          digitalWrite(Op4, HIGH);   
          delay(UniTime);               
          digitalWrite(Op4, LOW);    
          delay(1000);
          StateCheck = 0;
          
  }
  
  void BREAKcycle()
    {
   
    }

This is not the whole code its just changes. void loop() now only shines a LED to show its working and then basically waiting for an interrupt it what I want it to do.

Thanks

You’ve still got delays in there.
They all need to go.

long previousMillis ==> unsigned long previousMillis

as millis() returns unsigned long ...

It doesn’t work because you still use delay()s. You can’t interrupt a delay() call.

Also, the interrupt routine should be very small, perhaps just set a flag that tells the main loop that the button was pressed. You should definitely not call delay() inside an ISR.
But the fact is you don’t need to use interrupts here, just structure your code as a set of states that gets executed when a certain amount of time has passed.

The following code compiles but I didn’t test it on real hardware:

#define ARY_LEN(a) (sizeof(a)/sizeof(a[0]))

//////////////////////////////////////////////
//          led blink section
//////////////////////////////////////////////

boolean isBlinkRunning = false;

unsigned long blink_prevMillis;
unsigned long blink_interval;
byte currPinState;

const unsigned long BLINK_LONG_DELAY = 10000;
const unsigned long BLINK_SHORT_DELAY = 1000;

struct pinState {
    byte pinNumber;
    byte pinState;
    unsigned long interval;
};

struct pinState pinStates[] = {
    {  8, HIGH, BLINK_LONG_DELAY  },
    {  8, LOW,  BLINK_SHORT_DELAY },
    {  9, HIGH, BLINK_LONG_DELAY  },
    {  9, LOW,  BLINK_SHORT_DELAY },
    // etc.
};

const byte NUM_PIN_STATES = ARY_LEN(pinStates);


// directly go to satate number 0
void resetPinState() {
    currPinState = 0;
    applyPinState(currPinState);
}


// turn off all leds
void resetPins() {
    for (int i = 0; i < NUM_PIN_STATES; i++) {
        digitalWrite(pinStates[i].pinNumber, LOW);
    }
}


void applyPinState(byte stateIndex) {
    digitalWrite(pinStates[stateIndex].pinNumber, pinStates[stateIndex].pinState);
    blink_interval = pinStates[stateIndex].interval;
}



//////////////////////////////////////////////
//          button section
//////////////////////////////////////////////

// let's suppose a pushbutton is connected to pin 4 and ground
// the button is active low (LOW when pressed)
byte btnPin = 4;
byte btnState = HIGH;
byte btnPrevState = HIGH;

unsigned long btn_prevMillis;
unsigned long btn_interval = 30;        // check the button every 30 ms


void btnPressed() {
    if (isBlinkRunning) {
        isBlinkRunning = false;
        resetPins();
        resetPinState();
    }
}


void btnReleased() {
}



//////////////////////////////////////////////
//          main
//////////////////////////////////////////////

void setup() {
    for (int i = 0; i < NUM_PIN_STATES; i++) {
        pinMode(pinStates[i].pinNumber, OUTPUT);
    }
    
    pinMode(btnPin, INPUT);
    digitalWrite(btnPin, HIGH);        // activate internal pullup

    resetPins();
    resetPinState();
}


void loop() {

    // button section
    if (millis() - btn_prevMillis >= btn_interval) {
        btnState = digitalRead(btnPin);

        if ((btnPrevState == HIGH) && (btnState == LOW)) {
            btnPressed();
        }
        else if ((btnPrevState == LOW) && (btnState == HIGH)) {
            btnReleased();
        }

        btnPrevState = btnState;
    }


    // blink section
    if (isBlinkRunning) {
        if (millis() - blink_prevMillis >= blink_interval) {
            blink_prevMillis = millis();

            currPinState++;
            if (currPinState >= NUM_PIN_STATES) {
                currPinState = 0;
            }

            applyPinState(currPinState);
        }
    }
}

Ok so…

I have revised the code.Sorry for messing everyone around but this should be pretty easy to read + its allot less code and it works…for now.

Obviously you guys would know the repercussions that I will have later on with the Code.For now I cant see what can possibly go wrong accept for me not being able to pulse the interrupt with my Hands and a wire quick enough.

const int l = 13;
const int Op1 = 8;
const int Op2 = 9;
const int Op3 = 10;
const int Op4 = 11;

const int in1 = 2; //Interrupt 0;
//const int in2 = 3; //Interrupt 1;
int ledState = LOW;
int buttonState =0;
long previousMillis = 0;
long interval = 1000;
long UniTime = 10; 
int StateCheck =0;


void setup()
  {
    // digital pins=output
    pinMode(l, OUTPUT);
    pinMode(Op1, OUTPUT);
    pinMode(Op2, OUTPUT);
    pinMode(Op3, OUTPUT);
    pinMode(Op4, OUTPUT);
    pinMode(in1, INPUT);
    attachInterrupt(0, Check, LOW);
    //attachInterrupt(1, startstop2, CHANGE};
  }
  
  void loop()
    {
        if (StateCheck == 1)
       {
          digitalWrite(zone1, HIGH);   
          StateCheckDelay(UniTime);               
          digitalWrite(zone1, LOW);    
          delay(1000);               
        
          digitalWrite(zone2, HIGH);   
          StateCheckDelay(UniTime);               
          digitalWrite(zone2, LOW);    
          delay(1000);
        
          digitalWrite(zone3, HIGH);   
          StateCheckDelay(UniTime);               
          digitalWrite(zone3, LOW);    
          delay(1000);
        
          digitalWrite(zone4, HIGH);   
          StateCheckDelay(UniTime);               
          digitalWrite(zone4, LOW);    
          delay(1000);
          StateCheck = 0;
       }  
}
  
    
    void Check()
{
  if (StateCheck == 0)
    {
      StateCheck = 1;
      digitalWrite(led, HIGH);
    }
    else if(StateCheck == 1)
     {
       StateCheck = 0;
       digitalWrite(led, LOW);
     }
}


 void StateCheckDelay(int x)
    {
      for (int i=0;i<x+1;i++)
      {
      if (StateCheck == 1)
        {delay(850);}
        else if(StateCheck == 0)
        {break;}
      }  
  }

Please note while typing this someone replied so will quickly read.
Thanks allot :slight_smile:

Thanks Tux.
Quite allot to absorb but will check it out quickly.

Please check the code that I have just pasted a while ago.Right after your reply post.

Appreciated.
Ard

I checked your code. I’m sorry, but there’s no way it can do what you want unless you delete all of the delay() calls. If you delay() for 1 second, nothing else will happen during that second. An interrupt won’t er… interrupt a delay() call.

If you're in a real hurry and need working code you can post a request in "gigs and collaborations" section. Otherwise, keep asking and learning :smiley:

An interrupt won't er... interrupt a delay() call.

It will interrupt it, but it won't break out of it prematurely.

Of course :slight_smile:

So what do I do if I cant use Delays though?
Must be something that needs to keep 1 port HIGH for almost an hour.

Use the technique in the blink without delay code example in the arduino IDE.
Then use the time freed up to look at the pin that starts or resets your code.

Ok so…
This is what I came up with since I cant use the Delays I really cant see another way.Please tell me how and why this might be problematic.
Improvements are welcome.

  int Seconds()
    {
      unsigned long time = millis();
      return (time*1000);
    }
  
 void milliDelayPROTO(int x)
    {
      unsigned long CurrentSeconds = Seconds();
      unsigned long t = Seconds();
        while (CurrentSeconds - t < x)
          {
            CurrentSeconds = Seconds();
          }
    }

That is no different than doing a delay. The processor is still blocked out in a loop during the delay.
What is wrong with the blink without delay?

You were on the right track originally.

ISR():
  flip a flag;

loop():
  if (flag) waste_4hours();

waste_4hours():
  unsigned char start_time=millis();
  while (millis() - start_time < DURATION_4HR) {
    if (!flag) break;
    do_your_thing(); //execute user application
  }
}

Essentially, it enters waste_4hours() once the flag is set (the first pulse). It exits waste_4hours() if the time is up (DURATION_4H has expired) or flag is cleared - the 2nd pulse has arrived, earlier of the two.

You can plug your code pieces there.

dhenry:
You were on the right track originally.

No. Just ... no.

All you need is to poll the switch to determine the start and end of your activity, use a global variable to record whether the activity is currently in progress, and use the approach demonstrated in 'blink without delay' to carry out whatever timed activities need to happen during those four hours. It doesn't need interrupts, and it shouldn't use delays.