5V relays causing issues with sketch when switching

Afternoon all, This is my setup for automated greenhouse watering. But I am having some trouble with the 5v relays. (The relays I’m using are https://www.ebay.co.uk/itm/221890132279)

The system is fed off solar batteries and runs through the charge controller. I have the green LED which lights in the setup() function of the board. My reasoning is, if the solar battery runs out and then recharges (i.e the board restarts) then that light will illuminate to tell me that has happened, I have a red switch next to this LED that once pressed it turns the LED off, just to confirm I am aware that power has been lost at some stage, the LED shouldn’t light again until power is lost or the board is reset.

This part of the program works. However, if I connect the pins leading to the relay I have an issue where if the relay switches power then the LED will go off when it’s not meant to.

Things I have tried:
I have tried this with the 12V load disconnected, and the program works as it should, only when it is switching the 12V I have issues.

I have a separate 5v dc powering the relay side of the board jd-vcc which is stepped down from the 12v. The relays vcc and inputs are switched from the Uno which is running from the solar controllers onboard USB port

Input-pullup is selected on the reset switch so It shouldn’t be an issue with floating voltage, although I haven’t tried using an external pullup resistor.

This is the simplified wiring diagram I have knocked together for the setup:

Like I said, I only have the issue when the relays are switching the 12V, if I leave that part disconnected then the sketch works as I want. If I connect the 12V then my pump runs and the flowers are wartered, its just the LED that turns off after the first switching cycle.
From a bit of google research this makes me think it is caused by electrical noise and a ‘flyback diode’ may be the answer. But before I dive down that rabbit hole I wanted to see what others opinions were. Am I on the right track?

Thanks for reading and apologies for the mess of wires in my first photo you’ve just spent 10mins tracing to try and figure out what I’m talking about :blush:

1 Like

Code I’ve got is below:
I have set the watertime to water for 10seconds and wait for 20seconds to test the program (like I say that works when connected to my relay and pump, just having issues with the LED light staying on when the relay switches.)

The very last function is the code to trun my LED off if that helps, although I feel this may be a hardware issue, not code related.

Some functions are commented out as I am planning on adding bits (making a dry run protection for the water butt etc.,) but not got around to competing this part of the code yet.

const unsigned long SECOND = 1000UL;
const unsigned long MINUTE = (SECOND * 60UL);
const unsigned long HOUR = (MINUTE * 60UL);                   // for the 'clock'

unsigned long waterTimeA = (10 * SECOND);                      //Run time 45sec for solenoid A
unsigned long delayTimeA = (20 * SECOND);                     //Delay time 3Hrs for solenoid A                          [TIMING]

//---------------------------------------------------------------------------------------------------------------------------------------------------------

const int pumpPin = 2;
const int SolenoidAPin = 3;
const int SolenoidBPin = 4;
const int SolenoidCPin = 5;
const int Hallinput = 10;                                     //Define the physical pins on the board                   [BOARD]
const int LockoutLED = 6;
const int resetSwitch = 7;
const int PWRlossLED = 8;
const int PWRlossSwitch = 9;

unsigned long previousMillis = 0;                             // will store last time Solenoid was updated
int SolenoidStateA = LOW;                                    // State used to set the solenoid,   // LOW(pump on) on startup (relays are active low)
int SolenoidStateB = HIGH;
int SolenoidStateC = HIGH;

byte var = HIGH;
bool PWRloss;

//---------------------------------------------------------------------------------------------------------------------------------------------------------



void setup()
{ pinMode(SolenoidAPin, OUTPUT);
  pinMode(SolenoidBPin, OUTPUT);
  pinMode(SolenoidCPin, OUTPUT);
  pinMode(pumpPin, OUTPUT);
  pinMode(Hallinput, INPUT_PULLUP);                         //set-up pins                                               [BOARD][SETUP]
  pinMode(LockoutLED, OUTPUT);
  pinMode(PWRlossLED, OUTPUT);
  pinMode(resetSwitch, INPUT_PULLUP);
  pinMode(PWRlossSwitch, INPUT_PULLUP);

  digitalWrite(PWRlossLED, HIGH);
  digitalWrite(PWRlossSwitch, HIGH);
  PWRloss = true;                                         // power loss LED lights if board resets (loss of power)

  pinsOn();                                                 // pump etc starts on startup until water time has elapsed.
}


void loop()
{
  if (PWRloss == true) {
    resetPWRloss(); //has power been lost? - confirm ok with reset function()
  }

  unsigned long currentMillis = millis();                                                       //Current 'time'


  if ((SolenoidStateA == LOW) && (currentMillis - previousMillis >= waterTimeA))
  {
    SolenoidStateA = HIGH;                                                                       // Turn it off
    previousMillis = currentMillis;                                                             // Remember the time                                       //to do: **************** for '5' times then delay for 9 hrs*****************
    pinsOff();
  }
  else if ((SolenoidStateA == HIGH) && (currentMillis - previousMillis >= delayTimeA))
  {
    SolenoidStateA = LOW;                                                                      // Turn it on
    previousMillis = currentMillis;                                                             // Remember the time
    pinsOn();
  }                                                                                                                     //[TIMING][MAIN LOOP]
}



//FUNCTIONS----------------------------------------------------------FUNCTIONS--------------------------------------------------------//FUNCTIONS------------------------------------

void pinsOn() {
  digitalWrite(SolenoidAPin, SolenoidStateA);
  runPumpProtect();                                   // Runs @ watering time

}


//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void pinsOff() {
  digitalWrite(SolenoidAPin, SolenoidStateA);
  digitalWrite(pumpPin, SolenoidStateA);
  //digitalWrite(Hallinput, SolenoidStateA);                  // Runs to turn pump etc. off

}


//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void runPumpProtect() {

  digitalWrite(pumpPin, LOW);
  Serial.println("PumpProtect running");
  delay (10);                                                             // delay for pump priming
  //hallSensor();                                                           // runs Hall sensor to check flow is OK
}


//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void hallSensor() {
  int pulse = 0;                                                        // Variable for saving pulses count.
  //int var = 0;
  unsigned long currentTime = millis();

  while (millis() - currentTime < 5000UL) {
    if (digitalRead(Hallinput) > var)
    {
      var = LOW;
      pulse++;
      Serial.print(digitalRead(Hallinput));

      Serial.print(pulse);
      Serial.print(" pulse recieved ");
    }

    if (digitalRead(Hallinput) == 0) {
      var = HIGH;
    }

    delay(50);                                                          // debouncing.
  }                                                                     //pulses counted over a period of 5seconds (5000 millis)

  if (pulse >= 5) {
    Serial.print(" 5+ pulses recieved- flow is OK");                    //Continues rest of program until waterTimeA =! TRUE
  }
  else if (pulse < 5) {
    Serial.print("LOCKOUT");                                             //lockout requires all pins = OFF
    //LOCKOUT();                                                         //runs lockout if <5 pulses recieved in time frame
  }
  else {
    Serial.print("not sure whats happening");                          // this should never run
    LOCKOUT();
  }

}


//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void LOCKOUT() {                                                          //Runs if Hall sensor recieves <5 pulses in 5 sec. **Dry run protection for the pump.**
  digitalWrite(SolenoidAPin, LOW);
  digitalWrite(pumpPin, LOW);
  digitalWrite(Hallinput, LOW);
  digitalWrite(LockoutLED, HIGH);
  digitalWrite(resetSwitch, HIGH);
  Serial.println("EMERGENCY LOCKOUT") ;
  int L = 1;

  while (L == 1) {
    if (digitalRead (resetSwitch) == LOW) {
      Serial.println("reset pressed");
      digitalWrite(LockoutLED, LOW);
      break;
    }
  };

}

//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void resetPWRloss() {
  int buttonState = digitalRead(PWRlossSwitch);
  if (buttonState == LOW) {
    digitalWrite(PWRlossLED, LOW);
    PWRloss = false;
  }
}                                             //this should stay off unless power is lost



//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

That’s it, most probably. Do you know how to select and install such diodes?

Not the slightest clue, I’m afraid.

If you’ve got the time to explain or have a suggestion on a good tutorial or article for selecting diodes for this application I would appreciate it

It’s quite easy. The diodes must support the load voltage (12V) and the load current. You can measure the pump current or resistance and the diode must support at least that current. Or look for the electrical characteristics of your pumps, in their data sheet. A 1N4001 will do for up to 1A.

Then connect such a diode in parallel to the load, in reverse direction (cathode to supply +, anode to -).

Found the answer to my question…

Powered from solar battery via the charge controllers USB port, follow the wire from the uno in first photo. That charge controller is connected to a leisure battery out of shot and a solar panel

Your question?

I agree that noise is the likely cause and should be dealt with as suggested.

I also think you should do some checking to see how long the PWRlossSwitch is pressed for, at the moment if it’s pressed for the tiniest bit of time when you check then you clear the LED. The possible result of that is the button is too sensitive to noise. You should debounce it. My tutorial on this is here: Buttons and other electro-mechanical inputs (introduction), but there are others.

A simple fix if you don’t want to mess about with re-writing your code would be a small capacitor across the button at the point it connects to the Uno, maybe something between 0μ1 and 1μ0.

Your code is blocking in that it contains delays, while probably not the cause of this problem it would be better if you got rid of the delays and used millis for all your timing.

This is where I came confused earlier, what is the ‘load’ in this context? My flyback diode will be used to dissipate the energy created when the coil collapses… My relays will have a charged coil, my solenoids will have a charged coil and my motor once power is cut may induce a reverse current too?
Where should the diode be placed, is it on every one of these points? or one diode to cover the lot somehow?.

On that first photo I’ve posted I have 4 relays (2x2 channel) 1 for pump power, 3 for solenoids to different areas of the greenhouse (although only one will be active at a time).

Relay and motor driver boards typically include the diodes already. Remain the pumps, with a diode across each coil.

The thing that draws current, whatever that is. So a relay coil is a load, the motor is another load. As noted, relay boards usually have the diodes included.

Another ting to consider is tidy wiring, not because it looks nice (although it does) but because it reduces problems like this. Pairs of wires carrying the same current should be together, so, for example, the 2 wires to the button you are concerned about should be run together, and ideally twisted together. Signal wires should take a separate route to wires carrying power. You should avoid loops where the return path for the current does not follow the flow path: think of any cable with 2 wires in it providing power; the wires run right next to each other, this is not just convenient, it is electrical good practice.

I’ve just run a quick test on that theory, thanks for the explanation.
If I connect my setup with only the relays and the pump all is well, green light stays on.

It’s when I ask the relays to switch the solenoid that the issue occurs. Making me think diodes across the solenoids would be the possible cure. It this setup correct:

Red wire is 12v +ve solenoid#1 , green wire 12v +ve solenoid #2 and black is common ground for the two. (The black wire leaving from the second solenoid is left swinging in the wind at the moment but was for a 3rd solenoid once I get around to it.)

One solenoid draws 0.6A so the 1N4001 you mentioned earlier should suffice across each?

The pump, although this seems to be ok with the flyback voltage draws 1.3A so i’ll air on the side of caution and get a diode for that too, but a higher current rating.

I’ll also have a look at making the switch less sensitive as this may very well help also.

Thank you both for the input so far

My second picture shows the full wiring setup, I appreciate it looks unbelievably messy, it gives me a headache looking at it too.

The two floating red crocodile clips are connected to a temporary 12V 3A power supply, as I haven’t got a big battery connected yet (using an old car battery just to test currently).

There are two lengths of flexible conduit to the ‘button box’ on the right- one has only 12v switching to manually actuate the solenoids and pump, the other has only 5v which is connected to the Arduino. Granted I have pushed LED power and the switching wires up the same conduit and I have used untwisted wire (dupont jumper cable, as the dupont end was convenient for testing with the arduino)

So I have tried to separate the voltages, I will try some diodes first and if I’m still getting issues then look into redesigning the cable routes and adding twists. Thanks for the help.

The plus and minus in the picture confuses. Reading Your text it looks like correct.
Think like this: The current flows through the coil, motor, solenoid,… and when the current flow is cut off by relays, transistors, that free wheel diode allows the current to continue, until the magnetic field has collapsed.

1 Like

That’s fine, I could not see it clearly on the photos. Power and signals in separate conduit is the right thing to do. LED wiring and low voltage, low current switch wiring together won’t be a problem.

You need to realise that the messy wiring is actually a substantial part of the problem.

To avoid interference between different parts, it is essential to keep all connections between one part and another tightly bundled either by using ribbon-type wire, or tying with cord (nylon fishing line is convenient) so that there are no open loops in the wiring between a power or signal line and its matching ground return as such open loops function as little coupling transformers. It is necessary to understand that these microcontrollers operate at "RF" - radio frequencies - and the principles of radio transmission apply.

And note this especially applies to the wiring to motors, solenoids etc.

1 Like

You were on the money here, a bit of debouncing following your tutorial, and the LED is doing what it's meant to again. (I'll still add the diodes just to reduce the effects of noise even further.)

For completeness this is the new function I've got for pressing the switch:

void resetPWRloss() {
  unsigned long currentMillis = millis();                    
  static unsigned long lastMillis;                           
  const unsigned long BOUNCETIMEOUT = 20UL;                   
  bool currentButtonState = digitalRead(PWRlossSwitch);     
  static bool lastButtonState;                        

  if (lastButtonState != currentButtonState) {          
    if (currentMillis - lastMillis >= BOUNCETIMEOUT) {  
      lastButtonState = currentButtonState;             
      if (currentButtonState == LOW) {       
        digitalWrite(PWRlossLED, LOW);
        PWRloss = false;     
      }
    }
  }
  else {
    lastMillis = currentMillis;                        
  }
}

As you can see I've followed the tutorial, but not exactly copied it line for line, just to try and understand whats happening better. I do have a couple of questions relating to the code if I may ask?

Q1)
I see you've defined some variables as type uint32_t, I'm curious what the benefit of this is in this context and has it any benefit over using say unsigned long?

Q2)
Two times in your code you declared a static variable,

static uint32_t lastMillis;
static bool lastButtonState;

From my limited knowledge of the language, I was always under the impression that once you declare a variable it's best to assign it a value. So I was feeling like I should write

static uint32_t lastMillis = 0;
static bool lastButtonState = HIGH;

Just so that it wasn't picking its own value from some random point in memory? However I can't see how this would work with a static variable as it would then just reset to these values every time the function is called? So my question is when using the static variables how does it know what value to assign as the default value without me explicitly assigning it?

Thanks again for the help everyone, I am back on the right track again. :+1:

Personal preference; they are the same. I don't like unsigned long and similar because you are expected to know how big they are. uint32_t is explicit, you know what you are getting. Use which ever you are comfortable with.

If you don't assign a value to a variable when you create it it will have whatever value happens to be left in memory from whatever was using the memory before, so, at some point you have to give it a value you actually want. When you do this is up to you. You could probably write some really difficult to follow code by not assigning a value but deliberately using the value left behind by the previous variable. Might be a fun exercise to get it working.

You hit on something I misunderstood for quite a while when I was learning C: I thought what you just said, that if I gave a value to a static variable when it's declared then it would get that value each time the function was called. I ever wrote rather strange code to get around this problem. Thankfully that's not how it works: the variable will get it's initial value the first time the function is called, after that it will keep whatever value it has when the function returns.

1 Like