While loop executes more than once

Esteemed colleagues,

I’m trying to to setup a system with a timed execution of a cycle - to raise an output every few hours (the example is set to minutes, but works flawlessly with a 4 hour delay). The program works as expected with one (small) exception: one of the while loops (I’m using two) inside the void loop(), for some reason, is executed twice and I cannot understand why.

#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

// ----SET---- // Pin number
int output1 = 12;

// ----SET---- // Pin state (output dependant)
int defstate1 = HIGH;

// ----SET---- // Delay between cycles
int tim_cyc = 20;

// EEPROM timer save
int tcyc = 0;

// ----SET---- // Cycle count
int count = 3;

// ----SET---- // Output ON
int tim_on = 500;

// ----SET---- // Output OFF
int tim_off = 500;

void setup() {
  Serial.begin(9600);
  pinMode(output1, OUTPUT);
  digitalWrite(output1, defstate1);

  lcd.begin(16, 2);
  lcd.init();
  lcd.backlight();
}

void loop() {
  int tm = EEPROM.read(tcyc);
  if (tm == 0); {
    EEPROM.write(tcyc, tim_cyc);
  }
  while (tm > 0) {
    tm--;
    Serial.print("cycle timer = ");
    Serial.println(tm);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Delay in (sec.):");
    lcd.setCursor(0, 1);
    lcd.print(tm);
    delay(900);
    EEPROM.write(tcyc, tm);
    delay(100);
  }
  int c = 0;
  while (c < count) {
    c++;
    pump();
    Serial.print("c = ");
    Serial.println(c);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Cycle count:");
    lcd.setCursor(0, 1);
    lcd.print(c);
    delay(50);
  }
}

void pump() {
  delay(tim_off);
  digitalWrite(output1, LOW);
  delay(tim_on);
  digitalWrite(output1, HIGH);
}

The code in question is the second while loop, that counts cycles. The output is always the same:

19:04:37.122 -> cycle timer = 1
19:04:38.161 -> cycle timer = 0
19:04:40.172 -> c = 1
19:04:41.212 -> c = 2
19:04:42.221 -> c = 3
19:04:43.262 -> c = 1
19:04:44.270 -> c = 2
19:04:45.309 -> c = 3
19:04:45.342 -> cycle timer = 19
19:04:46.383 -> cycle timer = 18
19:04:47.390 -> cycle timer = 17

I would appreciate any guidance or help provided on the matter.

Thank You.

This code

void loop() {
  int tm = EEPROM.read(tcyc);
  if (tm == 0); {
    EEPROM.write(tcyc, tim_cyc);
  }

has a ';' after your if statement which makes that code essentially this

void loop() {
  int tm = EEPROM.read(tcyc);
  if (tm == 0) {
    // do nothing
  }
 {
    EEPROM.write(tcyc, tim_cyc);
  }

so your EEPROM.write() happens every time.

Also note that EEPROM has a finite number of writes in the lifetime of the chip (100k?) but doing that every time through loop can get there in a hurry.

Thank you for the EEPROM note. I'm aware of that, but since I'm in a learning process and the board I'm using costs around 5 Euros I can postpone this worries for now. Later I will add a "saving" feature on every couple of minutes and not every second.

But the problem with the second while loop still remains.

I suspect that tm=0 the 2nd time through loop() in which case nothing gets printed to serial before executing your 2nd while loop.. This makes it appear the 2nd while loop is getting executed twice.

Yup.

  1. At the start of loop() you read the value from the EEPROM, store it tm.

  2. Then, because of the bad if noted above, it writes tim_cyc (20) to the EEPROM.

  3. Then it gets to the first while loop, if tm is not 0, it counts down to 0, writing each value to the EEPROM in sequence. If tm is 0, this loop doesn't run at all, because the test is always false.

  4. Then it gets to the second loop, loops three times, and goes back to step 1.

First pass through the loop, at 1, tm is whatever was stored in the EEPROM.

At 2, it writes 20 to that location in the EEPROM.

So when it reaches 3, tm is whatever was previously stored in the EEPROM, and the EEPROM contains the value 20. Then it counts down. At the end of the loop, tm is 0 and the EEPROM contains the value 0.

Then it gets to step 4 and prints out those values.

Second pass through the loop, at 1, it reads out the 0 in the EEPROM.

Then at step 2, it writes 20 to the EEPROM.

Then it gets to step 3. The EEPROM now contains 20, but tm is still 0. This loop does not execute at all, since the test is never true, so the value in the EEPROM is unchanged and nothing is printed.

So it reaches step 4, and prints out those values again.

Third pass, at step 1 we read out the 20 in the EEPROM, and we're back where we started.

I see your point.
Thank You!
Following your logic I have switched the place of the “bad if” (the “;” error was noticed by me just right after I have posted the forum topic, but I did not bother to edit it here) by placing on the bottom of the firs loop like this:

while (tm > 0) {
    tm--;
    Serial.print("cycle timer = ");
    Serial.println(tm);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Delay in (sec.):");
    lcd.setCursor(0, 1);
    lcd.print(tm);
    delay(900);
    EEPROM.write(tcyc, tm);
    delay(50);
    if (tm == 0) {
      EEPROM.write(tcyc, tim_cyc);
    }
  }

It worked like a charm. Thanks for the assistance from all of you.