Incubator Project keeps freezing - Possible I2C Problem?

I'm creating an Egg Incubator project which keeps freezing.
I had multiple qty of components, adaptors, arduino boards etc.. All combinations freezes within random durations (3min to 2 hours) It usually won't work more than 2 hours.
I even ended up creating 2 incubators trying to isolate the issue.

Project only works thanks to "Watchdog" code I have which keeps resetting arduino after set amount of time when it hangs. Before using watchdog; it would just stay like that without doing anything, after adding watchdog code, it resets when it hangs.

It gets the job done as is but it's so annıoying that it keeps resetting. I'm showing "up duration" on LCD screen, I've not seen more than 2 hours so far.

Used components:

  • Arduino Nano Clone
  • 5V Relay (Turn-on/off Bulp)
  • MG 995 Servo (To turn eggs)
  • BME280 Temprature and Humdity Sensor (I2C)
  • DS3231 RTC (keep timing for hatch time and turn eggs every hour)
  • 16x2 LCD (I2C) (to show Temp, Humidty, next turn and remaing hatch days)

The methods I tried so far;

  • Using different set of power adaoptors, arduino boards and components..
  • I have 2 of the same setup.
  • On one of the setup; I use 1K resistors between 5V<->A4&A5 and 3.3V<->A4&A5. Apperantly it should help I2C comm.
  • The other doesn't have 1K resistors and it seems it resets more often than the one I use resistors.

Diagram attached and code is below, any idea where I should look for?

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
#include "RTClib.h"
#include "Time.h"
#include <avr/wdt.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 10

#define DS3231_I2C_ADDRESS 0x68
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme; // I2C

Servo eggTurnServo;
LiquidCrystal_I2C lcd(0x27, 16, 2);
RTC_DS3231 rtc;

// Define Target Temp and Humidity Levels
double tempThreshold = 37.7;
double humidThresold = 60;
double currentTemp = 0;
double currentHumid = 0;

const int relayBulpPin = 11;
boolean ledState= true;
const int servoPin= 9;

// Set up timer for 5 seconds before switch on/off lamp so it doesn't keep 
// switching onn&off every second.
const unsigned long MinStateChangeDuration=5000;
unsigned long lastBulpChange = 5;

// Date variables to calculate next egg turn, up time and hatch time
DateTime nowTime;
DateTime nextTurn;
DateTime hatchTime;
DateTime bootTime;
time_t remainingTime;
time_t remainingDays;
time_t upTime;

// LCD lines
char line0[16]; 
char line1[16];

void setup() {

// WatchDog Library code for resetting if it hangs
  wdt_disable();
  wdt_enable(WDTO_4S);// 4 sec

  digitalWrite(relayBulpPin,HIGH);
  
  //initialize the LCD
  lcd.begin();
  lcd.backlight();
  delay(100);

  // Initialize the BME
  unsigned status;
  status = bme.begin(0x76);  
  if (!status) {
      lcd.print("BME280 ERROR");
      while (1) delay(10);
  }
  delay(100);
  
  // Initialize RTC
  if (! rtc.begin()) {
    lcd.print("Couldn't find RTC!");
    delay(5000);
  }
  delay(300);

  pinMode(servoPin , OUTPUT);
  pinMode(relayBulpPin , OUTPUT);

  bootTime = rtc.now();
  delay(300);
}

void loop() {
  
  wdt_reset();
  
  currentTemp = bme.readTemperature();
  currentHumid = bme.readHumidity();
  
  delay(500);
  
  nowTime = rtc.now();
  nextTurn = DateTime(nowTime.year(), nowTime.month(), nowTime.day(), nowTime.hour()+1, 0, 0);
  hatchTime = DateTime(2021, 4, 1, 10, 0, 0);
  remainingTime = nextTurn.unixtime()-nowTime.unixtime();
  //remainingDays = hatchTime.unixtime()-nowTime.unixtime();
  upTime = nowTime.unixtime() - bootTime.unixtime();

  delay(500);

  lcd.setCursor(0,0);
  // Write Temp and Humidity
  lcd.print(F("S:"));
  lcd.print(currentTemp,1);
  lcd.print(F("C - "));
    lcd.print(F("N:"));
  lcd.print(currentHumid,0);
  lcd.print(F("%"));
  // Write Date&Time  
  lcd.setCursor(0,1);
  lcd.print(F("D:"));
  if(remainingTime/60<10) lcd.print(F("0"));
  lcd.print( remainingTime/60, DEC );
  lcd.print(":");
  if(remainingTime%60<10) lcd.print(F("0"));
  lcd.print(remainingTime%60, DEC);
  // Write UpTime  
  lcd.print(F("-UP:"));
  if(upTime/60<10) lcd.print(F("0"));
  lcd.print( upTime/60, DEC );
  lcd.print(":");
  if(upTime%60<10) lcd.print(F("0"));
  lcd.print(upTime%60, DEC);
  
  delay(500);

  // Turn eggs if less than 5 seconds to next turn time.
  if( remainingTime < 5 ){
    turnServo();
  }

  // Switch on&off bulp checking 5 seconds buffer between changes and current temp
  if (lastBulpChange<5) lastBulpChange++;
  else {
    lastBulpChange = 0;
    if (currentTemp <= tempThreshold){
      digitalWrite(relayBulpPin,LOW);
    }
    else 
    {
      digitalWrite(relayBulpPin,HIGH);  
    }
  }
}

// methods to turn eggs slowly.
void turnServo(){
  wdt_disable();
  // Turn off lamp temporarily
  digitalWrite(relayBulpPin,HIGH);

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("YUMURTALAR");
  lcd.setCursor(0,1);
  lcd.print("CEVIRILIYOR...");
  delay(1000);

  if(nextTurn.hour()%2 == 1) {
    eggTurnServo.write(95);
    eggTurnServo.attach(servoPin);
    for(int i=95; i<=180;i++){
      eggTurnServo.write(i);
      delay(100);
    }
    eggTurnServo.detach();
    //eggTurnServo2.detach();
  }
  else {
    eggTurnServo.write(180);
    eggTurnServo.attach(servoPin);
    for(int i=180; i>=95;i--){
      eggTurnServo.write(i);
      delay(200);
    }
    eggTurnServo.detach();
  }
  wdt_enable(WDTO_4S);
}

Add some serial prints to show where the freeze thing is happening to get to the area of issue?

void loop() {

Serial.println( "!"); 
  //wdt_reset();
 
  currentTemp = bme.readTemperature();
Serial.println( "@" );
  currentHumid = bme.readHumidity();
 
Serial.println( "#" );
  delay(500);
 
  nowTime = rtc.now()

Serial.println( "$" );;
  nextTurn = DateTime(nowTime.year(), nowTime.month(), nowTime.day(), nowTime.hour()+1, 0, 0);

Serial.println( "%" );
  hatchTime = DateTime(2021, 4, 1, 10, 0, 0);

Serial.println( ^" );
  remainingTime = nextTurn.unixtime()-nowTime.unixtime();

Serial.println( "&" ); and son on and so forth. Now when it feeezes, you know where it was. remove the prints when issues fixed
  //remainingDays = hatchTime.unixtime()-nowTime.unixtime();
  upTime = nowTime.unixtime() - bootTime.unixtime();

  delay(500);

  lcd.setCursor(0,0);
  // Write Temp and Humidity
  lcd.print(F("S:"));
  lcd.print(currentTemp,1);
  lcd.print(F("C - "));
    lcd.print(F("N:"));
  lcd.print(currentHumid,0);
  lcd.print(F("%"));
  // Write Date&Time 
  lcd.setCursor(0,1);
  lcd.print(F("D:"));
  if(remainingTime/60<10) lcd.print(F("0"));
  lcd.print( remainingTime/60, DEC );
  lcd.print(":");
  if(remainingTime%60<10) lcd.print(F("0"));
  lcd.print(remainingTime%60, DEC);
  // Write UpTime 
  lcd.print(F("-UP:"));
  if(upTime/60<10) lcd.print(F("0"));
  lcd.print( upTime/60, DEC );
  lcd.print(":");
  if(upTime%60<10) lcd.print(F("0"));
  lcd.print(upTime%60, DEC);
 
  delay(500);

  // Turn eggs if less than 5 seconds to next turn time.
  if( remainingTime < 5 ){
    turnServo();
  }

  // Switch on&off bulp checking 5 seconds buffer between changes and current temp
  if (lastBulpChange<5) lastBulpChange++;
  else {
    lastBulpChange = 0;
    if (currentTemp <= tempThreshold){
      digitalWrite(relayBulpPin,LOW);
    }
    else
    {
      digitalWrite(relayBulpPin,HIGH); 
    }
  }
}

Do you have a snubber diode on the relay? You may want to consider opto-isolating it too.

The power voltage for the sm-s2309s is 6 volts, are you using 12 as shown?

Are you driving a plain 5 volt relay directly from an output pin as shown?

These are both possible sources of undesired and unpredictable behaviours.

a7

How long are the wires of the I2C bus ? Do you use a cable ? Are those wires near other wires ? Can you show a photo with those wires ?

If you have a BME280 module with a onboard I2C level shifter, then you can make the I2C bus a 5V I2C bus.

Idahowalker:
Add some serial prints to show where the freeze thing is happening to get to the area of issue?

void loop() {

Serial.println( "!");
 //wdt_reset();

currentTemp = bme.readTemperature();
Serial.println( "@" );
 currentHumid = bme.readHumidity();

Serial.println( "#" );
 delay(500);

nowTime = rtc.now()

Serial.println( "$" );;
 nextTurn = DateTime(nowTime.year(), nowTime.month(), nowTime.day(), nowTime.hour()+1, 0, 0);

Serial.println( "%" );
 hatchTime = DateTime(2021, 4, 1, 10, 0, 0);

Serial.println( ^" );
 remainingTime = nextTurn.unixtime()-nowTime.unixtime();

Serial.println( "&" ); and son on and so forth. Now when it feeezes, you know where it was. remove the prints when issues fixed
 //remainingDays = hatchTime.unixtime()-nowTime.unixtime();
 upTime = nowTime.unixtime() - bootTime.unixtime();

delay(500);

lcd.setCursor(0,0);
 // Write Temp and Humidity
 lcd.print(F("S:"));
 lcd.print(currentTemp,1);
 lcd.print(F("C - "));
   lcd.print(F("N:"));
 lcd.print(currentHumid,0);
 lcd.print(F("%"));
 // Write Date&Time
 lcd.setCursor(0,1);
 lcd.print(F("D:"));
 if(remainingTime/60<10) lcd.print(F("0"));
 lcd.print( remainingTime/60, DEC );
 lcd.print(":");
 if(remainingTime%60<10) lcd.print(F("0"));
 lcd.print(remainingTime%60, DEC);
 // Write UpTime
 lcd.print(F("-UP:"));
 if(upTime/60<10) lcd.print(F("0"));
 lcd.print( upTime/60, DEC );
 lcd.print(":");
 if(upTime%60<10) lcd.print(F("0"));
 lcd.print(upTime%60, DEC);

delay(500);

// Turn eggs if less than 5 seconds to next turn time.
 if( remainingTime < 5 ){
   turnServo();
 }

// Switch on&off bulp checking 5 seconds buffer between changes and current temp
 if (lastBulpChange<5) lastBulpChange++;
 else {
   lastBulpChange = 0;
   if (currentTemp <= tempThreshold){
     digitalWrite(relayBulpPin,LOW);
   }
   else
   {
     digitalWrite(relayBulpPin,HIGH);
   }
 }
}

I can try that.. I thought Serial prints may also cause additional unwanted behavior/timing delays etc so first thing I did was to remove all of it. Will try when I can leave the laptop foır few hours..

wildbill:
Do you have a snubber diode on the relay? You may want to consider opto-isolating it too.

Do you mean if my relay has it or if I did wire one? attached is the relay I used (Now a single channel relay is wired to both setups) and I haven't wired one. I just briefly red about it now and will have to do more reading tonight to udnerstand more why we use it :slight_smile: (Sorry I'm a coder but new to electrnoics.. )

alto777:
The power voltage for the sm-s2309s is 6 volts, are you using 12 as shown?

Are you driving a plain 5 volt relay directly from an output pin as shown?

These are both possible sources of undesired and unpredictable behaviours.

a7

I listed the servo I used but didn't notice there was another servo model on the picture I draw.. Sorryu for confusion..

  • MG 995 Servo
    The servo I use is also rated 12V and yes I use a seperate 12v adaptor for servo..
    I infacat use 2x12V 2A adaptors.
    1- 12V-2A is powering Arduino
    2- 12V-2A is powering servo.
    The GND of the Servo adaoptor is also connected to GND of Arduino.

I can’t see how the relay is powered , if just from the Arduino pin , then it’s likely the current taken is causing a problem .

Koepel:
How long are the wires of the I2C bus ? Do you use a cable ? Are those wires near other wires ? Can you show a photo with those wires ?

If you have a BME280 module with a onboard I2C level shifter, then you can make the I2C bus a 5V I2C bus.

Longest wire is BME280 which is less than 30cm but I add pin wires to each other. Wires are all close to each other I attached the picture.
The BME280 I bought was advertised as 3.3V so I connect it to 3.3V. I tried to connect it to 5V before and it worked but didn't keep it that way. RTC is also 3.3V. Only LCD is connected to 5V. Do you think it would help to connect all to 5V?

hammy:
I can’t see how the relay is powered , if just from the Arduino pin , then it’s likely the current taken is causing a problem .

I'm using relay to switch on/off the bulp. Directly connected to AC outlet. I'm connecting VCC to arduino 5V directly. See attached..

Your relay module is equipped with a diode and opto-isolation, which means that you could be completely defended against noise from switching the relays.

However, the jumper on the board is powering the relay coils from the Arduino which may explain the crashes you observe. Better to get a different power supply for that piece.

korkete:
I listed the servo I used but didn't notice there was another servo model on the picture I draw.. Sorryu for confusion..

  • MG 995 Servo
    The servo I use is also rated 12V and yes I use a seperate 12v adaptor for servo..
    I infacat use 2x12V 2A adaptors.
    1- 12V-2A is powering Arduino

The backlight diode of the LCD if on may put the current draw over what the Arduino can handle when powered at 12V (and its small internal regulator overheats). You better get a 5V adapter for the Arduino and other 5V peripherals (power everything from their respective 5V pins) - an old mobile phone charger will do fine, likely you have a few collecting dust in a drawer. A USB adapter with USB cable to the USB plug of the Arduino is another decent alternative; then the peripherals get their power from the 5V pin (limited but plenty for your display and sensors).

Adding the relay's coil current in the mix will definitely overheat that regulator, and that in turn may cause crashes or otherwise odd behaviour when the regulator decides to shut down to protect itself.

2- 12V-2A is powering servo.

The servo is rated 4.8-6V, you're overpowering it. This may damage the servo. Especially when the servo is under load this may lead to overheating and possibly fire. A second phone charger (one that can output at least 2A) would be a really good alternative here. In fact, you can power the whole thing from a single 5V, 2A (or more) phone charger.

TBC the servo not in the drawing but that you specify, MG 995:

Item Name: MG995 Metal Gear Servo
...
Operation Voltage: **4.8 - 7.2 **Volts

so good that you haven't killed it yet, don't keep trying to.

a7

I will leave the power issue to others (servo, backlight, relays). The 5V pin is to power a few sensors.

I think that your I2C bus is not okay.
If you have 30cm flat ribbon cable with SDA and SCL next to each other, then 30cm is too long. The SDA and SCL should never be next to each other.
Can you give a link to your BME280 module ?
And a link to your DS3231 module ?

If you power the DS3231 with 3.3V, then the high level of SDA and SCL is not high enough for the Nano. If you power it with 5V, then the BME280 gets even more 5V leaking into its SDA and SCL pins via pullup resistors.
The LCD display must run at 5V. I think it has pullup resistors for SDA and SCL. That means that the BME280 already might get damaged.

You could read this, if you have some spare time: How to make a reliable I2C bus.

The DS3231 can operate at 5V. The BME280 not but OP may have a board with level shifters & regulator in place - but it's not specified... 1602 displays are usually 5V but they also come in 3.3V versions.

Too many unknowns.

alto777:
TBC the servo not in the drawing but that you specify, MG 995:

Item Name: MG995 Metal Gear Servo
...
Operation Voltage: 4.8 - 7.2 Volts

so good that you haven't killed it yet, don't keep trying to.

a7

Hear you now.. The issue was I bought this off a local site in Turkey. The small bag it came in said "ARDUİNO MG995 12 ". Checking the site I bought again; it was actually the "..12 KG..." they advertised not the Voltage.. That's why I used 12V DC adaptor :o See below the link I bought:
https://www.hatfon.com/urun/arduino-mg995-12-kg-360-derece-servo-motor-an-b120a

Will change that immediately not to fry it.. Thank you sir..

Don't guess. Don't trust whatever sellers tell you. Read the datasheet of the part (even if it's as simple as can be - like for this servo).

wvmarle:
The backlight diode of the LCD if on may put the current draw over what the Arduino can handle when powered at 12V (and its small internal regulator overheats). You better get a 5V adapter for the Arduino and other 5V peripherals (power everything from their respective 5V pins) - an old mobile phone charger will do fine, likely you have a few collecting dust in a drawer. A USB adapter with USB cable to the USB plug of the Arduino is another decent alternative; then the peripherals get their power from the 5V pin (limited but plenty for your display and sensors).

Adding the relay's coil current in the mix will definitely overheat that regulator, and that in turn may cause crashes or otherwise odd behaviour when the regulator decides to shut down to protect itself.

The servo is rated 4.8-6V, you're overpowering it. This may damage the servo. Especially when the servo is under load this may lead to overheating and possibly fire. A second phone charger (one that can output at least 2A) would be a really good alternative here. In fact, you can power the whole thing from a single 5V, 2A (or more) phone charger.

I thought recomended input voltage was 7-12V. It even says in Arduino site..
Input Voltage (recommended)
7-12V

Are you saying I should use usb port to power arduino and another one going to 5V pin?
That's actually another puzzle I'm trying to solve; I already have AC cable for bulp; another for arduino and one more for servo.. How many adoptors and cable I need :slight_smile:

Can you please clarify if my undersanding above was correct?

In fact, you can power the whole thing from a single 5V, 2A (or more) phone charger.
I was worried arduino can act strange when servo runs. If power source is 5V, it wouldn't be an issue?

The Arduino runs at 5V, so it needs 5V, and that Vin goes through a linear regulator. A nice extra from before the era of before ubiquitous mobile phones and spare chargers, and a lack of regulated power supplies in general.