Cannot get relay to start in off position. Simple code and i'm a noob

Hi all,

I just discovered what Arduino can do for my Postwar (1945-1969) Lionel train layout and also my HO layout. I am now trying to learn to code basic things. Not my strong suite. I am a very hands on mechanical person.

I am creating a very basic blinking code to flash an old Lionel (incandescent bulbs) crossing signal. The bulbs will alternate on/off every 600ms and will be triggered by an IR sensor.

I actually have this working. I can block the sensor and the relay opens and closes as it should until I remove my hand from the sensor.

The only thing I am trying to figure out is how to make it so the relay starts in an off position. Meaning it is not ON to start with. The light on the board should be off and not on. I don’t want the relay in an almost constant coil powered state.

My hardware is an Elegoo Uno R3, JBtek 8 ch 5v Arduino relay board, a breadboard and a GikFun IR sensor.

When the Arduino first boots up the relay is in an ON condition. If I trigger the circuit with the sensor it will then always cycle to the OFF condition once the trigger (my hand) is removed. I just cannot figure out how to get the relay to be in the OFF condition upon bootup.

I have tried different if val statements to try and get the relay to be in the OFF condition upon bootup, but I just cannot figure it out.

I have ordered 3 Elegoo Nano’s and a 5 pack of 5v relay boards to actually implement this project once working plus have extra stuff for other train automations.

Any help would be greatly appreciated. I’m sure this is extremely basic for those of you who really understand the code.

Here is my code:

Again, it is working as I want except the relay always starts in the ON condition on boot and until triggered the first time and then it always goes to the OFF condition after the trigger is removed.

int sensor = A0;
int relay = 2;

void setup() {
  pinMode(relay, OUTPUT);
  Serial.begin(9600);

}

void loop() {
  int valA1 = analogRead(sensor);
  Serial.println(valA1);

  if (valA1 < 500) {
    digitalWrite(relay, LOW);
    delay(600);
    digitalWrite(relay, HIGH);
    delay(600);

  }
}
#define relayOFF  LOW  //use HIGH to invert the level

int sensor = A0;
int relay = 2;

void setup() 
{
  pinMode(relay, OUTPUT);
  digitalWrite(relay, relayOFF);

  Serial.begin(9600);

} //END of setup()

void loop() 
{
  int valA1 = analogRead(sensor);
  Serial.println(valA1);

  if (valA1 < 500) 
  {
    //toggle the relay state
    digitalWrite(relay, !digitalRead(relay));
    delay(500);
  }

  else
   {
    digitalWrite(relay, relayOFF);
   }

} //END of loop()

Note: delay() freezes normal program flow for the delay time period.

Learn to use the BWD (Blink Without Delay) technique to make none blocking timers.

Thank you! I will check that out.

some relay-boards are in state "switched-on" when no voltage is feeded into the input.

To determine if this is the case you should write a small testprogram that switches the output only every 5 seconds.

Check the relay-switch-state with the multimeter
a) nothing connected to the relay-board
b) IO-pin switched low
c) IO-pin switched HIGH

Do you have a digital multimeter? (I guess yes if you are building modelrailways)
If not this is the right time to buy one. Any cheap type in the $20 class will do in most cases.
If you want to measure 10A or 20A take a DMM that can measure this.

If you can afford $60 I recommend this one

a lot of measurement possabilities including frequency and duty-cycle plus bluetooth recording

On boot-up all IO-Pins are switched as input. This could cause the relay to switch on.
You can supress this through a pull-down-resistor.
Can you provide a datasheet of exact your relay-board? Some of these chinese-boards are not fully opto-isolated by default which is the dumbest "feature" I have ever seen. On some of these boards the GND-connection can be cutted off.
8 relay each with 20 mA = 160 mA of current drive the Arduino-Onboard-Voltage-regulator near to his limits.
So it is a good idea to use an external 5V voltage-supply instead of just connecting the +5V of the relayboard to the Arduino+5V-connector.

best regards Stefan

Hi Stefan,

Thank you for the reply. I do have a digital multimeter and even a couple old O-scopes. Not that I can use alot of there functions. lol.

I do not have a data sheet for the relay board, but maybe this will help. When I use the sketch posted below the relays will start off in the OFF state. Both of my sketches are insanely simple, so I don’t understand why one will start the relays in the OFF state, but the other, even more simple sketch will not.

int sensor=A0; //Sets pin  A0 as our sensor input.
int relay1=2; //sets digital pin 2 as our relay control.
int relay2=3;
int relay3=4;

void setup(){
  Serial.begin(9600);//starts up the serial monitor.
  pinMode(relay1,OUTPUT);
  pinMode(relay2,OUTPUT);
  pinMode(relay3,OUTPUT);
  
}

void loop(){
int valA1 = analogRead(sensor);//Sets valA1 as whatever the sensor reads
Serial.println(valA1);

if (valA1<500){
  digitalWrite(relay1,LOW);//sets the relay to cut the power to the track
  digitalWrite(relay2,LOW);
  digitalWrite(relay3,LOW);
  delay(3000);

}

if (valA1>500){
  digitalWrite(relay1,HIGH);//keeps the power on while the sensor is not tripped
  digitalWrite(relay2,HIGH);
  digitalWrite(relay3,HIGH);
}
}

Notice that, unless valA1 is precisely 500 (unlikely), a digitalWrite(…) occurs that sets the state of the relay. This is not provided in the simple sketch, at least not until you incorporate the suggestion from larryd.
To avoid missing a case, you should learn to use “else”:

if (valA1<500) {
  digitalWrite(relay1,LOW);//sets the relay to cut the power to the track
  digitalWrite(relay2,LOW);
  digitalWrite(relay3,LOW);
  delay(3000);
} else {
  digitalWrite(relay1,HIGH);//keeps the power on while the sensor is not tripped
  digitalWrite(relay2,HIGH);
  digitalWrite(relay3,HIGH);
}

Also, valA1 is a terrible name. Something like vacantTrackLightSensorReading might be better. It is longer but explains what it does.

To determine when the relay is switched ON/OFF the sketch should be even more simple to narrow down on the bareminimum of variable conditions

run this code and report the results

int relay1 = 2; //sets digital pin 2 as our relay control.
int relay2 = 3;
int relay3 = 4;

boolean TimePeriodIsOver (unsigned long &expireTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();  
  if ( currentMillis - expireTime >= TimePeriod )
  {
    expireTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  } 
  else return false;            // not expired
}

unsigned long MyTestTimer = 0;                   // variables MUST be of type unsigned long
const byte OnBoard_LED = 13;


void setup(){
  Serial.begin(9600);//starts up the serial monitor.
  Serial.println("setup-Start");
  pinMode(relay1,OUTPUT);
  digitalWrite(relay1,LOW);

  pinMode(relay2,OUTPUT);
  digitalWrite(relay2,LOW);
  
  pinMode(relay3,OUTPUT); 
  digitalWrite(relay3,LOW);

  pinMode(OnBoard_LED,OUTPUT); 
  Serial.println("pinMode(relay3,OUTPUT)");
  Serial.println("digitalWrite(relay3,LOW)");
}

bool LED_State = LOW;

void loop(){

  if ( TimePeriodIsOver(MyTestTimer,3000) ) {
    
    if (LED_State == LOW) {
      Serial.println("digitalWrite(relay1,2,3,LOW)");
      digitalWrite(relay1,LOW);
      digitalWrite(relay2,LOW);
      digitalWrite(relay3,LOW);
      digitalWrite(OnBoard_LED,LOW);
      LED_State = HIGH;
    }
    else {
      Serial.println("digitalWrite(relay1,2,3,HIGH)");
      digitalWrite(relay1,HIGH);
      digitalWrite(relay2,HIGH);
      digitalWrite(relay3,HIGH);
      digitalWrite(OnBoard_LED,HIGH);
      
      LED_State = LOW;      
    }
        
  }

}

best regards Stefan

StefanL38:
To determine when the relay is switched ON/OFF the sketch should be even more simple to narrow down on the bareminimum of variable conditions

run this code and report the results

int relay1 = 2; //sets digital pin 2 as our relay control.

int relay2 = 3;
int relay3 = 4;

boolean TimePeriodIsOver (unsigned long &expireTime, unsigned long TimePeriod) {
 unsigned long currentMillis  = millis();  
 if ( currentMillis - expireTime >= TimePeriod )
 {
   expireTime = currentMillis; // set new expireTime
   return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
 }
 else return false;            // not expired
}

unsigned long MyTestTimer = 0;                   // variables MUST be of type unsigned long
const byte OnBoard_LED = 13;

void setup(){
 Serial.begin(9600);//starts up the serial monitor.
 Serial.println(“setup-Start”);
 pinMode(relay1,OUTPUT);
 digitalWrite(relay1,LOW);

pinMode(relay2,OUTPUT);
 digitalWrite(relay2,LOW);
 
 pinMode(relay3,OUTPUT);
 digitalWrite(relay3,LOW);

pinMode(OnBoard_LED,OUTPUT);
 Serial.println(“pinMode(relay3,OUTPUT)”);
 Serial.println(“digitalWrite(relay3,LOW)”);
}

bool LED_State = LOW;

void loop(){

if ( TimePeriodIsOver(MyTestTimer,3000) ) {
   
   if (LED_State == LOW) {
     Serial.println(“digitalWrite(relay1,2,3,LOW)”);
     digitalWrite(relay1,LOW);
     digitalWrite(relay2,LOW);
     digitalWrite(relay3,LOW);
     digitalWrite(OnBoard_LED,LOW);
     LED_State = HIGH;
   }
   else {
     Serial.println(“digitalWrite(relay1,2,3,HIGH)”);
     digitalWrite(relay1,HIGH);
     digitalWrite(relay2,HIGH);
     digitalWrite(relay3,HIGH);
     digitalWrite(OnBoard_LED,HIGH);
     
     LED_State = LOW;      
   }
       
 }

}



best regards Stefan

Hi Stefan,
Thank you so much for your help. I am sorry I am confusing you and probably others. I will try try to be more clear.
The sketch you modified above was just a basic 3 relay on and off using a sensor. It was not intended to blink. It started as a single relay sketch and I was trying to learn so I added 2 more. What that sketch does do is boot up with the relays in the OFF state.
Now here is my very simple blink sketch. For blinking 2 incandescent bulbs via a relay. With this sketch the relay starts in the ON state.

int sensor = A0;
int relay = 2;

void setup() {
  Serial.begin(9600);
  pinMode(relay, OUTPUT);
}

void loop() {
  int valA1 = analogRead(sensor);
  Serial.println(valA1);

  if (valA1<500){
    digitalWrite(relay,LOW);
    delay(600);
    digitalWrite(relay,HIGH);
    delay(600);
}
}

I can load each sketch back to back and the 3 relay sketch (not the one I want to use) will start with the relay in the OFF state and the other will start with the relay in the ON state. I want it to start in the OFF state.
I do not understand the difference in the sketches that is causing this.

vaj4088:
Notice that, unless valA1 is precisely 500 (unlikely), a digitalWrite(…) occurs that sets the state of the relay. This is not provided in the simple sketch, at least not until you incorporate the suggestion from larryd.
To avoid missing a case, you should learn to use “else”:

if (valA1<500) {

digitalWrite(relay1,LOW);//sets the relay to cut the power to the track
 digitalWrite(relay2,LOW);
 digitalWrite(relay3,LOW);
 delay(3000);
} else {
 digitalWrite(relay1,HIGH);//keeps the power on while the sensor is not tripped
 digitalWrite(relay2,HIGH);
 digitalWrite(relay3,HIGH);
}





Also, valA1 is a terrible name. Something like vacantTrackLightSensorReading might be better. It is longer but explains what it does.

Hi Vaj,
Thank you for the reply.
The name is like it is because I found this on youtube for basic train Arduino projects. I am literally a 5 day noob to this.
What i do not understand is that why the sketch with 3 relays will start in the OFF state, but the very simple blink sketch will not. Both have the same value.
Just for the record I am not quite as stupid as it may appear. lol. This coding thing though… :o

Hi vrdaddy,

I took your code changed the delays to bigger values to make it easier to follow the program-execution
and added serial-output for this

I added a

  digitalWrite(relay, LOW);

in the setup-function after a delay so you can follow if this initial set outout low makes the difference

and I added sewrialoutput that makes visible if the if-condition evaluates to true or to false

Now with this code you should be able to narrow down what is going on.

The variablename "valA!"is free choosable it could be even “blablblagrrrrjhgjhgh” which makes no sense but the compiler won’t care

int sensor = A0;
int relay = 2;

void setup() {
  Serial.begin(9600);
  Serial.println("Setup-Start");
  pinMode(relay, OUTPUT);
  Serial.println("pinMode(relay, OUTPUT);");
  Serial.println("1: now delaying for 3 seconds");
  delay(3000);
    digitalWrite(relay, LOW);
  Serial.println("digitalWrite(relay, LOW);");
  Serial.println("2: now delaying for 3 seconds");
}

void loop() {
  int MySensorValue = analogRead(sensor);
  Serial.println(MySensorValue);

  if (MySensorValue < 500) {
    Serial.print("3: if (MySensorValue < 500) is true MySensorValue=");
    Serial.println(MySensorValue);
    digitalWrite(relay, LOW);
    Serial.println("4: digitalWrite(relay, LOW);");
    Serial.println("5: now delaying for 5 seconds");
    delay(5000);
    digitalWrite(relay, HIGH);
    Serial.println("6: digitalWrite(relay, HIGH);");
    Serial.println("7: now delaying for 5 seconds");
    delay(5000);
  }
  else {
    Serial.print("8: MySensorValue < 500) false!! nothing to do MySensorValue=");
    Serial.println(MySensorValue);
    Serial.println("9: now delaying for 1 second");
    delay(1000);    
  }
}

best regards Stefan

StefanL38:
Hi vrdaddy,

I took your code changed the delays to bigger values to make it easier to follow the program-execution
and added serial-output for this

I added a

  digitalWrite(relay, LOW);

in the setup-function after a delay so you can follow if this initial set outout low makes the difference

and I added sewrialoutput that makes visible if the if-condition evaluates to true or to false

Now with this code you should be able to narrow down what is going on.

The variablename "valA!"is free choosable it could be even “blablblagrrrrjhgjhgh” which makes no sense but the compiler won’t care

int sensor = A0;

int relay = 2;

void setup() {
 Serial.begin(9600);
 Serial.println(“Setup-Start”);
 pinMode(relay, OUTPUT);
 Serial.println(“pinMode(relay, OUTPUT);”);
 Serial.println(“1: now delaying for 3 seconds”);
 delay(3000);
   digitalWrite(relay, LOW);
 Serial.println(“digitalWrite(relay, LOW);”);
 Serial.println(“2: now delaying for 3 seconds”);
}

void loop() {
 int MySensorValue = analogRead(sensor);
 Serial.println(MySensorValue);

if (MySensorValue < 500) {
   Serial.print(“3: if (MySensorValue < 500) is true MySensorValue=”);
   Serial.println(MySensorValue);
   digitalWrite(relay, LOW);
   Serial.println(“4: digitalWrite(relay, LOW);”);
   Serial.println(“5: now delaying for 5 seconds”);
   delay(5000);
   digitalWrite(relay, HIGH);
   Serial.println(“6: digitalWrite(relay, HIGH);”);
   Serial.println(“7: now delaying for 5 seconds”);
   delay(5000);
 }
 else {
   Serial.print(“8: MySensorValue < 500) false!! nothing to do MySensorValue=”);
   Serial.println(MySensorValue);
   Serial.println(“9: now delaying for 1 second”);
   delay(1000);    
 }
}



best regards Stefan

Hi Stefan,
I was able to see everything, but the results are still the same. It appears, according to the serial monitor, that the relay should start in the OFF state. It does not. Why does my other 3 relay sketch start all 3 (or 1 if 2 relays removed) in the OFF state? This makes no sense to me.
Here is the log of the startup from the serial monitor.
Setup-Start
pinMode(relay, OUTPUT);
1: now delaying for 3 seconds
digitalWrite(relay, LOW);
2: now delaying for 3 seconds
1020
8: MySensorValue < 500) false!! nothing to do MySensorValue=1020
9: now delaying for 1 second
1020
8: MySensorValue < 500) false!! nothing to do MySensorValue=1020
9: now delaying for 1 second
1020

…UPDATE AS I WAS TYPING…

I was trying different things and this somehow worked! It now boots with the relay in an OFF state. The sketch now does exactly what I want it to do, but why? I want to learn. Do you understand why this is happening?

Is it possible HIGH and LOW are reversed and HIGH is OFF and LOW is ON? I did try switching them early on and it made no difference.

int sensor=A0;
int relay=2;

void setup(){
  Serial.begin(9600);
  pinMode(relay,OUTPUT);
  
}

void loop(){
int valA1 = analogRead(sensor);
Serial.println(valA1);

if (valA1<500){
  digitalWrite(relay,LOW);
  delay(600);
  digitalWrite(relay,HIGH);
  delay(600);
  
}

if (valA1>500){
  digitalWrite(relay,HIGH);
}
}

Thanks again everyone for all your help.

Most/common relay boards with opto couplers briefly turn on when the Arduino powers up.
You can avoid that by first enabling internal pull up on the pin before you set the pin to output.
Like this.

const byte relay1Pin = 2;

void setup() {
  pinMode(relay1Pin, INPUT_PULLUP); // first enable pull up
  pinMode(relay1pin, OUTPUT); // then set pin to output
}

#define relayOFF is IMHO a silly thing to do.
Just learn and accept that LOW is ON.
Leo..

Wawa:
Most/common relay boards with opto couplers briefly turn on when the Arduino powers up.
You can avoid that by first enabling internal pull up on the pin before you set the pin to output.
Like this.

const byte relay1Pin = 2;

void setup() {
 pinMode(relay1Pin, INPUT_PULLUP); // first enable pull up
 pinMode(relay1pin, OUTPUT); // then set pin to output
}



Leo..

Thanks, I will try that instead of my last "if" line if that works or use it in conjunction with my last "if" line if that is a better way to boot relay board/s
Also, I think HIGH and LOW are "reversed". When I change the last line to LOW the relay starts in the ON state. When I change the last line to HIGH the relay starts in the OFF state.
Also, my serial monitor for my sensor starts with a high number (1022) and triggers as a low (22) number, so that makes sense.

Hi all,

Thank you everyone for their help and input.

In the end my entire problem stemmed from me not realizing that HIGH was OFF. I had it reversed in my head.

My sketch is working exactly how I want it to including a second relay as a trigger for the negative connection on my crossing signal (Lionel no. 154).

Thanks again for all the help.

I am attaching my sketch in case it helps someone else. I don’t know if it is “correct”, but it works perfect for my project.

int sensor=A0;
int relay1=2;
int relay2=3;

void setup(){
  Serial.begin(9600);
  pinMode(relay1,OUTPUT);
  pinMode(relay2,OUTPUT);
}

void loop(){
int valA1 = analogRead(sensor);
Serial.println(valA1);

if (valA1<500){
  digitalWrite(relay2,LOW);
  digitalWrite(relay1,LOW);
  delay(600);
  digitalWrite(relay1,HIGH);
  delay(600);
}

if (valA1>500){
  digitalWrite(relay1,HIGH);
  digitalWrite(relay2,HIGH);
}
}

try

const int ON = LOW;
const int OFF = HIGH;
...
digitalWrite(relay1,OFF);

You didn't use the pull up trick in setup(), so the relays may still activate briefly on bootup.
This is what setup should look like.

void setup(){
  Serial.begin(9600);
  pinMode(relay1, INPUT_PULLUP);
  pinMode(relay2, INPUT_PULLUP);
  pinMode(relay1, OUTPUT);
  pinMode(relay2, OUTPUT);
}

Leo..

vrdaddy:
In the end my entire problem stemmed from me not realizing that HIGH was OFF. I had it reversed in my head.

For relay, The relation between ON/OFF and HIGH/LOW depends on Normal Open or Normal Closed. See Arduino - Relay tutorial for detail

IoT_hobbyist:
For relay, The relation between ON/OFF and HIGH/LOW depends on Normal Open or Normal Closed. See Arduino - Relay tutorial for detail

The NO/NC labels are true when the relay coil is not activated.
Most/common opto relay modules activate the relay coil when the module input is LOW.

Some modules are "active HIGH", and some can be switched to active LOW or active HIGH with a jumper.
The tutorial you linked to is using the less common active HIGH module, adding to the confusion.
Leo..