Harware Interrupt gets repeated by itself

Hi everyone,

Im using Arduino Uno.

I am trying open and close a valve with a delay in between. I want to do this when a switch is pressed.

What I have done is to use a hardware Interrupt. It gets triggured as expected by using "attachInterrupt" command.

The problem starts when I introduce a code delay(1000);. for some unknown reason, the function is called repeatedly as soon as the code has a delay in it.. full code given below.

I am expecting the function "startaction" to run once and open/close valve once. but when I have a delay in it, valve gets repeatedly open and closed!!!

can someone help the mistake and how to correct it!!!

int potPin1 = 0;    // select the input pin for the potentiometer
int ValvePin = 8;   // select the pin for the Valve
int TriggerPin = 2; // Swith trigger

int p1, p2, p3, p4;  // raw Values of the POT's
int d1, d2, d3, d4;  // Delay values of each POT's
int d1m, d2m, d3m, d4m;   //Max delay corresponding full scale of POT (1023)




void setup() {
  
  //Setting Pin Modes
  pinMode(potPin1, INPUT);  // declare the PotPin as an INPUT
  pinMode(ValvePin, OUTPUT);  // declare the ValvePin as an OUTPUT
  
  Serial.begin(9600);
  
  
  d1m = 500;
  attachInterrupt(digitalPinToInterrupt(TriggerPin), StartAction, RISING);  //D2 as SWITCH INTURRUPT
  
  
  
}

void loop() {
  
  
}



void StartAction() {

  
  delay(10000);
  
  Serial.println("1");
  
  float pm = 1023.0;
  
  d1 = (analogRead(potPin1) / pm) * d1m ;

  Serial.println(d1);
  
  
  
  //STARTING LOOP ****************************
  
  //first drop
  digitalWrite(ValvePin, HIGH);  // turn the Valve on
  delay(d1*5);
  digitalWrite(ValvePin, LOW);  // turn the Valve off
  // first drop complete
  
  
}

Don’t do delays in interrupt context.
Don’t do serial I/O in interrupt context.

TheMemberFormerlyKnownAsAWOL:
Don't do delays in interrupt context.
Don't do serial I/O in interrupt context.

Don't use interrupts to detect human-speed events (i.e. push button switches).
Don't use interrupts if you're a newbie.
Don't use interrupts for this project.

thank you both.. i have done it using / digitalRead and it works.
can you point to the details or links as to why it was not working?

Does the reference page for attachInterrupt not mention stuff like this?
It should, if it doesn’t.

gfvalvo:
Don't use interrupts to detect human-speed events (i.e. push button switches).

So, it is better to waste time to look again and again by opening the entry door that the guest has arrived.

It is no good for the host to make an interrupt arrangement by installing a calling bell and an outside button so that when the guest arrives, he can inform the host about his arrival by pressing the button.

Why should one spend time by polling an event that may occur once a while? Let the event interrupt the host when it is ready.

Whether to use interrupt or not that depends on the application.

Using delay(), or various Serial actions cannot be used in an interrupt routine, as they wait
for other interrupts, which will never happen in an interrupt context, so the system locks up.

An interrupt routine is purely for servicing urgent hardware events, and its purpose is to get
prompt hardware response for the hardware in question.

Any global/static variables used by an interrupt routine need to be declared volatile so the
compiler doesn't optimize them incorrectly too.

If you are going to use interrupts to trigger an action and want a later action after a delay,
you need to use a timer and timer-interrupt to handle the second action. First interrupt
does the first action and programs the timer. Timer interrupt does the second action. No
calls to delay, no busy-waiting.

This is tricky stuff for a beginner, as you need to understand more about the system and the
subtleties to avoid various pitfalls.

MarkT:
Using delay(), or various Serial actions cannot be used in an interrupt routine, as they wait
for other interrupts, which will never happen in an interrupt context, so the system locks up.

An interrupt routine is purely for servicing urgent hardware events, and its purpose is to get
prompt hardware response for the hardware in question.

Any global/static variables used by an interrupt routine need to be declared volatile so the
compiler doesn't optimize them incorrectly too.

If you are going to use interrupts to trigger an action and want a later action after a delay,
you need to use a timer and timer-interrupt to handle the second action. First interrupt
does the first action and programs the timer. Timer interrupt does the second action. No
calls to delay, no busy-waiting.

This is tricky stuff for a beginner, as you need to understand more about the system and the
subtleties to avoid various pitfalls.

Thank you Mark.

I like to do complicated stuff although bit of beginner :slight_smile:

I have done a system for doing an automated focus stcking (Tips by Joe (Proe, Excel...)). It include integration of keybord, display, stepper and triggering the camera. So i have the confidence to pull things off although I am a mechanical engineer with limited electronics knowledge. I am able to do it thanks to the helpful people like in this forum. so thank you guys!!!

In this project, I initially tried timer interrupts but it was betting bit complicated. I wanted to develop this code to do a series of events followed by the switch trigger like multiple servo actions and camera actions. Since that was getting complicated I tried hardware interrupt.. initial trials were ok until i got stuck here. anyway, as suggested by you guys, I have avoided the interrupt.

for me, more than the project, it is an opportunity to learn new stuff...

So big thanks once again.. Once I complete the project, I will update here...

friends, gurus,

I have completed by project. I am able to trigger the valve to release two drops and then trigger camera, all based on delays set by the potentiometers. Thanks to the setup, I am able to capture some amazing moments. setup and a photo is attached. thanks.

https://www.instagram.com/p/B28rDZwlUCP/?utm_source=ig_web_copy_link

Next: the repeatability of the pot is not quite as I want. evenif i do not change the pot, the values fluctuate a bit and that make a difference in my application. I need to find an alternate thats more repeatable… Kindly suggest.

joevj:
I need to find an alternate thats more repeatable.. Kindly suggest.

Here's a few:

Rotary Encoder
Keypad
Serial Input
Up / Down Pushbuttons
Thumbwheel

Basically, anything digital.

gfvalvo:
Here's a few:

Rotary Encoder
Keypad
Serial Input
Up / Down Pushbuttons
Thumbwheel

Basically, anything digital.

Thanks gfvalvo. Will look it up..
Keypad or joystick would probably need a screen also for a feedback, I guess.. will try. Thank you.

BTW, I have submitted this as a project.

gfvalvo:
Here’s a few:

Rotary Encoder
Keypad
Serial Input
Up / Down Pushbuttons
Thumbwheel

Basically, anything digital.

Thanks to gfvalvo’s suggestion, I found a way to make the input digital. I have used HC-05 and made a mobile app (attached snapshot). I felt that was easier to do and for up-scaling… used https://appinventor.mit.edu and was pretty easy without any experience in making mobile app… my first app :)… glad that it worked fine…

I am attaching my code here below… basically, I ready the timing details over bluetooth… process it and then start the sequence. but to my surprise, the variations between each shot is too big for my requirement… my typical timings will be 50 milliseconds / 100 ms / 150ms / 500 ms… sometimes it is close and some times too far off… not able to figure out the root cause… is it that the delay function can vary so much! or is it that somehow the processor gets busy with something in between… the relays are triggered almost the end of the LOOP “//…START - CAMERA - ACTION…”

why it happens?
how to avoid / improve… ?
instead of setting delay, should I set a timer interrupt and will it help?

sorry if code is not so efficient… just self taught!!
Really appreciate the support from this forum… thank you…

BTW, when it works, it is awesome…
https://www.instagram.com/p/B4KzcPeFqkU/

/*
SAMPLE TEXT FROM BLUETOOTH

1000,1,100,250,350,0,0,0,0,0,0,0,/n

*/

#define INPUT_SIZE 300

typedef struct 
{
  int Pin; //Pin for triggerring
  int Timing;     //from T0
  int Action;     //0 to close valve; 1 to open valve
} dEvent;

int eventCount = -1;

int ValvePin1 = 9;   // select the pin for the Valve
int ValvePin2 = 10;   // select the pin for the Valve
int ValvePin3 = 11;   // select the pin for the Valve
int CameraPin = 8;  // to trigger camera

int BT_Rx = 0;
int BT_Tx = 1;


int LEDr1 = 7;
int LEDr2 = 6;
int LEDr3 = 5;
int LEDCam = 4;

int dCam;               // Delay of Camera
boolean r1, r2, r3;     //status of relays
int r1d1, r1d2, r1d3;  // Delay values of R1
int d1m, d2m, d3m, d4m;   //Max delay corresponding full scale of POT (1023)

dEvent Events[15];

//for BT05
char input[INPUT_SIZE + 1]; 
  

void setup() {
  
  Serial.begin(9600);
  
  
  //Setting Pin Modes
  pinMode(ValvePin1, OUTPUT);  // declare the ValvePin as an OUTPUT
  pinMode(ValvePin2, OUTPUT);  // declare the ValvePin as an OUTPUT
  pinMode(ValvePin3, OUTPUT);  // declare the ValvePin as an OUTPUT
  pinMode(CameraPin, OUTPUT);  // declare the CameraPin as an OUTPUT
  
  pinMode(BT_Rx, INPUT); //to Receve Blutooth Data
  
  
  
  // intializing.....
  
  
  // Set valve, camera, LED pins low
  digitalWrite(ValvePin1, HIGH);
  digitalWrite(ValvePin2, HIGH);
  digitalWrite(ValvePin3, HIGH);
  digitalWrite(CameraPin, HIGH);
  
  r1=false;  
  
  
}

void loop() {
  
  
  byte size = Serial.readBytesUntil('\n', input, INPUT_SIZE); 
  input[size] = 0;
  
  // Serial.println(size);
  
  if (size > 0) {
    
    /* FORMAT
    
    first CameraDelay, then three replay details..
    if Rn is enabled, will be Rn=1,D1,D2,D3,
    if Rn is not enabled then will be Rn=0, 
    n = 1, 2, 3...
    
    
    */
    
    char* x;
    
    dCam = atoi(strtok(input, ","));
    r1 = atoi(strtok(NULL, ","));
      r1d1 = atoi(strtok(NULL, ","));
      r1d2 = atoi(strtok(NULL, ","));
      r1d3 = atoi(strtok(NULL, ","));
    
    int t0 = 500;
    int i = 0;
    
    if (r1==1) {
      Events[i++] = (dEvent) {ValvePin1,t0,1};                //open 1st drop
      Events[i++] = (dEvent) {ValvePin1,t0+r1d1,0};           //close 1st drop
      Events[i++] = (dEvent) {ValvePin1,t0+r1d2,1};      //open 2nd drop
      Events[i++] = (dEvent) {ValvePin1,t0+r1d3,0}; //close 2nd drop
    }
    
    
    Events[i++] = (dEvent) {CameraPin,t0+dCam,1};           //Open Camera port
    Events[i++] = (dEvent) {CameraPin,t0+dCam+200,0};           //close Camera port
    
    eventCount = i-1;    
    
    sortEvents();   //Sort it to Ascending Order and set timing as relative.. 
    
    
    //--------------------------------------
    //........START - CAMERA - ACTION.......
    //--------------------------------------
    
    for (i=0; i<=eventCount; i++) {
      
      
      //operate relay
      delay(Events[i].Timing);
      if (Events[i].Action == 1) {
        digitalWrite( Events[i].Pin, LOW );  //Switch ON Relay
        LED_Set(r,HIGH);
      } else if (Events[i].Action == 0) {
        digitalWrite( Events[i].Pin, HIGH );  //Switch OFFLOWay
        LED_Set(r,LOW);
      }
      
       
    }    
    
    
  }
  
}



void sortEvents() {
  
  int i, j;
  dEvent d;
  
  
  //Bubble sort to Ascending Order...
  for (i=0; i<eventCount; i++) {
    for (j=i+1; j<eventCount; j++) {
      if (Events[i].Timing > Events[j].Timing) {
        
        d = Events[i];
        Events[i] = Events[j];
        Events[j] = d;
        
      } 
    }
  }
  
    
  
  
  
  
}

I wanted to give an update … may be someone has same challenge…

I tried to go through many things in the code and the app to see where the issue was. actually the code was ok. it was in the circuit.

I needed 12V to drive the solenoid. instead of giving another power supply, I supplied 12V to Arduino and took the Vin (12V) to drive the relay. it was working somewhat but was inconsistent.

When I gave separate input for the solenoid, all worked perfect.

I guess, when the solenoid was drawing power, the voltage of the board may have gone too low and drove things crazy… anyway, glad that it is behind me… may be was obvious for most, but these are challenges when someone with no background in electronics does it :slight_smile:

https://www.instagram.com/p/B4ksquwlOBH/