Problem with code, please help

Hello
I am making an automation for aquarium light. Arduino is driving stepper motor which turning potentiometer, which further regulate 1-10V input on ballast for T5 bulbs.

So I have connected everything, made a code and it works.

Just one thing confuses me:
For example, part of the code which does "sunrise" should move stepper motor one step when second on clock is 0,20 and 40. This should last for two hours.

By my calculation, it's 3 steps per minute, so in two hours should be 120 x 3 = 360 steps.

But program now in the morning did just 326 steps.

here is the part of the code:


void loop() {
      /*-------------------------------------Sunrise-----------------------------------------------------*/
        if ((myRTC.getHour(h24,hPM) >= 8) && (myRTC.getHour(h24,hPM) < 10) ){
          if(myRTC.getSecond() == 0  || myRTC.getSecond() == 20 || myRTC.getSecond() == 40  ){
            if(check== true){
              if(step < 360){
                step  += 1;
                myStepper.step(1);
              }
              else{
                digitalWrite(2, LOW);
                digitalWrite(3, LOW);
                digitalWrite(4, LOW);
                digitalWrite(5, LOW);
              }
            }
            }
        }
        /*-------------------------------------Sunrise-----------------------------------------------------*/
       
delay(500);
check = !check;
}

Please post the whole sketch

you check your time twice per second ➜ it is possible that on some seconds you hit 0, 20 or 40 twice

say it's 8:00:20:100 ➜ you get a match for seconds == 20
you read again 500ms later, it's 8:00:20:600 ➜ you get a second match for seconds == 20

you should modify the code to change what you expect next 0, 20 and 40 and check only against that value this way you won't hit the same second twice

I get Your point, but this "check = !check;" is toggling every half a second.
And "if(check== true){" than is doing steps, so every second.

Here is whole code:

#include <LiquidCrystal_I2C.h>  /*include LCD I2C Library*/
#include <DS3231.h>
#include <Stepper.h>
bool check = true;
DS3231 myRTC;
int count = 0; ////change!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
int step = 0; ////change!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
bool h24;
bool hPM;
Stepper myStepper = Stepper(1050, 2, 3, 4, 5);
LiquidCrystal_I2C lcd(0x27,16,2);  /*I2C scanned address defined + I2C screen size*/
void setup() {
  pinMode(9, OUTPUT); 
  pinMode(8, INPUT_PULLUP);
  pinMode(7, INPUT_PULLUP);
  pinMode(6, INPUT_PULLUP);
  myStepper.setSpeed(10);
  //digitalWrite(9, HIGH);
  Serial.begin(9600);
  time_t epochNow = 1659875100UL;
  // put your setup code here, to run once:
  Wire.begin();
  /*------------------------------CLOCK SETTING -----------------------------------------------------------
  bool mode12 = false; // sets the clock mode, 12-hour (`true`) or 24-hour (`false`), in the DS3231
  myRTC.setClockMode(mode12); // uploads 'false' (1) to bit 6 of register 0x02
  myRTC.setSecond(5); // uploads 42 to register 0x00
  myRTC.setMinute(9);
  myRTC.setHour(22);
  myRTC.setDoW(2); //Day of the Week
  myRTC.setDate(16); //day of the month
  myRTC.setMonth(1);
  myRTC.setYear(24);
  -------------------------------CLOCK SETTING------------------------------------------------------------*/
  lcd.init();  /*LCD display initialized*/
  lcd.clear();     /*Clear LCD Display*/
  lcd.backlight();      /*Turn ON LCD Backlight*/ 
}
void loop() {
  if (digitalRead(8) == LOW) {
      myStepper.step(1);
      step++;
      count = 0;
      lcd.setCursor(0,0);   /*Set cursor to Row 1*/
  lcd.print(step); /*print message on LCD*/
  }
  else if(digitalRead(7) == LOW){
      count = 0;
      step=0;
  }
  else if(digitalRead(6) == LOW){
      myStepper.step(-1);
      step--;
      count = 0;
      lcd.setCursor(0,0);   /*Set cursor to Row 1*/
  lcd.print(step); /*print message on LCD*/
  }
  else {
        if( myRTC.getHour(h24,hPM) == 11  && myRTC.getMinute() == 0 && myRTC.getSecond() == 20){
          digitalWrite(9, HIGH);
        }
      /*-------------------------------------Sunrise-----------------------------------------------------*/
        if ((myRTC.getHour(h24,hPM) >= 8) && (myRTC.getHour(h24,hPM) < 10) ){
          if(myRTC.getSecond() == 0  || myRTC.getSecond() == 20 || myRTC.getSecond() == 40  ){
            if(check == true){
              if(step < 360){
                step  += 1;
                myStepper.step(1);
              }
              else{
                digitalWrite(2, LOW);
                digitalWrite(3, LOW);
                digitalWrite(4, LOW);
                digitalWrite(5, LOW);
              }
            }
            }
        }
        /*-------------------------------------Sunrise-----------------------------------------------------*/
        /*-------------------------------------Noon--------------------------------------------------------*/
        if ((myRTC.getHour(h24,hPM) >= 10) && (myRTC.getHour(h24,hPM) < 13) ){
          if(myRTC.getSecond() == 0  || myRTC.getSecond() == 10 || myRTC.getSecond() == 20 || myRTC.getSecond() == 30  || myRTC.getSecond() == 40 || myRTC.getSecond() == 50 || myRTC.getSecond() == 55  ){
              if(check == true){
              if(step < 1050){
                step  += 1;
                myStepper.step(1);
              }
              else{
                digitalWrite(2, LOW);
                digitalWrite(3, LOW);
                digitalWrite(4, LOW);
                digitalWrite(5, LOW);
              }
              }
            }
        }
        /*-------------------------------------Noon--------------------------------------------------------*/

        /*-------------------------------------Sunset--------------------------------------------------------*/
        if ((myRTC.getHour(h24,hPM) >= 16) && (myRTC.getHour(h24,hPM) < 20) ){
          if( myRTC.getHour(h24,hPM) == 16  &&myRTC.getMinute() == 0 && myRTC.getSecond() == 10){
          digitalWrite(9, LOW);
        }
        if(step > 360){
          if(myRTC.getSecond() == 0  || myRTC.getSecond() == 10 || myRTC.getSecond() == 20 || myRTC.getSecond() == 30  || myRTC.getSecond() == 40 || myRTC.getSecond() == 50 || myRTC.getSecond() == 55  ){
              if(check == true){
                step  -= 1;
                myStepper.step(-1);
              }
            }
        }
        else if(step > 0){
             if(myRTC.getSecond() == 0  || myRTC.getSecond() == 20 ||  myRTC.getSecond() == 40  ){
                if(check == true){
                  if(step > 0){
                    step  -= 1;
                    myStepper.step(-1);
                  }
                }
              }
         }
        else{
          digitalWrite(2, LOW);
          digitalWrite(3, LOW);
          digitalWrite(4, LOW);
          digitalWrite(5, LOW);
        }
        }
        /*-------------------------------------Sunset--------------------------------------------------------*/

     if(count == 0){
       lcd.clear(); 
     }
     if(count < 4){
       count ++;       
        lcd.setCursor(3,0);
        lcd.print("LIGHT LEVEL");
        lcd.setCursor(1,1);
        lcd.print(step);
        lcd.print(" from 1050");
      }
      else{
   if(count == 4){
       lcd.clear(); 
     }
  if(count < 7){
    count ++;
  }
  else {
    count = 0;
  }
  lcd.setCursor(4,0);   /*Set cursor to Row 1*/
  lcd.print(myRTC.getDate()); /*print message on LCD*/
  lcd.print(".");
  bool CenturyBit;
  lcd.print(myRTC.getMonth(CenturyBit));
  lcd.print(".");
  lcd.print(myRTC.getYear());
  lcd.setCursor(0,1);   /*set cursor on row 2*/
  bool h24;
  bool hPM;
  lcd.print(myRTC.getHour(h24,hPM));
  lcd.print(":");
  lcd.print(myRTC.getMinute());
  lcd.print(":");
  lcd.print(myRTC.getSecond());
  lcd.print(" ");
  lcd.print( myRTC.getTemperature());
  lcd.print("'C");
}  
delay(500);
check = !check;
  }
}

Now I am thinking...
Can it be that some time program miss some seconds?
Cause is doing refresh twice per 1000 (but just once executes the code), and those arduinos 1000 can be slightly more than RTC one second?

right I missed that check, but millis() is not super precise so I'd be careful with this approach. (why don't you wait for 1 full second then ?)

I'd consider something like this

void loop() {

  /*-------------------------------------------------------------------------------------------------*/
  /*-------------------------------------Sunrise-----------------------------------------------------*/
  /*-------------------------------------------------------------------------------------------------*/
  static byte waitingFor = 0;
  byte hour = myRTC.getHour(h24, hPM);

  if ((hour >= 8) && hour < 10) ) {
    byte second = myRTC.getSecond();
    if (second >= waitingFor) { // >= to catch the possible event that you missed that second if the code is too busy elsewhere (but not to a point where you miss 20s)
      if (step < 360) {
        step  += 1;
        waitingFor = (waitingFor + 20) % 60; // go through 0, 20, 40
        myStepper.step(1);
      }
      else {
        digitalWrite(2, LOW);
        digitalWrite(3, LOW);
        digitalWrite(4, LOW);
        digitalWrite(5, LOW);
        waitingFor = 0;
      }
    }
  }

  /*-------------------------------------------------------------------------------------------------*/


}

I assume you have some other part of the code where you reset step the other way at sunset?

EDIT: this is buggy

Okay, this is a little bit on advance side for me. Can You please explain "waitingFor = (waitingFor + 20) % 60;"
This code will not execute multiple times per one second?
Also further in the code I need sometime steps to be executed 6 times and 7 times per minute...how to apply your code to that?
Thank You.

By the way, whole code is up in the post.

Yes, I also have "noon" part where lights are at maximum level, till step 1050 going with potentiometer and than disconnect potentiometer with a relay (it gives slightly stronger light) than further trough the day connect again and go opposite direction till step is zero.

you start with waitingFor being 0
when you are in the 8am 10am bracket (sunrise) and the current second is >= 0 then you take one step and change the the waitingFor value with the formula

waitingFor = (waitingFor + 20) % 60;

the % operator is the modulo, the rest of the integral division by 60.

so when waitingFor is 0, the formula is (0 + 20) % 60 ➜ the rest of 20 divided by 60 is 20, si the new value of waitingFor becomes 20, and thus you don't take further steps until the seconds are >= 20

When your seconds goes above 20, the formula is (20 + 20) % 60 ➜ the rest of 40 divided by 60 is 40, si the new value of waitingFor becomes 40, and thus you don't take further steps until the seconds are >= 40

When your seconds goes above 40, the formula is (40 + 20) % 60 ➜ the rest of 60 divided by 60 is 0, si the new value of waitingFor becomes 40, and thus you don't take further steps until the seconds are >= 0

➜ and this is a bug because it will be true all the way between 40 and 60 :slight_smile: sorry for that

you should go for == but it means your loop should spin in less than a second or build the time including the hours and minutes (seconds elapsed since midnight) for example and then you don't have the issue any more

Haha, good that You check it out :slight_smile:
Okay, so You are right, I need to make a loop shorter than one second .
Building time is not a bad idea, but i don't know how much it can drift during day?
Or maybe...to make a time triggered by Hour, so every Hour its gonna count seconds and minutes. Like this time should not drift a lot?

you build it at the start of the loop, it will have the precision of your RTC

void loop() {
  uint32_t hour = myRTC.getHour(h24, hPM);
  uint32_t minute = myRTC.getMinute();
  uint32_t second = myRTC.getSecond();
  uint32_t secondsSinceMidnight = 3600ul* hour + 60ul * minute + second;

...

}

Thing is, if you don't know something, why not test it and see? Maybe, run a loop for an hour, see what the drift is, and multiply it by 24? These are the things we can do for ourselves, easily. You will find the accuracy of the clock is marginal, and if you want to, you can do the temperature experiment - run it in your room for an hour, then run it in your fridge for an hour, and see how much difference that makes. Curiosity is your friend.
As for the decision-making in your code, I'd recommend reading through the state-change code for ideas. What you want to do, is act on only the FIRST time the time meets your criteria, and at that time, change your criteria to the next target. Then, it doesn't matter how often your loop() runs(I recommend 'as fast as possible'), you'll only ever take the right actions.
It really doesn't matter what your source of time is, by the way, if you structure your decision-making correctly. It could be millis() comparisons, RTC epoch values, or whatever; as long as you take action only the first time you meet criteria, you're good.
Hope that helps.

Hi,
I know that clock can have various time at diferent temperatures.

The best solution for me is exactly that, to execute just once when meet criteria.

But I'm not sure how to do this exactly...

Forgive me. I'm using IDE 1.8.13, so your menus may be different, but read through
File|Examples|Digital|StateChangeDetection
While the example is all about button state changes, there's no conceptual difference. You simply want to know the first time your conditions are met, and act on that.

Okay thanks a lot.
I'm going to check it out.

Thank You. This is what I needed. It solved my problem.
I will continue testing it little bit longer, but for now it doesn't skip any step.

Good to hear that, thanks for reporting in.

Just checking in with final result.
Everything is going smoothly, without any problems.
Thank you guys.

Here is the final code:

#include <LiquidCrystal_I2C.h>
#include <DS3231.h>
#include <Stepper.h>
DS3231 myRTC;
int count = 0; 
int step = 0;
int clockSec = 0;
bool h24;
bool hPM;
bool secondState = false;
bool lastSecondState = false;
Stepper myStepper = Stepper(1050, 2, 3, 4, 5);
LiquidCrystal_I2C lcd(0x27,16,2);
void setup() {
  pinMode(9, OUTPUT); 
  pinMode(8, INPUT_PULLUP);
  pinMode(7, INPUT_PULLUP);
  pinMode(6, INPUT_PULLUP);
  myStepper.setSpeed(10);
  Serial.begin(9600);
  time_t epochNow = 1659875100UL;
  Wire.begin();
  /*==============================================================SET THE CLOCK==============================================================*/
  /*
  bool mode12 = false; // sets the clock mode, 12-hour (`true`) or 24-hour (`false`)
  myRTC.setClockMode(mode12); // uploads 'false' (1) to bit 6 of register 0x02
  myRTC.setSecond(5); // uploads 42 to register 0x00
  myRTC.setMinute(9);
  myRTC.setHour(22);
  myRTC.setDoW(2); //Day of the Week
  myRTC.setDate(16); //day of the month
  myRTC.setMonth(1);
  myRTC.setYear(24);
  */
  /*==========================================================/////SET THE CLOCK==============================================================*/
  lcd.init();
  lcd.clear();
  lcd.backlight();
}
void loop() {
  if (digitalRead(8) == LOW) {
      myStepper.step(1);
      step++;
      count = 0;
      lcd.setCursor(0,0);
      lcd.print(step);
  }
  else if(digitalRead(7) == LOW){
      count = 0;
      step=0;
  }
  else if(digitalRead(6) == LOW){
      myStepper.step(-1);
      step--;
      count = 0;
      lcd.setCursor(0,0);
      lcd.print(step);
  }
  else {
    /*==============================================================RELAY OPEN==============================================================*/
    if( myRTC.getHour(h24,hPM) == 11  && myRTC.getMinute() == 0 && myRTC.getSecond() == 20){
      digitalWrite(9, HIGH);
    }
    /*=========================================================/////RELAY OPEN==============================================================*/
    /*==============================================================RELAY CLOSE=============================================================*/
    if( myRTC.getHour(h24,hPM) == 16  &&myRTC.getMinute() == 0 && myRTC.getSecond() == 10){
        digitalWrite(9, LOW);
    }
    /*=========================================================/////RELAY CLOSE=============================================================*/
    /*===============================================================SUNRISE================================================================*/
    if ((myRTC.getHour(h24,hPM) >= 8) && (myRTC.getHour(h24,hPM) < 10) ){
      if(myRTC.getSecond() == 0  || myRTC.getSecond() == 20 || myRTC.getSecond() == 40  ){
        secondState = true;
        if(secondState != lastSecondState){
          if(step < 360){
            step  += 1;
            myStepper.step(1);
          }
          else{
            digitalWrite(2, LOW);
            digitalWrite(3, LOW);
            digitalWrite(4, LOW);
            digitalWrite(5, LOW);
          }
        }
      }
      else{
        secondState = false;
      }
      lastSecondState = secondState;
    }
    /*==========================================================/////SUNRISE================================================================*/
    /*=================================================================NOON=================================================================*/
    if ((myRTC.getHour(h24,hPM) >= 10) && (myRTC.getHour(h24,hPM) < 13) ){
      if(myRTC.getSecond() == 0  || myRTC.getSecond() == 10 || myRTC.getSecond() == 20 || myRTC.getSecond() == 30  || myRTC.getSecond() == 40 || myRTC.getSecond() == 50 || myRTC.getSecond() == 55  ){
        secondState = true;
        if(secondState != lastSecondState){
          if(step < 1050){
            step  += 1;
            myStepper.step(1);
          }
          else{
            digitalWrite(2, LOW);
            digitalWrite(3, LOW);
            digitalWrite(4, LOW);
            digitalWrite(5, LOW);
          }
        }
      }
      else{
          secondState = false;
        }
        lastSecondState = secondState;
    }
    /*============================================================/////NOON=================================================================*/
    /*================================================================SUNSET================================================================*/
    if ((myRTC.getHour(h24,hPM) >= 16) && (myRTC.getHour(h24,hPM) < 20) ){
      if(step > 360){
        if(myRTC.getSecond() == 0  || myRTC.getSecond() == 10 || myRTC.getSecond() == 20 || myRTC.getSecond() == 30  || myRTC.getSecond() == 40 || myRTC.getSecond() == 50 || myRTC.getSecond() == 55  ){
          secondState = true;
          if(secondState != lastSecondState){
            step  -= 1;
            myStepper.step(-1);
          }
        }
        else{
            secondState = false;
        }
        lastSecondState = secondState;
      }
      else if(step > 0){
        if(myRTC.getSecond() == 0  || myRTC.getSecond() == 20 ||  myRTC.getSecond() == 40  ){
          secondState = true;
          if(secondState != lastSecondState){
              step  -= 1;
              myStepper.step(-1);
          }
        }
        else{
          secondState = false;
        }
        lastSecondState = secondState;
      }
      else{
        digitalWrite(2, LOW);
        digitalWrite(3, LOW);
        digitalWrite(4, LOW);
        digitalWrite(5, LOW);
      }
    }
    /*================================================================SUNSET================================================================*/
    /*================================================================DISPLAY===============================================================*/
    if(myRTC.getSecond() != clockSec){
      if(count == 2 || count == 5){
        lcd.clear();
        } 
      count++;
      if(count == 6){
       count = 0;
      }
      clockSec = myRTC.getSecond();
    }   
     if(count < 3 ){
        /*----------------------------------------LIGHT LEVEL---------------------------------------------*/ 
                  lcd.setCursor(3,0);
                  lcd.print("LIGHT LEVEL");
                  lcd.setCursor(1,1);
                  lcd.print(step);
                  lcd.print(" from 1050");
        /*-----------------------------------/////LIGHT LEVEL---------------------------------------------*/   
      }
      else{
      /*----------------------------------------CLOCK---------------------------------------------------*/            
                lcd.setCursor(4,0);   /*Set cursor to Row 1*/
                lcd.print(myRTC.getDate()); /*print message on LCD*/
                lcd.print(".");
                bool CenturyBit;
                lcd.print(myRTC.getMonth(CenturyBit));
                lcd.print(".");
                lcd.print(myRTC.getYear());
                lcd.setCursor(0,1);   /*set cursor on row 2*/
                bool h24;
                bool hPM;
                lcd.print(myRTC.getHour(h24,hPM));
                lcd.print(":");
                lcd.print(myRTC.getMinute());
                lcd.print(":");
                lcd.print(myRTC.getSecond());
                lcd.print(" ");
                lcd.print( myRTC.getTemperature());
                lcd.print("'C");       
      /*-----------------------------------/////CLOCK---------------------------------------------------*/ 
      }   
    /*===========================================================/////DISPLAY===============================================================*/     
  }
}

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