Day counter on lcd 16x2 problem

Hi everyone,
I have a problem with a incubator project I've been working on. It has automatic egg turning (motor from a microwave), PID logic for heating and a fan (from a microwave), which is always on. The "schematic" for the AC part is:

I have also a lcd screen (16x2) displaying temperature, humidity level and day of incubation. Sometimes the lcd start displaying random numbers, and if I reset Arduino Uno everything goes back to normal except the day counter that gives something like "Day : 30581". The egg turner keeps working fine even with this problem. My guess is that I'd need a snubber circuit because when I disconnect the fan, the lcd shows "Day : -25401" (or something similar) for a moment. In the past sometimes the lcd completly froze, and the Arduino with it, but it was due to a faulty cable of the screen (don't know how that could happen).
The full code is:

#include <DS1302RTC.h>

#include <TimeLib.h>

#include <DallasTemperature.h>


#include <EEPROM.h>
#include <PID_v1.h>
#include <Wire.h>
#include <OneWire.h>
#include <LiquidCrystal_I2C.h>


#define pinData 7                                                  // Temperature sensor Pin 
#define SSR 6                                                      // Pin that triggers the Solid State Relay for the heating element

#define cycletime 1000
DS1302RTC RTC( 2, 3,  4 );
unsigned long t_0;                                                  //time at the beginning of the incubation (UNIX time)
unsigned long t_1;                                                  //time at the latest egg tuning
unsigned long t_2;                                                  //current time
unsigned long t_turner;                                             //time between egg turnings

int Position = 0;                                                   //

int Day = 0;                                                      //day

LiquidCrystal_I2C led(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

double Setpoint, Input, Output;                                     // Define Variables
double Kp = 130, Ki = 3, Kd = 0;                                   // PID parameters
float temperature = 0;
float t_WB = 0;                                                    //wet bulb temperature
int humid;                                                         // relative humidity

unsigned long LastTemperatureResponse = 0;
unsigned long lastPIDCalculation = 0;
float prevTemperature = -9999.0;

PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
OneWire ourWire(pinData);                                           
DallasTemperature sensors(&ourWire);                                

// Addresses of 2 DS18B20s
uint8_t sensor_temp[8] = {0x28, 0xC8, 0xE3, 0x79, 0x97, 0x21, 0x03, 0x3A };
uint8_t sensor_um[8] = { 0x28, 0xF0, 0x44, 0x94, 0x97, 0x06, 0x03, 0x6F };

void setup()
{
  Setpoint = 37.7;                                                 // initialize the variables we're linked to
  myPID.SetOutputLimits(0, cycletime);
  myPID.SetSampleTime(cycletime);
  myPID.SetMode(AUTOMATIC);
  Serial.begin(115200);
  pinMode(SSR, OUTPUT);
  digitalWrite(SSR, LOW);


  sensors.begin();      // initialize sensors
  
 t_0 =  1632378000;
 //t_1 = t_0;            //uncomment, load sketch, comment, reload sketch
  RTC.haltRTC(false);
  RTC.writeEN(false);
 EEPROM.put(0, t_0);
 EEPROM.get(35, t_1);
  t_turner = 21600;        // turn every six hours

tmElements_t tm;
    tm.Hour = 9;             // set the tm structure 
    tm.Minute = 21;
    tm.Second = 30;
    tm.Day = 23;
    tm.Month = 9;
    tm.Year = 2021 - 1970;    // tmElements_t.Year is the offset from 1970.

  // RTC.write(tm);            // set the RTC from the tm structure



  led.clear();
  // Set the clock to run-mode, and disable the write protection


  // Setup LCD to 16x2 characters
  led.begin(16, 2);


    
  pinMode(8, INPUT); //limit switch 1
  pinMode(9, INPUT); //limit switch 2
  pinMode(12, OUTPUT); //motor
  digitalWrite(12, HIGH);
}

void loop()
{

 t_2 = RTC.get();
 
  //turner();
  
  humidity();
  day_counter();
lcd();

  if (millis() - LastTemperatureResponse >= cycletime) {
    temperature = sensors.getTempC(sensor_temp);
    Input = (double)temperature;
    myPID.Compute();
    lastPIDCalculation = millis();
    Serial.print(temperature);
    Serial.print(" , ");
    Serial.print(Output / 50);
    Serial.print(" , ");
    Serial.print(humid);
    Serial.print(" , ");
    Serial.print(t_1);
    Serial.print(" , ");
    Serial.print(t_0);
    Serial.print(" , ");
    Serial.print(t_2-t_1);
    Serial.print(" , ");
    Serial.print(t_2);
    Serial.print(" , ");
    Serial.print(t_2 - t_0);
//Serial.print(" , ");
    //Serial.print(now());


    Serial.println();

    sensors.requestTemperatures();
    LastTemperatureResponse = millis();
  }
  control();
}

void control() {

  if ((millis() <= (lastPIDCalculation + Output)) || (Output == cycletime)) {
    // Power on:
    digitalWrite(SSR, HIGH);

  } else {
    // Power off:
    digitalWrite(SSR, LOW);
  }

  //  delay(10);

}

void lcd() {
  led.setCursor(0, 0);
  led.print("T: ");
  led.print(temperature);
  led.print(" RH: ");
  led.print(humid);
    led.print(" ");
  led.setCursor(0, 1);
  led.print("Day: ");
  led.print(Day);
  led.print(" ");

}

void turner() {
 
  switch (Position) {

    case 0:

      if (t_2 - t_1>= t_turner ) { 
        digitalWrite(12, LOW); //turner motor
        if (digitalRead(8) == LOW && digitalRead(9) == HIGH) { //limit switches check
          Position = 1;
        } else {
          Position = 2;
        }
      }

      break;

    case 1:
      if (digitalRead(9) == LOW) {
        digitalWrite(12, HIGH);
        Position = 0;
        t_1=t_2;
        EEPROM.put(35, t_1);
   
      }


      break;

    case 2:
      if (digitalRead(8) == LOW) {
        digitalWrite(12, HIGH);
        Position = 0;
        t_1=t_2;
        EEPROM.put(35, t_1);
      }
      break;
  }
 
}

void humidity() {
  t_WB = sensors.getTempC(sensor_um);
  humid = (t_WB / temperature - 0.45) * 170.5;
}

 void day_counter() {
  Day=((t_2-t_0)/60/60/24)+1;  //day
}

Do you have an idea of why I have this problem? The day counter loop is in the very last line of code. Let me know if you need additional info/schematics. Thank you

You comment something as obvious as "sensors.begin", and leave a magic number like that to guesswork? ?

Sorry, I commented a few lines above. It is the unix time at the beginning of the incubation. Maybe I could just put zero, since I only care about the difference.

  • SSR part#? Some SSRs require current limiting resistors (if not built-in).
  • Pins 8 and 9 have external pullups?
  • int humid ... but you're using humid = (t_WB / temperature - 0.45) * 170.5;
  • Overflow issue? if (millis() - LastTemperatureResponse >= cycletime)
  • Maybe something like this would be better?
 unsigned long elapsedTime = millis() - LastTemperatureResponse;
 if (elapsedTime >= cycletime) {
  ...
 }

-I don't know but I think it has one
-Yes
-Could you explain what's the problem with that? I'm using a temperature sensor to calculate humidity
-I don't know, but I believe the problem is here

void day_counter() {
  Day=((t_2-t_0)/60/60/24)+1;  //day

or maybe an hardware problem.
I forgot to mention that if I re-upload the scketch everything works fine until something happens (maybe a short blackout?), and as I said resetting Arduino won't solve the problem.

That 30581 day number sounds like what you would get if t_2 (terrible name by the way) is zero. Perhaps you have a wiring issue with the clock. I think you're reading it rather too often as well.

I'll check the wiring, thank you. What would be a better name and reading frequency?

You gave it a better name in the comments, so why not use that instead: CurrentTime?

Reading frequency depends on what you need. Since you're interested in day count and a six hour interval between turns I would think once a minute would do fine. Even once a second would be better than what you have now.

How can I decrease the reading frequency? I just realized that it is not stated in the code. Once a minute sounds fine.

You're using millis to check on cycletime. You can use the same model to check on a longer period.

Alternatively, you can use the cycletime if and read once a second.

I implemented your suggestion:

#include <DS1302RTC.h>

#include <TimeLib.h>

#include <DallasTemperature.h>


#include <EEPROM.h>
#include <PID_v1.h>
#include <Wire.h>
#include <OneWire.h>
#include <LiquidCrystal_I2C.h>


#define pinData 7                                                  // Temperature sensor Pin 
#define SSR 6                                                      // Pin that triggers the Solid State Relay for the heating element

#define cycletime 1000
DS1302RTC RTC( 2, 3,  4 );
unsigned long TimeBeginning;                                                  //time at the beginning of the incubation (UNIX time)
unsigned long TimeLatestTurning;                                                  //time at the latest egg tuning
unsigned long CurrentTime;                                                  //current time
unsigned long t_turner;                                             //time between egg turnings
unsigned long LastRTCReading = 0;
int Position = 0;                                                   //

int Day = 0;                                                      //day

LiquidCrystal_I2C led(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

double Setpoint, Input, Output;                                     // Define Variables
double Kp = 130, Ki = 3, Kd = 0;                                   // PID parameters
float temperature = 0;
float t_WB = 0;                                                    //wet bulb temperature
int humid;                                                         // relative humidity

unsigned long LastTemperatureResponse = 0;
unsigned long lastPIDCalculation = 0;
float prevTemperature = -9999.0;

PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
OneWire ourWire(pinData);                                           
DallasTemperature sensors(&ourWire);                                

// Addresses of 2 DS18B20s
uint8_t sensor_temp[8] = {0x28, 0xC8, 0xE3, 0x79, 0x97, 0x21, 0x03, 0x3A };
uint8_t sensor_um[8] = { 0x28, 0xF0, 0x44, 0x94, 0x97, 0x06, 0x03, 0x6F };

void setup()
{
  Setpoint = 37.7;                                                 // initialize the variables we're linked to
  myPID.SetOutputLimits(0, cycletime);
  myPID.SetSampleTime(cycletime);
  myPID.SetMode(AUTOMATIC);
  Serial.begin(115200);
  pinMode(SSR, OUTPUT);
  digitalWrite(SSR, LOW);


  sensors.begin();      // initialize sensors
  
 TimeBeginning =  1644420455;
 //TimeLatestTurning = TimeBeginning;            //uncomment, load sketch, comment, reload sketch
  RTC.haltRTC(false);
  RTC.writeEN(false);
 EEPROM.put(0, TimeBeginning);
 EEPROM.get(35, TimeLatestTurning);
  t_turner = 600;        // turn every six hours

tmElements_t tm;
    tm.Hour = 16;             // set the tm structure 
    tm.Minute = 27;
    tm.Second = 45;
    tm.Day = 11;
    tm.Month = 2;
    tm.Year = 2022 - 1970;    // tmElements_t.Year is the offset from 1970.

   //RTC.write(tm);            // set the RTC from the tm structure



  led.clear();
  // Set the clock to run-mode, and disable the write protection


  // Setup LCD to 16x2 characters
  led.begin(16, 2);


    
  pinMode(8, INPUT); //limit switch 1
  pinMode(9, INPUT); //limit switch 2
  pinMode(12, OUTPUT); //motor
  digitalWrite(12, HIGH);
}

void loop()
{
  if (millis() - LastRTCReading>= 2000) {
 CurrentTime = RTC.get();
 LastRTCReading=millis();
  }
 
  //turner();
  
  humidity();
  day_counter();
lcd();

  if (millis() - LastTemperatureResponse >= cycletime) {
    temperature = sensors.getTempC(sensor_temp);
    Input = (double)temperature;
    myPID.Compute();
    lastPIDCalculation = millis();
    Serial.print(temperature);
    Serial.print(" , ");
    Serial.print(Output / 50);
    Serial.print(" , ");
    Serial.print(humid);
    Serial.print(" , ");
    Serial.print(millis());
     Serial.print(" , ");
    Serial.print(LastRTCReading);
    Serial.print(" , ");
    Serial.print(TimeLatestTurning);
    Serial.print(" , ");
    Serial.print(TimeBeginning);
    Serial.print(" , ");
    Serial.print(CurrentTime-TimeLatestTurning);
    Serial.print(" , ");
    Serial.print(CurrentTime);
    Serial.print(" , ");
    Serial.print(CurrentTime - TimeBeginning);
//Serial.print(" , ");
    //Serial.print(now());


    Serial.println();

    sensors.requestTemperatures();
    LastTemperatureResponse = millis();
  }
  control();
}

void control() {

  if ((millis() <= (lastPIDCalculation + Output)) || (Output == cycletime)) {
    // Power on:
    digitalWrite(SSR, HIGH);

  } else {
    // Power off:
    digitalWrite(SSR, LOW);
  }

  //  delay(10);

}

void lcd() {
  led.setCursor(0, 0);
  led.print("T: ");
  led.print(temperature);
  led.print(" RH: ");
  led.print(humid);
    led.print(" ");
  led.setCursor(0, 1);
  led.print("Day: ");
  led.print(Day);
  led.print("     ");

}

void turner() {
 
  switch (Position) {

    case 0:

      if (CurrentTime - TimeLatestTurning>= t_turner ) { 
        digitalWrite(12, LOW); //turner motor
        if (digitalRead(8) == LOW && digitalRead(9) == HIGH) { //limit switches check
          Position = 1;
        } else {
          Position = 2;
        }
      }

      break;

    case 1:
      if (digitalRead(9) == LOW) {
        digitalWrite(12, HIGH);
        Position = 0;
        TimeLatestTurning=CurrentTime;
        EEPROM.put(35, TimeLatestTurning);
   
      }


      break;

    case 2:
      if (digitalRead(8) == LOW) {
        digitalWrite(12, HIGH);
        Position = 0;
        TimeLatestTurning=CurrentTime;
        EEPROM.put(35, TimeLatestTurning);
      }
      break;
  }
 
}

void humidity() {
  t_WB = sensors.getTempC(sensor_um);
  humid = (t_WB / temperature - 0.45) * 170.5;
}

 void day_counter() {
  Day=((CurrentTime-TimeBeginning)/60/60/24)+1;  //day
}

and also changed the battery of the RTC and things seem to go better, but now things that worked just fine don't work anymore. For example:

TimeBeginning =  1632378000;
 //TimeLatestTurning = TimeBeginning ;            //uncomment, load sketch, comment, reload sketch

in these lines I set TimeBeginning as the unix time at the beginning of the incubation and then set TimeLatestTurning , which is the time at the latest turning, equal to TimeBeginning . Then I comment and reload so if there is a power loss I can recall TimeLatestTurning from EEPROM. The problem is that from the Serial Monitor I see that TimeLatestTurning is always the same and different from TimeBeginning . Furthermore, even if
CurrentTime - TimeLatestTurning>= t_turner
the next line
digitalWrite(12, LOW);
doesn't work. I checked the wirings and voltages with a multimeter and pin 12 is always HIGH.

I don't really understand what you're doing. Why is the start time hard coded rather than read from the clock?

Well yes maybe you are right now that I think of it, but I'd still have to save TimeBeginning and TimeLatestTurning to the EEPROM. Anyway I understand that this may be confusing but I don't think that's the problem. Even if hard coded, TimeLatestTurning isn't equal to TimeBeginning, and the turner loop doesn't work anymore, too. I messed up something but I can't find out what.

Throw in some serial prints and post that code, along with the serial output it produces.

Another thing to consider is putting something in EEPROM about whether the system is running. If you're worried about recovery after a power issue, it would be nice to know whether the incubator was actually active when the power went out.

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