Interrupt interference causing havoc??

Hi all.

I’m working on a project that uses a hall effect sensor to control the timing of some 12V solenoid valves. The problem I had used LEDs to indicate the valves back in the early stages when I was working on the valve sequence, but now that I’ve connected up the valves they’re playing havoc with the interrupt - I suspect it’s interference.
I also noted that just touching the wire that runs to the interrupt pin causes massive interference with the valves…

I’ve attached two videos below - one showing the sequence working (sans valves), the other NOT working (with valves) - In both videos, note the yellow LED is showing when the hall effect sensor is triggered. This is when I expect the valves will move along their sequence.
Valve sequence working: https://youtu.be/bm-nMdCZIWU
Valve sequence NOT working: https://youtu.be/1uX-hQW878o

Any idea what I can do to ensure that the sequence works correctly and reliably? I’ve spent way too much time trying to figure this out myself…

The schematic and code is also shown below.

EDIT: In the schematic below I forgot to connect the two grounds. They are in fact common grounds.
Capture.PNG

#include <LiquidCrystal.h>

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);           // select the pins used on the LCD panel

//LCD Variables
int lcd_key     = 0;
int adc_key_in  = 0;
int led_on      = 0;
int timer;
int btn_count   = 0;
int btnDelay =200;
//int ledDelay =0;
unsigned long prevBtnMillis=0;
unsigned long prevLedMillis=0;
int ledState = LOW;

//Interrupt Variables
const byte interruptPin = 2;        //Sensor pin attached
volatile byte cyl1 = LOW;
volatile bool newISR = false;

//Valve Variables                   //if cyl1 = true then toggle valve 1, else toggle valve 2. the interrupt will toggle cyl1.
//boolean cyl1 = true;
boolean valve1 = true;
boolean valve3 = true;              // only declare boolean variables for valve 1 and 3, since 2 and 4 are just the opposite.
int V1Pin =  3;
int V2Pin = 11;
int V3Pin = 12;
int V4Pin = 13;

//Sensor Variables
int IPM = 4;                                //sensed intervals per revolution
volatile unsigned long prevSigTime;         //Time (ms) when the last signal was received
volatile unsigned long currSigTime;
unsigned long nextSigTime;                  //Prediction for next interval.
unsigned long prevInterval;
unsigned long nextInterval;

//RPMVariables
unsigned int currRPM;               
unsigned int setRPM = 50;

#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

int read_LCD_buttons(){               // read the buttons
    adc_key_in = analogRead(0);       // read the value from the sensor 

    if (adc_key_in > 1000) return btnNONE; 

    // For V1.1 us this threshold
    if (adc_key_in < 50)   return btnRIGHT;  
    if (adc_key_in < 250)  return btnUP; 
    if (adc_key_in < 450)  return btnDOWN; 
    if (adc_key_in < 650)  return btnLEFT; 
    if (adc_key_in < 850)  return btnSELECT;  

    return btnNONE;                // when all others fail, return this.
}

void setup(){
  Serial.begin(9600);
   lcd.begin(16, 2);               // start the library
   lcd.setCursor(0,0);             // set the LCD cursor   position 
   lcd.print("G-Steam 0.1");       // print a simple message on the LCD
   lcd.setCursor(0,1);
   lcd.print("rpm:");
//   pinMode(led_pin,OUTPUT);
   timer=millis()/1000;
//   pinMode(interruptLed, OUTPUT);
   pinMode(interruptPin, INPUT_PULLUP);
   attachInterrupt(digitalPinToInterrupt(interruptPin),toggle,RISING);
   
}
 
void loop(){

  if (newISR){
    calcInterval();
  }
  //NEED TO FIGURE OUT HOW TO TRIGGER THE VALVES BASED ON SENSOR READING OR PREDICTION, WITHOUT UPSETTING THE SEQUENCE (ON/OFF)
  //CODE BELOW IS TO ENSURE THAT THE VALVE FROM A PAIR IS TURNED OFF BEFORE THE OTHER ONE IS TURNED ON. THE POWER SUPPLY (PROBABLY)
  //ONLY HAS ENOUGH POWER FOR A MAXIMUM OF 2 VALVES... 
  if (valve1){
    digitalWrite(V2Pin, !valve1);
    digitalWrite(V1Pin, valve1);
  }
  else{
    digitalWrite(V1Pin, valve1);
    digitalWrite(V2Pin, !valve1);
  }

  if (valve3){
    digitalWrite(V3Pin, valve3);
    digitalWrite(V4Pin, !valve3);
  }
  else{
    digitalWrite(V4Pin, !valve3);
    digitalWrite(V3Pin, valve3);
  }
  
  updateLCD();
}

void toggle(){
  prevSigTime = currSigTime;
  currSigTime = millis();
  newISR = true;

  if (cyl1)
  {
    cyl1 = !cyl1;
    valve1=!valve1;
  }
  else
  {
    cyl1 = !cyl1;
    valve3=!valve3;
  }

  //Serial.print(String(currRPM) + "; " + String(prevInterval));
               //Serial.println();
}

void updateLCD(){
  /*   lcd.setCursor(9,1);             // move cursor to second line "1" and 9 spaces over
   lcd.print (btn_count);
   
   lcd.setCursor(0,1);             // move to the begining of the second line
   */
   lcd_key = read_LCD_buttons();   // read the buttons

  unsigned long currBtnMillis = millis();
  unsigned long currLedMillis = millis();

lcd.setCursor(5,1);

lcd.print(String(currRPM) + "->" + setRPM + "  ");

  
   switch (lcd_key){               // depending on which button was pushed, we perform an action

       case btnRIGHT:{             //  push button "RIGHT" and show the word on the screen
            //lcd.print("RIGHT ");
            break;
       }
       case btnLEFT:{
             //lcd.print("LEFT   "); //  push button "LEFT" and show the word on the screen
             break;
       }  

       case btnUP:{
             //lcd.print("UP    ");  //  push button "UP" and show the word on the screen
             if (currBtnMillis - prevBtnMillis >= btnDelay){
               setRPM = ++setRPM;
               lcd.setCursor(11,1);
               lcd.print ("    ");
               lcd.setCursor(11,1);
               lcd.print (setRPM);
               lcd.setCursor(0,1);
               prevBtnMillis=millis();
             }
             break;
       }
       case btnDOWN:{
             //lcd.print("DOWN  ");  //  push button "DOWN" and show the word on the screen
             if(currBtnMillis-prevBtnMillis>=btnDelay){
               setRPM = --setRPM;
               lcd.setCursor(11,1);
               lcd.print ("     ");
               lcd.setCursor(11,1);
               lcd.print(setRPM);
               lcd.setCursor(0,1);
               prevBtnMillis=millis();
             }
             break;
       }
       case btnSELECT:{
             //lcd.print("SELECT");  //  push button "SELECT" and show the word on the screen
             if(currBtnMillis-prevBtnMillis>=btnDelay){
               
               prevBtnMillis=millis();
             }
             break;
       }
       case btnNONE:{
             //lcd.print("NONE  ");  //  No action  will show "None" on the screen
             break;
       }
   }
}

void calcInterval(){
  prevInterval = currSigTime-prevSigTime;
  currRPM = 60000/((long)IPM*prevInterval);                //equivalent to 1/interval * number of intervals per rev
  newISR = false;
  
}

Hi,
Two quick ideas:

1: You voltage divider from 12V is shown as wrong.. You need the 200K in the series lead and the 100K to ground.

2: Electromagnetic Interference from the inductance of the solenoids. See:
http://arduino-info.wikispaces.com/RelayIsolation

It looks like your 5V circuit (Arduino) does not share a Ground with your 12V circuit (MOSFETS). That will make it hard for the Arduino to switch the MOSFETS properly. Connect the two Grounds together.

terryking228:
Hi,
Two quick ideas:

1: You voltage divider from 12V is shown as wrong.. You need the 200K in the series lead and the 100K to ground.

2: Electromagnetic Interference from the inductance of the solenoids. See:
http://arduino-info.wikispaces.com/RelayIsolation

Thanks for that, I'll make that change to the voltage divider tonight and give it a shot. Having a read through that wiki now too...

johnwasser:
It looks like your 5V circuit (Arduino) does not share a Ground with your 12V circuit (MOSFETS). That will make it hard for the Arduino to switch the MOSFETS properly. Connect the two Grounds together.

Thanks John. That's an error in my schematic. The two grounds are common, I realised that mistake a little while ago.

Are there diodes across the solenoid coils to absorb the reverse voltage spikes when the magnetic field collapses?