Different behaviour on different power supplies

I'm running into a very frustrating issue. My project is set up like this. I have four buttons connected to the Arduino responsible for 4 different functions. One button runs a pump for a certain duration by activating a relay and closing a circuit which the pump then detects (the relays should be optocoupled, the model is JQC-3FF-S-Z), one triggers and interrupt service routine to stop all active functions, and the other two each respectively open a valve for a certain amount of time by activating a relay which in turn closes the circuit on a separate circuit, opening the normally closed valves.

I have two power supplies (both 12V 5A) -- one should eventually correctly power the relays (via the 5V pin) and the Arduino (via the Vin and GND pins), while the other separately supplies the circuit with the two valves since they have relatively demanding current draws -- about 1A each. The relays are all 5V relays with 3 input pins, one for Vcc, one for GND, and another for a digital signal to turn them on/off.

Whenever I debug this on my computer, I have both supplies connected, as well as USB power so that I can get a serial readout. In this state, everything works perfectly -- the valves stay open as long as they should, there's no noise/false ISR triggers, everything is great.

As soon as I disconnect the USB and try to let the Arduino run off of the Vin and GND I've fed it from the power supply, it just starts doing its own random thing. For example, one of the functions programmed is for the pump to run, and both valves to be open all at the same time, for 60 seconds. When its plugged into the computer, it does this perfectly. When not plugged into the computer, it will run for 60 seconds the first time, and then on subsequent runs it will run 30s, 20s, 10s, or whatever other random time duration it feels like.

A couple of things I've read here have been to try common ground (this did nothing but cause other issues) as well as to try to smooth out the power input via capacitors which I have now done since it is worth having them there anyways, but that has also been to no avail, unless I wired them wrong. I also tried grounding the whole thing to earth by connecting a ground wire from ground to a large metal desk (I have absolutely no clue if this was the right way to approach that) but that also didn't help. What can I do? Any help would be greatly appreciated. The code and circuit diagram are below.

Please note I omitted the LCD in the circuit diagram, and I denoted the valves and pump "running" as LEDs in the diagram.

////////////////////////// LIBRARIES /////////////////////////////
#include <avr/interrupt.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

////////////////////////// TIME VARIABLES (in ms) /////////////////////////////
unsigned long LSTime = 60000;
unsigned long HSTime = 110000;
unsigned long LSprimeTime = 60000;
unsigned long HSprimeTime = 10000;
unsigned long washTime = 60000;
unsigned long timeBeforePause = 0;
unsigned long timeAfterPause = 0;
unsigned long pauseDuration = 0;
unsigned long startTime = 0;
unsigned long endTime = 0;
unsigned long lastPressTime = 0;

////////////////////////// I2C DEVICES /////////////////////////////
LiquidCrystal_I2C lcd(0x27,16,2);

////////////////// Button Pin Declarations ////////////////////////
int pumpCtrlPin = 6;
int fillBtn = 12;
int stopBtn = 3;
int primeBtn = 7;
int washBtn = 5;
int valveHeavy = 10;
int valveLight = 9;
int appropriateBtn;

////////////////////////// STATE DECLARATIONS & FLAGS /////////////////////////////
enum {idle, LSInit, LSRun, LSResume, HSInit, HSRun, HSResume, LSprimeInit, LSprimeRun, LSprimeResume, HSprimeInit, HSprimeRun, HSprimeResume, washInit, washRun, washResume, paused, stopDelay};
int resumeState;
int stopped = false;
int programState = idle; //What the program is doing at any moment

void setup() {
  //////////////////////////////// DEVICE INITIALIZATION //////////////////////////////////
  Serial.begin(9600);
  while (!Serial) { delay(1); } // Wait until serial port is opened
  lcd.begin();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0,0);
  //////////////////////////////// BUTTON INITIALIZATION //////////////////////////////////
  pinMode(fillBtn, INPUT_PULLUP);
  pinMode(stopBtn, INPUT_PULLUP);
  pinMode(primeBtn, INPUT_PULLUP);
  pinMode(washBtn, INPUT_PULLUP);
  pinMode(pumpCtrlPin, OUTPUT);
  pinMode(valveHeavy, OUTPUT);
  pinMode(valveLight, OUTPUT);
  digitalWrite(valveHeavy, LOW);
  digitalWrite(valveLight, LOW);
  attachInterrupt(digitalPinToInterrupt(stopBtn), stopISR, RISING);
 //////////////////////////////// ISR FLAG SET //////////////////////////////////
  stopped = false;
  lcd.clear();
  lcd.print("Idle");
}

void loop() {
  switch(programState) {
    case idle:
      {
        if (digitalRead(fillBtn) == LOW) {
          lastPressTime = millis();
          programState = LSInit;
          stopped = false;
          break;
        }
        if (digitalRead(primeBtn) == LOW) {
          lastPressTime = millis();
          programState = HSprimeInit;
          stopped = false;
          break;
        }
        if (digitalRead(washBtn) == LOW) {
          lastPressTime = millis();
          programState = washInit;
          stopped = false;
          break;
        }
        break;
      }
    case LSInit:
      {
        lcd.clear();
        lcd.print("Dispensing Light");
        lcd.setCursor(0,1);
        lcd.print("Sucrose");
        timeBeforePause = 0;
        timeAfterPause = 0;
        pauseDuration = 0;
        startTime = millis();
        endTime = startTime;
        programState = LSRun;
        if (stopped == true) {
          programState = stopDelay;
        }
        break;
      }
    case LSRun:
      { 
        if ((endTime - startTime) <= LSTime) {
          digitalWrite(pumpCtrlPin, HIGH);
          digitalWrite(valveLight, HIGH);
          if (((millis() - lastPressTime) >= 1000) && (digitalRead(fillBtn) == LOW)) {
            Serial.println("pausedSomehow");
            appropriateBtn = fillBtn;
            resumeState = LSResume;
            lastPressTime = millis();
            digitalWrite(pumpCtrlPin, LOW);
            digitalWrite(valveLight, LOW);
            timeBeforePause = millis();
            lcd.clear();
            lcd.print("Paused");
            programState = paused;
            break;
          }
        } else {
          digitalWrite(pumpCtrlPin, LOW);
          digitalWrite(valveLight, LOW);
          programState = HSInit;
          lcd.clear();
          lcd.print("Idle");
          if (stopped == true) {
            programState = stopDelay;
          }
          break;  
        }
        endTime = millis() - pauseDuration;
        if (stopped == true) {
          programState = stopDelay;
        }
        break;
      }
    case LSResume:
      {
        lcd.clear();
        lcd.print("Dispensing Light");
        lcd.setCursor(0,1);
        lcd.print("Sucrose");
        timeAfterPause = millis();
        pauseDuration = pauseDuration + (timeAfterPause - timeBeforePause);
        endTime = millis() - pauseDuration;
        programState = LSRun;
        if (stopped == true) {
          programState = stopDelay;
        }
        break;
      }
    case HSInit:
      {
        lcd.clear();
        lcd.print("Dispensing Heavy");
        lcd.setCursor(0,1);
        lcd.print("Sucrose");
        timeBeforePause = 0;
        timeAfterPause = 0;
        pauseDuration = 0;
        startTime = millis();
        endTime = startTime;
        programState = HSRun;
        if (stopped == true) {
          programState = stopDelay;
        }
        break;
      }
    case HSRun:
      { 
        if ((endTime - startTime) <= HSTime) {
          digitalWrite(pumpCtrlPin, HIGH);
          digitalWrite(valveHeavy, HIGH);
          if (((millis() - lastPressTime) >= 1000) && (digitalRead(fillBtn) == LOW)) {
            Serial.println("pausedSomehow");
            appropriateBtn = fillBtn;
            resumeState = HSResume;
            lastPressTime = millis();
            digitalWrite(pumpCtrlPin, LOW);
            digitalWrite(valveHeavy, LOW);
            timeBeforePause = millis();
            lcd.clear();
            lcd.print("Paused");
            programState = paused;
            break;
          }
        } else {
          digitalWrite(pumpCtrlPin, LOW);
          digitalWrite(valveHeavy, LOW);
          programState = idle;
          lcd.clear();
          lcd.print("Idle");
          if (stopped == true) {
            programState = stopDelay;
          }
          break;  
        }
        endTime = millis() - pauseDuration;
        if (stopped == true) {
          programState = stopDelay;
        }
        break;
      }
    case HSResume:
      {
        lcd.clear();
        lcd.print("Dispensing Heavy");
        lcd.setCursor(0,1);
        lcd.print("Sucrose");
        timeAfterPause = millis();
        pauseDuration = pauseDuration + (timeAfterPause - timeBeforePause);
        endTime = millis() - pauseDuration;
        programState = HSRun;
        if (stopped == true) {
          programState = stopDelay;
        }
        break;
      }
/////////////////////////////////////// PRIMING ///////////////////////////////////
    case HSprimeInit:
      {
        lcd.clear();
        lcd.print("Priming...");
        timeBeforePause = 0;
        timeAfterPause = 0;
        pauseDuration = 0;
        startTime = millis();
        endTime = startTime;
        programState = HSprimeRun;
        if (stopped == true) {
          programState = stopDelay;
        }
        break;
      }
    case HSprimeRun:
      { 
        if ((endTime - startTime) <= HSprimeTime) {
          digitalWrite(pumpCtrlPin, HIGH);
          digitalWrite(valveHeavy, HIGH);
          if (((millis() - lastPressTime) >= 1000) && (digitalRead(primeBtn) == LOW)) {
            Serial.println("pausedSomehow");
            appropriateBtn = primeBtn;
            resumeState = HSprimeResume;
            lastPressTime = millis();
            digitalWrite(pumpCtrlPin, LOW);
            digitalWrite(valveHeavy, LOW);
            timeBeforePause = millis();
            lcd.clear();
            lcd.print("Paused");
            programState = paused;
            break;
          }
        } else {
          digitalWrite(pumpCtrlPin, LOW);
          digitalWrite(valveHeavy, LOW);
          programState = LSprimeInit;
          lcd.clear();
          lcd.print("Idle");
          if (stopped == true) {
            programState = stopDelay;
          }
          break;  
        }
        endTime = millis() - pauseDuration;
        if (stopped == true) {
          programState = stopDelay;
        }
        break;
      }
    case HSprimeResume:
      {
        lcd.clear();
        lcd.print("Priming...");
        timeAfterPause = millis();
        pauseDuration = pauseDuration + (timeAfterPause - timeBeforePause);
        endTime = millis() - pauseDuration;
        programState = HSprimeRun;
        if (stopped == true) {
          programState = stopDelay;
        }
        break;
      }
    case LSprimeInit:
      {
        lcd.clear();
        lcd.print("Priming...");
        timeBeforePause = 0;
        timeAfterPause = 0;
        pauseDuration = 0;
        startTime = millis();
        endTime = startTime;
        programState = LSprimeRun;
        if (stopped == true) {
          programState = stopDelay;
        }
        break;
      }
    case LSprimeRun:
      { 
        if ((endTime - startTime) <= LSprimeTime) {
          digitalWrite(pumpCtrlPin, HIGH);
          digitalWrite(valveLight, HIGH);
          if (((millis() - lastPressTime) >= 1000) && (digitalRead(primeBtn) == LOW)) {
            Serial.println("pausedSomehow");
            appropriateBtn = primeBtn;
            resumeState = LSprimeResume;
            lastPressTime = millis();
            digitalWrite(pumpCtrlPin, LOW);
            digitalWrite(valveLight, LOW);
            timeBeforePause = millis();
            lcd.clear();
            lcd.print("Paused");
            programState = paused;
            break;
          }
        } else {
          digitalWrite(pumpCtrlPin, LOW);
          digitalWrite(valveLight, LOW);
          programState = idle;
          lcd.clear();
          lcd.print("Idle");
          if (stopped == true) {
            programState = stopDelay;
          }
          break;  
        }
        endTime = millis() - pauseDuration;
        if (stopped == true) {
          programState = stopDelay;
        }
        break;
      }
    case LSprimeResume:
      {
        lcd.clear();
        lcd.print("Priming...");
        timeAfterPause = millis();
        pauseDuration = pauseDuration + (timeAfterPause - timeBeforePause);
        endTime = millis() - pauseDuration;
        programState = LSprimeRun;
        if (stopped == true) {
          programState = stopDelay;
        }
        break;
      }
/////////////////////////////// WASHING ///////////////////////////////////  
    case washInit:
      {
        lcd.clear();
        lcd.print("Washing...");
        timeBeforePause = 0;
        timeAfterPause = 0;
        pauseDuration = 0;
        startTime = millis();
        endTime = startTime;
        programState = washRun;
        if (stopped == true) {
          programState = stopDelay;
        }
        break;
      }
    case washRun:
      {
        if ((endTime - startTime) <= washTime) {
          Serial.println(endTime-startTime);
          digitalWrite(pumpCtrlPin, HIGH);
          digitalWrite(valveLight, HIGH);
          digitalWrite(valveHeavy, HIGH);
          if (((millis() - lastPressTime) >= 1000) && (digitalRead(washBtn) == LOW)) {
            Serial.println("pausedSomehow");
            appropriateBtn = washBtn;
            resumeState = washResume;
            lastPressTime = millis();
            digitalWrite(pumpCtrlPin, LOW);
            digitalWrite(valveLight, LOW);
            digitalWrite(valveHeavy, LOW);
            timeBeforePause = millis();
            lcd.clear();
            lcd.print("Paused");
            programState = paused;
            break;
          }
        } else {
          digitalWrite(pumpCtrlPin, LOW);
          digitalWrite(valveLight, LOW);
          digitalWrite(valveHeavy, LOW);
          programState = idle;
          lcd.clear();
          lcd.print("Idle");
          if (stopped == true) {
            programState = stopDelay;
          }
          break;  
        }
        endTime = millis() - pauseDuration;
        if (stopped == true) {
          programState = stopDelay;
        }
        break;        
      }
    case washResume:
      {
        lcd.clear();
        lcd.print("Washing...");
        timeAfterPause = millis();
        pauseDuration = pauseDuration + (timeAfterPause - timeBeforePause);
        endTime = millis() - pauseDuration;
        programState = washRun;
        if (stopped == true) {
          programState = stopDelay;
        }
        break;
      }
    case paused:
      {
        if (((millis() - lastPressTime) >= 1000) && (digitalRead(appropriateBtn) == LOW)) {
          lastPressTime = millis();
          programState = resumeState;
          break;
        }
        if (stopped == true) {
          programState = stopDelay;
        }
        break;
      }
    case stopDelay:
      {
        digitalWrite(pumpCtrlPin, LOW);
        digitalWrite(valveLight, LOW);
        digitalWrite(valveHeavy, LOW);
        lcd.clear();
        lcd.print("Stopping...");
        delay(1500);
        stopped = false,
        programState = idle; 
        lcd.clear();
        lcd.print("Idle");
        break;
      }
  }
}

void stopISR() {
  stopped = true;
}

Do you recall seeing comments about reverse-biased diodes for relays, solenoids, and motors(not bidirectional, obviously)? What you describe sounds to me like voltage transients originating in the solenoids/motor brushes, leaking back to the cpu.

How much current are you trying to supply from this 5v pin?
image

Good catch.
10 mA per output module, plus the LCD is a good load, while feeding Vin 12V is pushing it.

@alusch7 Without changing much, if you can, drop the Vin to around 8V, and see if things improve. Can be done with a 7809 or 7808 linear regulator if you have access to one, or just an 8 or 9V DC wall wart. Make sure it's DC, and regulated, or your problems will compound. This is a test, remember, a final configuration would await proving that this relates to your problem.

I will try and get back to you (I don’t have access to the stuff right now, it’s at work) and I will also need to order a variable buck converter or something of the sort to get it down to 8.

As for how much current it’s drawing, (@apf1979) I would have to guess based on this shoddy spec sheet, probably around 400mA maximum when all 3 relays are active along w/ the LCD and digital pins?

From your incomplete schematic I can understand why it does not operate properly. It appears you are slowing cooking the Arduino to the well done state just before it fries. Main point: "A Power Supply the Arduino is NOT!" My experience tells me the relay coils are drawing to much current causing the 5V regulator on the Arduino to partially shut down as it is overloaded and hot. The reason it works with the USB is it is getting power from that which is supplied by your computer, not the Arduino regulator. Add a buck or SEPIC converter and get your 5V from the 12V source. I simply use relay modules hat have 12V relays, works great.

Yes, the schematic was incomplete. I’m new to Fusion 360s electronics maker and thus a bit slow with it, and didn’t want to waste time adding in the LCD since this problem has been plaguing me for days. Did my best to get the jist down, clearly it was enough.

Anyways. This seems the most likely reason/solution, because I saw someone mention something similar. I will try to continue to power the Arduino with the 12V supply but branch off a section into a 12-5V buck converter and power the relays via that branch, if that is what you meant (please correct me if it is not). Or I might swap the relays for 12V ones since that seems way easier and I need 12V to power the LEDs on the buttons (purely for aesthetics).

Yeah, I misread your schematic, the relay part number there draws 10 mA but those you listed draw 70+. Absolutely, killing your Arduino is just a matter of time, and not much of it once you start turning on more than one.
Rework your power.

I am not familiar with Fusion 360s electronics maker. I use KiCad which is a full blown electronics CAD program that will take me from schematic capture to pc boards. It is very popular and well documented on the web. It is free for the downloading however they ask but not require a donation.

If the schematic were complete you would have probably seen what the problem was.

Doubtful. I had no idea there was even a regulator I could overload.

@camsysca, would my above power reworking plan suffice?

I think it'll work. Make sure the control grounds are tied together, but not the loads.

1 Like

Yes, that should work. Running the relays off the buck converter is a good use of it. If you continue to put the LCD on the 5V output(but only that), there is a minor chance you'll have further issues, but I don't think it's likely. My comment about reverse diodes still applies, by the way - transients can still cause you grief.

Ah right. Something I actually did forget to include is I do have pretty huge fly back diodes at the valves (which are solenoids) and the relays I’m using already have built in fly back diodes (although that model I put on the diagram supposedly has them built in too). I was having noise issues from the valves before, but that specific interference I was encountering before (the interrupt accidentally misfiring every time the solenoids switched state) is no longer there.

And that is the sort of reason why so many seasoned helpers on this list ignore posts that don't provide a schematic to work with. I'm sorry, but so much time is wasted struggling to understand the context of a new problem when a drawing will clarify so much. You're in engineering, so that shouldn't be lost on you. Not lecturing you, just trying to help you get faster, more pertinent answers to your questions here.

I hooked up a 5V voltage regulator and put the LCD and relays on that circuit. It works beautifully now. Thank you all for your assistance.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.