I2C RTC & OLED loop breaks

Dear All,

I am having a trouble with Arduino where I have assembled a project, at various stages it worked, but at the moment after a while loop breaks, OLED screen freezes and loop no longer works.

Project in a nutshell:

There are 2 sensors: MQ135 for air quality reading & Moisture sensor
There are 2 relays connected to Arduino
There is also an RTC & OLED screen both connected though I2C

What code does in a loop:

Take air & moisture readings and display on screen,
Take RTC reading, and depending on values switch relays on or off depending on predefined time parameters.

Because code works for a while, and does exactly what intended I have pinned the problem to one of the following problems:

  1. When I2C devices disconnect while Arduino is running, loop breaks. Maybe there is a loose connection, although I have checked it over and over again.

  2. Problem with the code (this is my weakness, as it is my first Arduino project). Tried to check variables, but not sure what can cause the problem

  3. Incorrect circuit - missing resistors?

Any help and advice is highly appreciated. Code is below and circuit is attached.
Please excuse my lack of proficiency in the way code is written and circuit is built, this is my first project.

Many thanks!

//-----below is definition of relay pins
int rly_1 = 12;
int rly_3 = 11;

//-----variable for moisture
float moist_v;
float min_mst = 100;
float max_mst = 0;

//-----below are LCD library setups-----

#include "SSD1306Ascii.h"
#include "SSD1306AsciiAvrI2c.h"

// 0X3C+SA0 - 0x3C or 0x3D
#define I2C_ADDRESS 0x3C

// Define proper RST_PIN if required.
#define RST_PIN -1

SSD1306AsciiAvrI2c oled;

//-----below are RTC library setups-----
#include <DS3231.h>

// Init the DS3231 using the hardware interface
DS3231  rtc(SDA, SCL);
Time  t;

//-----CO2 sensor setup------
#define anInput     A1                        //analog feed from MQ135
#define co2Zero     0  

float co2_min = 5000;
float co2_max = 0;

void setup()
{
//-----below is setup for RTC------
  Serial.begin(9600);
  // Uncomment the next line if you are using an Arduino Leonardo
  //while (!Serial) {}
  
  // Initialize the rtc object
  rtc.begin();
  
  //The following lines can be uncommented to set the date and time
//  rtc.setDOW(WEDNESDAY);     // Set Day-of-Week to SUNDAY
//  rtc.setTime(17, 33, 40);     // Set the time to 12:00:00 (24hr format)
//  rtc.setDate(4, 11, 2018);   // Set the date to January 1st, 2014
  
//-----below is setup for LCD-----

  #if RST_PIN >= 0
  oled.begin(&Adafruit128x64, I2C_ADDRESS, RST_PIN);
#else // RST_PIN >= 0
  oled.begin(&Adafruit128x64, I2C_ADDRESS);
#endif // RST_PIN >= 0

  oled.setFont(Adafruit5x7);

  uint32_t m = micros();
  oled.clear();

//-----below is setup pf relays-----

  pinMode(rly_1, OUTPUT);
  digitalWrite(rly_1, HIGH);
  pinMode(rly_3, OUTPUT);
  digitalWrite(rly_3, HIGH);
  
}

void loop()
{
  //-----int for co2-----
  
  int co2now[10];
  int co2raw = 0; 
  int co2comp = 0;
  int co2ppm = 0; 
  int zzz = 0;
  int grafX = 0;
  
  //-----below are variables for co2 measurement
  
  for (int x = 0;x<10;x++){                   //samplpe co2 10x over 1 seconds
    co2now[x]=analogRead(A1);
    delay(100);
  }
  
  oled.clear(); // clear display after 1 sec delay above
  
  for (int x = 0;x<10;x++){                     //add samples together
    zzz=zzz + co2now[x];
  }
  
  co2raw = zzz/10;                            //divide samples by 10
  co2comp = co2raw - co2Zero;                 //get compensated value
  co2ppm = (map(co2comp,0,1023,400,5000) - 100);      //map value for atmospheric levels
  
  if(co2ppm < co2_min) {
  co2_min = co2ppm;
  }
  
  if(co2ppm > co2_max) {
  co2_max = co2ppm;
  }

  //-----below is code for moisture sensor-----
  
  int mst_sens = analogRead(A0);
  moist_v = (((1023 - mst_sens)*100L / 1023 ));
  
  
  if(moist_v > max_mst) {
  max_mst = moist_v;
  }
  
  if(moist_v < min_mst) {
  min_mst = moist_v;
  }
  
  
  //-----below are variables for relays-----
  
  int cycle_1 = (12 * 60); //time in minutes
  int cycle_3 = (1 * 60); //time in minutes
  int on_1 = 35; //time in seconds to be on -> water
  int on_3 = 20; //time in seconds to be on
  int start_r1_h = 9; //first time start of relay 1 in hours
  int start_r1_m = 0; //first time start of relay 1 in minutes
  int start_r3_h = 9; //first time start of relay 3 in hours
  int start_r3_m = 0; //first time start of relay 3 in minutes
  
  
    // Get data from the DS3231
  t = rtc.getTime();
  int rtc_in_min = t.hour * 60 + t.min;
  int start_r1 = ((start_r1_h * 60) + start_r1_m);
  int start_r3 = ((start_r3_h * 60) + start_r3_m);
  int disp_rly1 = cycle_1 - (mod((rtc_in_min - start_r1),  cycle_1)); //to display relays time left to screen
  int disp_rly3 = cycle_3 - (mod((rtc_in_min - start_r3),  cycle_3)); //to display relays time left to screen

//-----print time-----


  oled.print("Time: ");
  char s1[2] = "";
  char s2[10] = "";
  dtostrf(t.hour, 2, 0, s1);
  strcat(s2, s1);
  strcat(s2, ":");
  dtostrf(t.min, 2, 0, s1);
  strcat(s2, s1);
  strcat(s2, ":");
  dtostrf(t.sec, 2, 0, s1);
  strcat(s2, s1);
  oled.print(s2);



//-----turn relay 1 on/off-----
  
  if(mod((rtc_in_min - start_r1),  cycle_1) < 1) { //below this is screen refresh time
    
    if(t.sec <= on_1) {
      digitalWrite(rly_1, LOW);
       //-----below if text for display-----
        char on_time[2] = "";
        oled.println();
        oled.print("R1 eng'd for ");
        int t_left = on_1 - t.sec;
        dtostrf(t_left, 2, 0, on_time);  
        oled.print(on_time);
        oled.print(" sec");
    }
    else{
      digitalWrite(rly_1, HIGH);
      //-----below if text for display-----
      char s_rly1[3] = "";
      char relay_num[5] = "R1 in";
      oled.println();
      oled.print(relay_num);
      dtostrf(disp_rly1, 5, 0, s_rly1);
      oled.print(s_rly1);
      oled.print(" min. (");
      oled.print(on_1);
      oled.print("s)");
    }
  }
  else  {
    digitalWrite(rly_1, HIGH);
      //-----below if text for display-----
      char s_rly1[3] = "";
      char relay_num[5] = "R1 in";
      oled.println();
      oled.print(relay_num);
      dtostrf(disp_rly1, 5, 0, s_rly1);
      oled.print(s_rly1);
      oled.print(" min. (");
      oled.print(on_1);
      oled.print("s)");
  }
  
//-----turn relay 3 on/off + display relevant text-----

  if(mod((rtc_in_min - start_r3),  cycle_3) < 1) { //below this is screen refresh time
    
    if(t.sec <= on_3) {
      digitalWrite(rly_3, LOW);
        //-----below if text for display-----
        char on_time[2] = "";
        oled.println();
        oled.print("R3 eng'd for ");
        int t_left = on_3 - t.sec;
        dtostrf(t_left, 2, 0, on_time);  
        oled.print(on_time);
        oled.print(" sec");
          }
    else{
      digitalWrite(rly_3, HIGH);
      //-----below if text for display-----
      char s_rly3[3] = "";
      char relay_num[5] = "R3 in";
      oled.println();
      oled.print(relay_num);
      dtostrf(disp_rly3, 5, 0, s_rly3);
      oled.print(s_rly3);
      oled.print(" min. (");
      oled.print(on_3);
      oled.print("s)");
    }
  }
  else  {
    digitalWrite(rly_3, HIGH);
      //-----below if text for display-----
    char s_rly3[3] = "";
    char relay_num[5] = "R3 in";
    oled.println();
    oled.print(relay_num);
    dtostrf(disp_rly3, 5, 0, s_rly3);
    oled.print(s_rly3);
    oled.print(" min. (");
    oled.print(on_3);
    oled.print("s)");
  }
  
  //-----print CO2 + min/max values & moisture-----
  
  char str_co2_now[4] = "";
  char str_moist[4] = "";
  oled.println();
  oled.println();
  oled.print("  CO2     ");
  oled.print("% wet");
  dtostrf(co2ppm, 4, 0, str_co2_now);
  oled.println();
  oled.print("now:");
  oled.print(str_co2_now);
  oled.print("  now:");
  dtostrf(moist_v, 4, 0, str_moist);
  oled.print(str_moist);
  
  
  char str_co2_min[4] = "";
  char str_mst_min[4] = "";
  oled.println();
  oled.print("min:");
  dtostrf(co2_min, 4, 0, str_co2_min);
  oled.print(str_co2_min);
  oled.print("  min:");
  dtostrf(min_mst, 4, 0, str_mst_min);
  oled.print(str_mst_min);

  char str_co2_max[4] = "";
  char str_mst_max[4] = "";
  oled.println();
  oled.print("max:");
  dtostrf(co2_max, 4, 0, str_co2_max);
  oled.print(str_co2_max);
  oled.print("  max:");
  dtostrf(max_mst, 4, 0, str_mst_max);
  oled.print(str_mst_max);
  
}


int mod(int k, int n) {
  return ((k %= n) < 0) ? k+n : k;
  
}

Relays often cause problems. If you disconnect the relays do you see the problem?
Your circuit diagram shows no secondary output on the relays. What are they switching?
I'm not sure about the modules you are using, but powering the primary side of the relays from the Arduino directly is not good practice. Can you power them from something other than the 5v pin? Connect the grounds if you change the supply.

OP's attached circuit

Thank you Cattledog,

It is interesting you say that about relays.. I'd be concerned if there is no way around that :).

I will check without relays and come back.

Output to relays is connected to 240v, they control sockets.

Also interesting re power supply to relays, I will check that as a second point.

Will come back soon.

Thank you!

---UPDATE---

Cattledog, it starts looking like you were right about the relays. After disconnecting them, arduino has been running smoothly, although it was tested only for a few hours for now.

Many thanks for the advice!

One last clarification on your point re external power supply for relays: all other components aside, would you agree that the attached wiring for relay with external power is correct?

Thanks!

OptoRelay4X_Wiring.png

would you agree that the attached wiring for relay with external power is correct?

I think that's right. See Terry's information on wiring those relay modules. There's wiring information near the bottom of the page.

http://arduino-info.wikispaces.com/Relay-Board-How-To

Another page on isolation and noise
https://arduino-info.wikispaces.com/RelayIsolation

Yes, thank you! That is exactly what the article says!

Very interesting read on relays and EMI too, thanks!

I will mark thread as solved, and get back if problem occurs again.

Cheers!

-----UPDATE-----

Hey everyone & Cattledog,

It appears that everything was working when relays were disconnected completely.

Once I have connected relays with a separate power input, as per the diagram from my second last message, and the problem is back.

It appears that when relays are disengaged the problem occurs.

After having a read on this, it appears to be an EMI problem.

In terms of solutions, people suggest isolating circuit (which I have done), using capacitors and varistors get rid of the current (?) that is being sent back to Arduino when the relay is disengaged.

Unfortunately even after reading on about it, there is no clear solution that I see (probably due to my lack of knowledge on the subject).

Once again any help is appreciated!

thank you!

Output to relays is connected to 240v, they control sockets.

Once I have connected relays with a separate power input, as per the diagram from my second last message, and the problem is back.

It appears that when relays are disengaged the problem occurs.

I understand what you have done on the coil side of the relay. Can we focus on the output for a moment.

Are the relays controlling AC or DC? If there is nothing plugged into the socket, does the program fail?

What is plugged in to the socket to be switched? Is it inductive or resistive load?

If you have AC you may be better off with an SSR and zero crossing switching.

Are the relays controlling AC or DC? If there is nothing plugged into the socket, does the program fail?

What is plugged in to the socket to be switched? Is it inductive or resistive load?

Both relays control 240v AC power line. At the end of the power lines are: small aquarium water pump on one of them and small aquarium air pump on the other. Not sure which type of load that is..

When nothing is plugged in, everything and relays work fine.

If you have AC you may be better off with an SSR and zero crossing switching.

Could you please advise on where to find out more about that, with instructions if possible?

Many thanks!! :slight_smile:

To add to my last post, the 220V AC devices that are connected to the relay outputs are only 2watts and 4watts respectively.

It sounds like you have your problem well defined with the turn off of the AC motors on the output side of the relays.

Before changing from relays to SSRs I would explore noise suppression of the motors because you might need that with the SSR as well. You will need to place an RC snubber or MOV across the motor.

This hardware selection is not really my area, and I would just be giving back my internet search findings. I encourage you to spend some time with Mr Google or the forum search box as well. Your motors are pretty small, the 240V is standard and I don't think you will have a problem selecting something or building something yourself.

If after the research you can't decide on what to use, you might also want to make a new posting in the General Electronic section of the forum with your current problem statement, the latest isolated circuit diagram, the motor information, etc and ask for RC snubber or MOV recomendations.

There are other noise suppression things to consider like the distance between the Arduino and the motors. Possibly shielding the Arduino in some sort of metal box, or wrapping running the wires from the motors to the sockets around some ferrite cores which also suppresses transients.

EMI and electrical noise issues from switching inductive loads can be tricky. I think you've done the right things on the primary side. If after you work on the AC side for a bit and your problems don't go away then you will be needing the black magic.