trouble with multiple realys

I am having trouble with a circuit of 4 relays that must fire for 20 seconds when I place a sticker on a panel to close the circuit. Once all 4 relays are fired the stickers are removed and the process starts over.

I got some amazing guidance earlier this week to get my code working. It works great when i close one circuit at a time. If I try to close 2 circuits the 2nd relay will not fire.

It’s get stuck in the “ALL_DONE” state How can i allow the program to keep looking for the other 3 closed circuits?

Thank you to everyone here for such great advice.

here’s my current code:

// Program will sense a closed circuit and turn on a relay for 20 seconds
// there are 4 circuits in all, Program must be able to fire a relay
// regardless of the state of the other 3.



//these pins go to the relay
int ledPin1 = 6;
int ledPin2 = 5;
int ledPin3 = 4;
int ledPin4 = 3;
//these pins go out to the sticker circuit
int sensePin1 = 0;
int sensePin2 = 1;
int sensePin3 = 2;
int sensePin4 = 3;
//setting the states
enum state { 
  NO_OBJECT_IN_PANEL1,
  NO_OBJECT_IN_PANEL2,
  NO_OBJECT_IN_PANEL3,
  NO_OBJECT_IN_PANEL4,
  LED_ON1,
  LED_ON2,
  LED_ON3,
  LED_ON4,
  ALL_DONE1,
  ALL_DONE2,
  ALL_DONE3,
  ALL_DONE4,
  

} state = NO_OBJECT_IN_PANEL1;

uint32_t startTime_ms;

void setup(){
  Serial.begin(9600);
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  pinMode(ledPin3, OUTPUT);
  pinMode(ledPin4, OUTPUT);
  pinMode(sensePin1, INPUT);
  pinMode(sensePin2, INPUT);
  pinMode(sensePin3, INPUT);
  pinMode(sensePin4, INPUT);
  
}

void loop() {
  // these values determine if the circuit is open or closed
  int val1 = analogRead(sensePin1);
  int val2 = analogRead(sensePin2);
  int val3 = analogRead(sensePin3);
  int val4 = analogRead(sensePin4);
  Serial.println(state);
  switch(state) {
  case NO_OBJECT_IN_PANEL1:  // state = 0
    if (val1 > 25) {
      digitalWrite(ledPin1, HIGH);
      startTime_ms = millis();
      state = LED_ON1;
      break;
    }
   case NO_OBJECT_IN_PANEL2:  // state = 1
    if (val2 > 25) {
      digitalWrite(ledPin2, HIGH);
      startTime_ms = millis();
      state = LED_ON2;
      break;
     }
    case NO_OBJECT_IN_PANEL3:  // state = 2
    if (val2 > 25) {
      digitalWrite(ledPin3, HIGH);
      startTime_ms = millis();
      state = LED_ON2;
      break;
     }
      case NO_OBJECT_IN_PANEL4:  // state = 3
    if (val2 > 25) {
      digitalWrite(ledPin4, HIGH);
      startTime_ms = millis();
      state = LED_ON2;
      break;
     }

  case LED_ON1: // state = 4
    if(millis() - startTime_ms >= 5000L) {
      digitalWrite(ledPin1, LOW);
      state = ALL_DONE1;
      break;
    }
   case LED_ON2: // state = 5
    if(millis() - startTime_ms >= 5000L) {
      digitalWrite(ledPin2, LOW);
      state = ALL_DONE2;
      break;
    }
   case LED_ON3: // state = 6
    if(millis() - startTime_ms >= 5000L) {
      digitalWrite(ledPin3, LOW);
      state = ALL_DONE3;
      break;
    }
   case LED_ON4: // state = 7
    if(millis() - startTime_ms >= 5000L) {
      digitalWrite(ledPin4, LOW);
      state = ALL_DONE4;
      break;
    } 
 
  case ALL_DONE1: // state = 8
       break;
     
  case ALL_DONE2: // state = 9
       break;
     
  case ALL_DONE3: // state = 10
       break;
    
  case ALL_DONE4: // state = 11
       break;
   

  }
if (val1 < 25 && val2 < 25 && val3 < 25 && val4){
  state = NO_OBJECT_IN_PANEL1;}

}

Just a guess, no idea if even related to the problem but did you intend to check val4 for < 25?

“if (val1 < 25 && val2 < 25 && val3 < 25 && val4)”

I caught that right after i posted. Checked it and it's still the same.

thank you,

Search for "val2". You find it in two places incorrectly, where you should be testing val3 and val4.

got it avr_fred. That's what happens when i copy paste...

Still same result.

I just feel like something needs to be happening at the ALL_DONE state to release it back into the loop.

But, i have no clue what that would be.

It's so close!

There are actually several things going on… the big picture is that you can only handle one state at a time in the present form. You need to do all four sensors in parallel. That requires a little rework. The other show stopper is misplaced break statements in the select cases. That one is rather subtle, it’s a common mistake.

Here’s a quick rework. I’m not sure the logic is exact what you want but at least I think this will get you moving again.

// Program will sense a closed circuit and turn on a relay for 20 seconds
// there are 4 circuits in all, Program must be able to fire a relay
// regardless of the state of the other 3.

//these pins go to the relay
const int ledPin1 = 6;
const int ledPin2 = 5;
const int ledPin3 = 4;
const int ledPin4 = 3;

//these pins go out to the sticker circuit
const int sensePin1 = 0;
const int sensePin2 = 1;
const int sensePin3 = 2;
const int sensePin4 = 3;

enum state {
  NO_OBJECT_IN_PANEL,
  LED_ON,
  ALL_DONE,
};

state state1 = NO_OBJECT_IN_PANEL;
state state2 = NO_OBJECT_IN_PANEL;
state state3 = NO_OBJECT_IN_PANEL;
state state4 = NO_OBJECT_IN_PANEL;

uint32_t startTime_ms1;
uint32_t startTime_ms2;
uint32_t startTime_ms3;
uint32_t startTime_ms4;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  pinMode(ledPin3, OUTPUT);
  pinMode(ledPin4, OUTPUT);
  pinMode(sensePin1, INPUT);
  pinMode(sensePin2, INPUT);
  pinMode(sensePin3, INPUT);
  pinMode(sensePin4, INPUT);
}

void loop() {
  // these values determine if the circuit is open or closed
  int val1 = analogRead(sensePin1);
  int val2 = analogRead(sensePin2);
  int val3 = analogRead(sensePin3);
  int val4 = analogRead(sensePin4);

  Serial.println(state1);
  Serial.println(state2);
  Serial.println(state3);
  Serial.println(state4);
  Serial.println("");

  switch (state1) {
    case NO_OBJECT_IN_PANEL:
      if (val1 > 25) {
        digitalWrite(ledPin1, HIGH);
        startTime_ms1 = millis();
        state1 = LED_ON;
      }
      break;
    case LED_ON:
      if (millis() - startTime_ms1 >= 5000UL) {
        digitalWrite(ledPin1, LOW);
        state1 = ALL_DONE;
      }
      break;
    case ALL_DONE:
      break;
  }

  switch (state2) {
    case NO_OBJECT_IN_PANEL:
      if (val2 > 25) {
        digitalWrite(ledPin2, HIGH);
        startTime_ms2 = millis();
        state2 = LED_ON;
      }
      break;
    case LED_ON:
      if (millis() - startTime_ms2 >= 5000UL) {
        digitalWrite(ledPin2, LOW);
        state2 = ALL_DONE;
      }
      break;
    case ALL_DONE:
      break;
  }

  switch (state3) {
    case NO_OBJECT_IN_PANEL:
      if (val3 > 25) {
        digitalWrite(ledPin3, HIGH);
        startTime_ms3 = millis();
        state3 = LED_ON;
      }
      break;
    case LED_ON:
      if (millis() - startTime_ms3 >= 5000UL) {
        digitalWrite(ledPin3, LOW);
        state3 = ALL_DONE;
      }
      break;
    case ALL_DONE:
      break;
  }

  switch (state4) {
    case NO_OBJECT_IN_PANEL:
      if (val4 > 25) {
        digitalWrite(ledPin4, HIGH);
        startTime_ms4 = millis();
        state4 = LED_ON;
      }
      break;
    case LED_ON:
      if (millis() - startTime_ms4 >= 5000UL) {
        digitalWrite(ledPin4, LOW);
        state4 = ALL_DONE;
      }
      break;
    case ALL_DONE:
      break;
  }

  if (state1 == ALL_DONE && state2 == ALL_DONE && state3 == ALL_DONE && state4 == ALL_DONE ) {
    if (val1 < 25 && val2 < 25 && val3 < 25 && val4 < 25) {
      state1 = NO_OBJECT_IN_PANEL;
      state2 = NO_OBJECT_IN_PANEL;
      state3 = NO_OBJECT_IN_PANEL;
      state4 = NO_OBJECT_IN_PANEL;
    }
  }
}

I really appreciate you helping me out here. I have to have this solved by Monday.

I ran your code and now all 4 relays fire when i close one circuit.
I still have the problem with only one switch at a time. Each work independently, but as soon as i close 2 of them… nothing happens.

I’m going to try and absorb what you just did.

thanks again!!

I have tested the logic, it works as expected without all four outputs turning on at the same time. Additionally, all four inputs must go >25 counts to fire the output and then it is inhibited from re-firing until all four inputs have cycled high (>25). Only then and when all four inputs are <25, all four channels are reset to NO_OBJECT so the process can repeat.

I suspect you have a problem with whatever the input devices are and the way you sensing them or have them wired. I hope you’re not using the analog inputs as digital inputs, that’s actually what it looks like to me since you only check for the analog value to be either below 25 counts or above 25 counts. That really doesn’t pass the smell test for me… Some additional information about the “stickers” and how they work should be the next topic up for discussion.

Here is a cleaned up version. There are no real changes from the last version posted, I just corrected a few details and removed the sensePin pinMode calls, these are not needed since you are using the pins as analog inputs. Also removed the “magic number” 5000UL time value and moved it to a define.

// Program will sense a closed circuit and turn on a relay for 5 seconds
// there are 4 circuits in all, Program must be able to fire a relay
// regardless of the state of the other 3.

#define timeSetpoint 5000UL   // in miliseconds

//these pins go to the relay
const int ledPin1 = 6;
const int ledPin2 = 5;
const int ledPin3 = 4;
const int ledPin4 = 3;

//these pins go out to the sticker circuit
const int sensePin1 = A0;
const int sensePin2 = A1;
const int sensePin3 = A2;
const int sensePin4 = A3;

enum state {
  NO_OBJECT_IN_PANEL,
  LED_ON,
  ALL_DONE,
};

state state1 = NO_OBJECT_IN_PANEL;
state state2 = NO_OBJECT_IN_PANEL;
state state3 = NO_OBJECT_IN_PANEL;
state state4 = NO_OBJECT_IN_PANEL;

uint32_t startTime_ms1;
uint32_t startTime_ms2;
uint32_t startTime_ms3;
uint32_t startTime_ms4;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  pinMode(ledPin3, OUTPUT);
  pinMode(ledPin4, OUTPUT);
}

void loop() {
  // these values determine if the circuit is open or closed
  int val1 = analogRead(sensePin1);
  int val2 = analogRead(sensePin2);
  int val3 = analogRead(sensePin3);
  int val4 = analogRead(sensePin4);

  switch (state1) {
    case NO_OBJECT_IN_PANEL:
      if (val1 > 25) {
        digitalWrite(ledPin1, HIGH);
        startTime_ms1 = millis();
        state1 = LED_ON;
      }
      break;
    case LED_ON:
      if (millis() - startTime_ms1 >= timeSetpoint) {
        digitalWrite(ledPin1, LOW);
        state1 = ALL_DONE;
      }
      break;
    case ALL_DONE:
      break;
  }

  switch (state2) {
    case NO_OBJECT_IN_PANEL:
      if (val2 > 25) {
        digitalWrite(ledPin2, HIGH);
        startTime_ms2 = millis();
        state2 = LED_ON;
      }
      break;
    case LED_ON:
      if (millis() - startTime_ms2 >= 5000UL) {
        digitalWrite(ledPin2, LOW);
        state2 = ALL_DONE;
      }
      break;
    case ALL_DONE:
      break;
  }

  switch (state3) {
    case NO_OBJECT_IN_PANEL:
      if (val3 > 25) {
        digitalWrite(ledPin3, HIGH);
        startTime_ms3 = millis();
        state3 = LED_ON;
      }
      break;
    case LED_ON:
      if (millis() - startTime_ms3 >= timeSetpoint) {
        digitalWrite(ledPin3, LOW);
        state3 = ALL_DONE;
      }
      break;
    case ALL_DONE:
      break;
  }

  switch (state4) {
    case NO_OBJECT_IN_PANEL:
      if (val4 > 25) {
        digitalWrite(ledPin4, HIGH);
        startTime_ms4 = millis();
        state4 = LED_ON;
      }
      break;
    case LED_ON:
      if (millis() - startTime_ms4 >= timeSetpoint) {
        digitalWrite(ledPin4, LOW);
        state4 = ALL_DONE;
      }
      break;
    case ALL_DONE:
      break;
  }

  if (state1 == ALL_DONE && state2 == ALL_DONE && state3 == ALL_DONE && state4 == ALL_DONE ) {
    if (val1 < 25 && val2 < 25 && val3 < 25 && val4 < 25) {
      state1 = NO_OBJECT_IN_PANEL;
      state2 = NO_OBJECT_IN_PANEL;
      state3 = NO_OBJECT_IN_PANEL;
      state4 = NO_OBJECT_IN_PANEL;
    }
  }
}

It’s getting late here (NY time) so I will not be checking back in until the morning. Good luck.

i sincerely appreciate your guidance here. Thank you again.

So it sounds like i should move away from the A0-A3 for my inputs. I will do that.
The "stickers" are these LED lights...

I have to use them... I just read the "val1" from the serial monitor to find out what number is on.
I'm using a 5ohm resistor to stabilize the number. Without it i get wild fluctuations when off. not 'zero'

I think you are right on about my inputs. I will play with them and see if i can make your code work for me.

you are the best!

This may sound circular in thinking (because it is) but are you trying to turn the LED on with the switching of the output when the same LED is sensed in place via the analog input?

If so, I'll have to cogitate on that one for a bit...

As a side note, I originally tested the logic using digital inputs, this was due to noise issues with the analog. Here is the same sketch using those digital inputs. It uses the "INPUT_PULLUP" feature of the processor so you don't have to add external resistors. The only thing that may be confusing is that the inputs are active LOW, not active HIGH. This may be exactly what you want because the input should be pulled low (~2 volts) when an LED is in place from the input to ground.

The result of this reversed logic is that you have to flip the input test using the NOT (!) operator. It's one of many almost invisible things until you're fluent in C/C++.

// Program will sense a closed circuit and turn on a relay for 5 seconds
// there are 4 circuits in all, Program must be able to fire a relay
// regardless of the state of the other 3.

#define timeSetpoint 5000UL   // in miliseconds

//these pins go to the relay
const int ledPin1 = 6;
const int ledPin2 = 5;
const int ledPin3 = 4;
const int ledPin4 = 3;

//these pins go out to the sticker circuit
const int sensePin1 = 8;
const int sensePin2 = 9;
const int sensePin3 = 10;
const int sensePin4 = 11;

enum state {
  NO_OBJECT_IN_PANEL,
  LED_ON,
  ALL_DONE,
};

state state1 = NO_OBJECT_IN_PANEL;
state state2 = NO_OBJECT_IN_PANEL;
state state3 = NO_OBJECT_IN_PANEL;
state state4 = NO_OBJECT_IN_PANEL;

uint32_t startTime_ms1;
uint32_t startTime_ms2;
uint32_t startTime_ms3;
uint32_t startTime_ms4;

void setup() {
  Serial.begin(9600);
  pinMode(sensePin1, INPUT_PULLUP);
  pinMode(sensePin2, INPUT_PULLUP);
  pinMode(sensePin3, INPUT_PULLUP);
  pinMode(sensePin4, INPUT_PULLUP);
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  pinMode(ledPin3, OUTPUT);
  pinMode(ledPin4, OUTPUT);
}

void loop() {

  switch (state1) {
    case NO_OBJECT_IN_PANEL:
      if (!digitalRead(sensePin1)) {
        digitalWrite(ledPin1, HIGH);
        startTime_ms1 = millis();
        state1 = LED_ON;
      }
      break;
    case LED_ON:
      if (millis() - startTime_ms1 >= timeSetpoint) {
        digitalWrite(ledPin1, LOW);
        state1 = ALL_DONE;
        Serial.println("C1 Done");
      }
      break;
    case ALL_DONE:
      break;
  }

  switch (state2) {
    case NO_OBJECT_IN_PANEL:
      if (!digitalRead(sensePin2)) {
        digitalWrite(ledPin2, HIGH);
        startTime_ms2 = millis();
        state2 = LED_ON;
      }
      break;
    case LED_ON:
      if (millis() - startTime_ms2 >= timeSetpoint) {
        digitalWrite(ledPin2, LOW);
        state2 = ALL_DONE;
        Serial.println("C2 Done");
      }
      break;
    case ALL_DONE:
      break;
  }

  switch (state3) {
    case NO_OBJECT_IN_PANEL:
      if (!digitalRead(sensePin3)) {
        digitalWrite(ledPin3, HIGH);
        startTime_ms3 = millis();
        state3 = LED_ON;
      }
      break;
    case LED_ON:
      if (millis() - startTime_ms3 >= timeSetpoint) {
        digitalWrite(ledPin3, LOW);
        state3 = ALL_DONE;
        Serial.println("C3 Done");
      }
      break;
    case ALL_DONE:
      break;
  }

  switch (state4) {
    case NO_OBJECT_IN_PANEL:
      if (!digitalRead(sensePin4)) {
        digitalWrite(ledPin4, HIGH);
        startTime_ms4 = millis();
        state4 = LED_ON;
      }
      break;
    case LED_ON:
      if (millis() - startTime_ms4 >= timeSetpoint) {
        digitalWrite(ledPin4, LOW);
        state4 = ALL_DONE;
        Serial.println("C4 Done");
      }
      break;
    case ALL_DONE:
      break;
  }

  if (state1 == ALL_DONE && state2 == ALL_DONE && state3 == ALL_DONE && state4 == ALL_DONE ) {
    if (digitalRead(sensePin1) && digitalRead(sensePin2) && digitalRead(sensePin3) && digitalRead(sensePin4)) {
      Serial.println("Reset All");
      state1 = NO_OBJECT_IN_PANEL;
      state2 = NO_OBJECT_IN_PANEL;
      state3 = NO_OBJECT_IN_PANEL;
      state4 = NO_OBJECT_IN_PANEL;
    }
  }
}

avr_fred:
This may sound circular in thinking (because it is) but are you trying to turn the LED on with the switching of the output when the same LED is sensed in place via the analog input?

If so, I'll have to cogitate on that one for a bit...

The Sticker must stay lit for the duration. yes. Its quite a challenge.

avr_fred

this guy Cs

amazing…

It's one of many almost invisible things until you're fluent in C/C++.

Avr_fred you are amazing. I am also on this project with Joe, I just set up the board with your code and attached to the relays and am running it off the adafruit trinket. It works great! I was just wondering if you can send more current through the digital out pins or not as much resistance on the input pullup because the led on the sticker isn't very bright. It does not seem like it is reading a value anymore but only reading a closed circuit.I found out that these are 5v neopixel lights on these circuit stickers. Can you change the value of the input pullup and still get the code to read the same way?

INPUT_PULLUP is fixed, you cannot change its value. If you need higher pullup current, turn off the internal resistor and use an external resistor.

Overall, I need a better understanding of the project. Could you answer these questions please?

  1. Are we dealing with a total of four LED’s or eight?
  2. If four LED’s, the same LED’s that are input devices are the output devices, correct?
  3. If four LED’s, do you have the Trinket input pin tied together with the output pin, correct?
  4. Which model and voltage Adafruit Trinket? Mini, Pro, etc. 3.3 or 5 volts?
  5. Do you have a multimeter available? Analog or Digital?

Questions 1, 2 and 3 would be best answered with a schematic but if that is not available, I understand.

BTW, these are not Neopixels. Just single element LED chip with a resistor in series. Neopixels have red, blue and green chips along with a driver IC in a square surface mount package. This is the most common package:

rsz_1655-03.jpg

Here is my schematic and circuit that is running right now.

1)4 Leds 4 relays
2)no, the leds are the inputs the relays are the out puts. On the Relays I have RGBW 12v led strips but I only need white and blue so that is my high and low switcher
3)yes
4)5v Pro Trinket
5)yes digital multi meter

Oh thanks for the input on the neopixels, I have some strips and I read on the site it was the same type of light as but because it is one color per light it would not be considered neopixel. :sweat_smile: :sweat_smile:

Thanks!

Thank you for the information, very helpful.

If you want the sticker LED’s to be on at full brightness and act as a switch at the same time, you’ll need to add some parts to make this work, an NPN transistor and a resistor. Diagram below.

The full current of the LED (10ma or so) flows through the base to emitter junction of the transistor, turning the transistor on which sinks current through the INPUT_PULLUP resistor connected to the input of the Trinket. The Trinket input goes low when the sticker is in place, high when missing. The 10k resistor from base to ground is to prevent false triggering due to the 60hz noise transmitted through human contact. It’s questionable as to it be absolutely needed, I could not saturate a 2N3904 by touching the base but I could see noise on the collector when touched so I figured it would do no harm. Better to have it and not need it than to need it and not have it…

Good luck.

LED Switch.jpg

Edit: As an afterthought, you might need another resistor, about 100 ohms in series with the +5V supply. This will reduce the LED brightness a bit but it will prevent damage to the transistor. Should the base of the transistor be connected directly to +5 volts, too much current will flow and it will damage (short) the transistor. The value could be optimized as low as practical for best brightness - but only when you know the specific transistor being used.

I don’t know if this condition can occur without seeing the back side of the stickers but I’d rather you didn’t find out the hard way…

eagon:
Here is my schematic and circuit that is running right now.

Dangerous (for the Pro Trinket) to power that many relays from the board.
Each relay uses ~80mA when active, and the Trinked seems to have a 500mA absolute max backflow protection diode in series with USB supply. Five or more relays active could release the magic smoke.
Leo..