Skip lines of code if requirements are given

Hi,

I'm pretty new to the whole Arduino thing and programming in general.
What I'm trying to do right now is reading an input on PIN13. Based on that input (HIGH or LOW) the Arduino is supposed to switch on (PIN13 == HIGH) or off (PIN13 == LOW) the PINs A0-A5 with a delay of 1sec between each PIN.
My first code looked like this:

const int Thermostat = 13;
const int Sieder1 =  A0;
const int Sieder2 =  A1;
const int Sieder3 =  A2;
const int Sieder4 =  A3;
const int Sieder5 =  A4;
const int Sieder6 =  A5;


int buttonState = 0;
int Sieder1State = 0;
int Sieder2State = 0;
int Sieder3State = 0;
int Sieder4State = 0;
int Sieder5State = 0;
int Sieder6State = 0;

void setup() {
  pinMode(Thermostat, INPUT);
  pinMode(Sieder1, OUTPUT);
  pinMode(Sieder2, OUTPUT);
  pinMode(Sieder3, OUTPUT);
  pinMode(Sieder4, OUTPUT);
  pinMode(Sieder5, OUTPUT);
  pinMode(Sieder6, OUTPUT);
}

void loop() {
  buttonState = digitalRead(Thermostat);
  Sieder1State = digitalRead(Sieder1);
  Sieder2State = digitalRead(Sieder2);
  Sieder3State = digitalRead(Sieder3);
  Sieder4State = digitalRead(Sieder4);
  Sieder5State = digitalRead(Sieder5);
  Sieder6State = digitalRead(Sieder6);
  
  delay(50);
  if (buttonState == HIGH) {
    
    if (Sieder1State == LOW) {
    digitalWrite(Sieder1, HIGH);
    delay(1000);
    }
    if (Sieder2State == LOW) {
    digitalWrite(Sieder2, HIGH);
    delay(1000);
    }
    if (Sieder3State == LOW) {
    digitalWrite(Sieder3, HIGH);
    delay(1000);
    }
    if (Sieder4State == LOW) {
    digitalWrite(Sieder4, HIGH);
    delay(1000);
    }
    if (Sieder5State == LOW) {
    digitalWrite(Sieder5, HIGH);
    delay(1000);
    }
    if (Sieder6State == LOW) {
    digitalWrite(Sieder6, HIGH);
    delay(1000);
    }
    
  } else {
    
    if (Sieder1State == HIGH) {
    digitalWrite(Sieder1, LOW);
    delay(1000);
    }
    if (Sieder2State == HIGH) {
    digitalWrite(Sieder2, LOW);
    delay(1000);
    }
    if (Sieder3State == HIGH) {
    digitalWrite(Sieder3, LOW);
    delay(1000);
    }
    if (Sieder4State == HIGH) {
    digitalWrite(Sieder4, LOW);
    delay(1000);
    }
    if (Sieder5State == HIGH) {
    digitalWrite(Sieder5, LOW);
    delay(1000);
    }
    if (Sieder6State == HIGH) {
    digitalWrite(Sieder6, LOW);
    }
  }
}

The problem there was that it had to complete the entire loop before it startet reading the state of PIN13 again. So I decided to add the if-function to each output:

const int Thermostat = 13;
const int Sieder1 =  A0;
const int Sieder2 =  A1;
const int Sieder3 =  A2;
const int Sieder4 =  A3;
const int Sieder5 =  A4;
const int Sieder6 =  A5;


int buttonState = 0;
int Sieder1State = 0;
int Sieder2State = 0;
int Sieder3State = 0;
int Sieder4State = 0;
int Sieder5State = 0;
int Sieder6State = 0;

void setup() {
  pinMode(Thermostat, INPUT);
  pinMode(Sieder1, OUTPUT);
  pinMode(Sieder2, OUTPUT);
  pinMode(Sieder3, OUTPUT);
  pinMode(Sieder4, OUTPUT);
  pinMode(Sieder5, OUTPUT);
  pinMode(Sieder6, OUTPUT);
}

void loop() {
  buttonState = digitalRead(Thermostat);
  Sieder1State = digitalRead(Sieder1);
  Sieder2State = digitalRead(Sieder2);
  Sieder3State = digitalRead(Sieder3);
  Sieder4State = digitalRead(Sieder4);
  Sieder5State = digitalRead(Sieder5);
  Sieder6State = digitalRead(Sieder6);
  
  delay(50);
  if (buttonState == HIGH) {
    
    if (buttonState == HIGH && Sieder1State == LOW) {
    digitalWrite(Sieder1, HIGH);
    delay(1000);
    }
    if (buttonState == HIGH && Sieder2State == LOW) {
    digitalWrite(Sieder2, HIGH);
    delay(1000);
    }
    if (buttonState == HIGH && Sieder3State == LOW) {
    digitalWrite(Sieder3, HIGH);
    delay(1000);
    }
    if (buttonState == HIGH && Sieder4State == LOW) {
    digitalWrite(Sieder4, HIGH);
    delay(1000);
    }
    if (buttonState == HIGH && Sieder5State == LOW) {
    digitalWrite(Sieder5, HIGH);
    delay(1000);
    }
    if (buttonState == HIGH && Sieder6State == LOW) {
    digitalWrite(Sieder6, HIGH);
    delay(1000);
    }
    if (buttonState == LOW && Sieder1State == HIGH) {
    digitalWrite(Sieder1, LOW);
    delay(1000);
    }
    if (buttonState == LOW && Sieder2State == HIGH) {
    digitalWrite(Sieder2, LOW);
    delay(1000);
    }
    if (buttonState == LOW && Sieder3State == HIGH) {
    digitalWrite(Sieder3, LOW);
    delay(1000);
    }
    if (buttonState == LOW && Sieder4State == HIGH) {
    digitalWrite(Sieder4, LOW);
    delay(1000);
    }
    if (buttonState == LOW && Sieder5State == HIGH) {
    digitalWrite(Sieder5, LOW);
    delay(1000);
    }
    if (buttonState == LOW && Sieder6State == HIGH) {
    digitalWrite(Sieder6, LOW);
    }
  }
}

But the loop still keeps cycling through every single line and for some reason the outputs don't turn off at all anymore.

What should I do to interupt the loop and turn off the outputs as soon as PIN13 has no voltage anymore?

Adding a check buttonState in all your if statements won't help because you only read it at the top of loop. You have made things worse by removing the else too. The code that turns your outputs off is enclosed inside the if that established that buttonState is HIGH. They check to see if it is low, which it can't be, so they will never be turned off, as you observe.

Thank you for the quick answer.
I already realized that the first code was the better approach, just didn't know why the second one didn't work.
What do I need to add to the first code to interrupt and restart the loop as soon as my input on PIN13 changes? The goal is to start turning the outputs off as soon as the input changes to 0.

This

and this

Does not make sense for several reasons. First why not use the Digital pins and save the Analog and I2C pins for their intended use?

Next if you are going to read the state of a pin then why set it to OUTPUT?

From my understanding of your description is that you want a timed sequenced event to occur based upon an input, correct?

Learn to use millis() for your timing and look up STATE MACHINE.

Learn to shy away from using delay(x) and don't mix delay(x) and millis() for timing.

If you are using an ESP32 solving the matter would be much easier with the built-in multitasking multi processing OS, freeRTOS.

As suggested, you need to maintain some state information. You need to know if you're turning outputs on, turning them off or waiting for something to happen.

Look at the IDE's state change example to check your input. Keep a variable with the output pin number in it that should be changed next. Use millis to decide if it is time to do something.

As a general rule, if you have three or more variables that have the same name except for a sequence number, it's time to use arrays.

const byte PINCOUNT = 6;

const int Thermostat = 13;
const int SiederPins[PINCOUNT] =  {A0, A1, A2, A3, A4, A5};

bool SiederStates[PINCOUNT];

void setup()
{
  pinMode(Thermostat, INPUT);
  for (size_t i = 0; i < PINCOUNT; i++)
  {
    pinMode(SiederPins[i], OUTPUT);
    digitalWrite(SiederPins[i], SiederStates[i]);
  }
}

void loop()
{
  for (size_t i = 0; i < PINCOUNT; i++)
  {
    if (digitalRead(Thermostat) == HIGH && !SiederStates[i])
    {
      SiederStates[i] = true;
      digitalWrite(SiederPins[i], SiederStates[i]);
      delay(1000);
    }

    if (digitalRead(Thermostat) == LOW && SiederStates[i])
    {
      SiederStates[i] = false;
      digitalWrite(SiederPins[i], SiederStates[i]);
      delay(1000);
    }
  }
}
1 Like

Hi oneg,

welcome to the arduino-User-forum and the world of programming.
You will have a lot of fun building up programming-knowledge with the support of the forum.

I estimate that you will have a lot of questions. The users here will answer them.
You made a good start with posting code as a code-section. Well done!

I want to rewrite a description of the functionality you want in my own words to verify If I undestand it right.

IO-Pin 13 is configured as input

if IO-pin 13 is low
switch off several output pins (A0 to A5) with a delay of 1 second one after the other

if IO-pin 13 is HIGH
switch ON several output pins (A0 to A5) with a delay of 1 second one after the other

when ever a change on io-pin 13 occurs
change from switching ON to switching off regardless of how many IO-pins (A0 to A5) are on or off to the new state always with a dleay of 1 second one after the other.

As your sequence of what should happen can change at any time at any state

A0 ON  A1 OFF A2 OFF A3 OFF A4 OFF A5 OFF
A0 ON  A1 ON  A2 OFF A3 OFF A4 OFF A5 OFF
A0 ON  A1 ON  A2 ON  A3 OFF A4 OFF A5 OFF
...
A0 OFF A1 OFF A2 ON  A3 OFF A4 OFF A5 OFF
etc. etc. 

a state-machine is a must.

Your functionality is described easily in words. The programming needs the medium-advanced concept of what is called a state-machine.
because you want to change at any moment to one of two sequences
sequence 1: building up A0, A1, ..A5 ON
sequence2: building up OFF in reversed order to building up ON A5, A4, A3...A0

the basic concept of a state-machine is to jump in and jump out of a part of the program.
This jumping in jumping out enables to do multiple things in (almost) parallel.

the repeating is done by the most outer loop that exists.
The most outer loop is function

void loop()

So as a pseudo-code your functionality looks like this

void loop() {
  byte myInputState = digitalRead(myInputPin );

  if (myInputState == HIGH) {
     do_a_SINGLE_ON_SwitchingStep();
  }
  else { // else means myInputState  == low
     do_a_SINGLE_OFF_SwitchingStep();
  }  
}

the word SINGLE in the functions name is program
jump into the function to do

one single step

of switching on / off the next output or just check if 1 second of time has passed by
and then quickly jump out again
to read-in the input-pin new

This means you have to learn:

  • how non-blocking timing based on function millis() works
  • how state-machines work

This will take some time. It is not done within 5 minutes

pizza-example
as an everyday example with easy to follow numbers
delay() is blocking. As long as the delay is "delaying" nothing else of the code can be executed.
Now there is a technique of non-blocking timing.
The basic principle of non-blocking timing is fundamental different from using delay()

You have to understand the difference first and then look into the code.

otherwise you might try to "see" a "delay-analog-thing" in the millis()-code which it really isn't
Trying to see a "delay-analog-thing" in millis() makes it hard to understand millis()
Having understood the basic principle of non-blocking timing based on millis() makes it easy to understand.

imagine baking a frosted pizza
the cover says for preparation heat up oven to 200°C
then put pizza in.
Baking time 10 minutes

You are estimating heating up needs 3 minutes
You take a look onto your watch it is 13:02 (snapshot of time)
You start reading the newspaper and from time to time looking onto your watch
watch shows 13:02. 13:02 - 13:02 = 0 minutes passed by not yet time
watch shows 13:03. 13:03 - 13:02 = 1 minute passed by not yet time
watch shows 13:04. 13:04 - 13:02 = 2 minutes passed by not yet time

watch shows 13:05 when did I start 13:02? OK 13:05 - 13:02 = 3 minutes time to put pizza into the oven

New basetime 13:05 (the snapshot of time)
watch 13:06 not yet time
watch 13:07 not yet time
watch 13:08 not yet time (13:08 - 13:05 = 3 minutes is less than 10 minutes
watch 13:09 not yet time
watch 13:10 not yet time
watch 13:11 not yet time
watch 13:12 not yet time
watch 13:13 not yet time
watch 13:14 not yet time (13:14 - 13:05 = 9 minutes is less than 10 minutes
watch 13:15 when did I start 13:05 OK 13:15 - 13:05 = 10 minutes time to eat pizza (yum yum)

You did a repeated comparing how much time has passed by
This is what non-blocking timing does

In the code looking at "How much time has passed by" is done

currentTime - startTime >= bakingTime

bakingTime is 10 minutes

13:06 - 13:05 = 1 minute >= bakingTime is false
13:07 - 13:05 = 2 minutes >= bakingTime is false
...
13:14 - 13:05 = 9 minutes >= bakingTime is false
13:15 - 13:05 = 10 minutes >= bakingTime is TRUE time for timed action!!

So your loop() is doing

void loop()
// doing all kinds of stuff like reading the newspaper

if (currentTime - previousTime >= period) {
previousTime = currentTime; // first thing to do is updating the snapshot of time
// time for timed action
}

it has to be coded exactly this way because in this way it manages the rollover from Max back to zero
of the function millis() automatically

As a general advice on the very first day of registration at arduino-forum your postings are limited to 10 postings. You have to do some steps to be allowed to post more
Get to trust level 1 by…

  • Entering at least 5 topics
  • Reading at least 30 posts
  • Spend a total of 10 minutes reading posts

If you have reached the posting-limit start reading this tutorial
Take a look into this tutorial:

Arduino Programming Course

It is easy to understand and has a good mixture between explaining important concepts and example-codes to get you going. So give it a try and report your opinion about this tutorial.

best regards Stefan

1 Like

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