RTC and Interval Timing

Hello peeps! So I am trying to troubleshoot a problem that I'm having with a program I have been trying to fine tune for a future project. Currently the program runs on an Arduino Mega 2560 and controls 4 relays using a DHT11 temp/humidity sensor and an RTC3231.
The issue that I'm having is when I try to create two separate scenarios in the same hour. I am trying to get one of my relays to switch on during the first 10 minutes of the hour, and a 10 minute block in the middle of the hour (XX:30-XX:40). The way I currently have it written causes a complete failure of the function all together and the relay just doesn't turn on at all. What I would like to know is why would that happen, and how can I change what I currently have to make this work?
Any help would be appreciated as I am trying to eventually use this as the root program for the same controller but with an LCD button display that will allow me to manipulate these options as well as the humidity/temp.
Thanks Everybody!

#include <DS3231.h>
#include <Wire.h>
#include "DHT.h"

// Define the "data in" pin for the DHT11
#define DHTPIN A3

// Define which type of sensor 
#define DHTTYPE DHT11  //DHT 11

// Initialize DHT sensor.
DHT dht(DHTPIN, DHTTYPE);


// Set Relay constants to digital pins 4-7
const int RELAY1 = 8;
const int RELAY2 = 9;
const int RELAY3 = 10;
const int RELAY4 = 11;

// Identify clock variables
DS3231 Clock;
bool Century = false;
bool h12;
bool PM;
byte ADay, AHour, AMinute, ASecond, ABits;
bool ADy, A12h, Apm;

byte year, month, date, DoW, hour, minute, second;


void setup() {
  
  // Set pinMode for RELAYs 1-4 to OUTPUT
  pinMode(RELAY1, OUTPUT);
  pinMode(RELAY2, OUTPUT);
  pinMode(RELAY3, OUTPUT);
  pinMode(RELAY4, OUTPUT);
  

  // Start I2C interface
  Wire.begin();
  Clock.setSecond(20);//Set the second
  Clock.setMinute(18);//Set the minute
  Clock.setHour(13);  //Set the hour
  Clock.setDoW(3);    //Set the day of the week
  Clock.setDate(24);  //Set the date of the month
  Clock.setMonth(8);  //Set the month of the year
  Clock.setYear(16);  //Set the year (Last two digits of the year)
  
  // Begin serial interface
  Serial.begin(115200);
  
  Serial.println("DHT11 test!");
  
  dht.begin();

}

void ReadDS3231()
{
  // Initialize variables for time

  // Print time

}


void loop() {
  // Read the RTC module
  ReadDS3231();
  delay(1000);
  
  // Set local variables for RTC relay logic
  int second, minute, hour, date, month, year, temperature;
  second = Clock.getSecond();
  minute = Clock.getMinute();
  hour = Clock.getHour(h12, PM);
  date = Clock.getDate();
  month = Clock.getMonth(Century);
  year = Clock.getYear();
  
  // Print readout for RTC module
  Serial.print("20");
  Serial.print(year, DEC);
  Serial.print('-');
  Serial.print(month, DEC);
  Serial.print('-');
  Serial.print(date, DEC);
  Serial.print(' ');
  Serial.print(hour, DEC);
  Serial.print(':');
  Serial.print(minute, DEC);
  Serial.print(':');
  Serial.print(second, DEC);
  Serial.print('\n');

  
  // Sets fan interval
  if ( minute >= 0 && minute < 10 )
  {
    digitalWrite ( RELAY2, HIGH );
  }
  else
  {
    digitalWrite ( RELAY2, LOW );
  }
  if ( minute >= 30 && minute < 35 )
  {
    digitalWrite ( RELAY2, HIGH );
  }
  else
  {
    digitalWrite ( RELAY2, LOW );
  }
  */
  // Turn on relay from 6am to 6pm
  if ( hour >= 6 && hour < 18 )
  {
    digitalWrite ( RELAY3, HIGH );
  }
  else
  {
    digitalWrite ( RELAY3, LOW );
  }
  
    // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float f = dht.readTemperature(true);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }

  // Compute heat index in Fahrenheit (the default)
  float hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(t, h, false);
  
  
  // Print readout from DHT11 sensor
  Serial.print("Humidity: ");
  Serial.print(h);
  Serial.print(" %\t");
  Serial.print("Temperature: ");
  Serial.print(t);
  Serial.print(" *C ");
  Serial.print(f);
  Serial.print(" *F\t");
  Serial.print("Heat index: ");
  Serial.print(hic);
  Serial.print(" *C ");
  Serial.print(hif);
  Serial.println(" *F");
  
  
  // Sets parameter for Humidity RELAY1 switch
  if (h < 89.00)
  { 
    digitalWrite(RELAY1, HIGH);
  }
  else 
  {
    digitalWrite(RELAY1, LOW);
  }
  
  // Sets parameter for Temperature RELAY4 switch
  /*  if (t <= 70.00)
  { 
    digitalWrite(RELAY4, HIGH);
  }
  else 
  {
    digitalWrite(RELAY4, LOW);
  }
  */

Which RTC library are you using?

It is DS3231.h
The readme doc states that it "was original code by Eric Ayars 4/1/11

Where did you get it? Is that the one? GitHub - NorthernWidget/DS3231: Communicates between Arduino-programmed AVR and Maxim DS3231 RTC: splice of Ayars' (http://hacks.ayars.org/2011/04/ds3231-real-time-clock.html) and Jeelabs/Ladyada's (https://github.com/adafruit/RTClib) libraries

I am not certain. It does look like the one that I have thought

How did you get it? Is it up to date?

I've seen more frequently DS3231 - Rinky-Dink Electronics or GitHub - JChristensen/DS3232RTC: Arduino Library for Maxim Integrated DS3232 and DS3231 Real-Time Clocks

You can use the library to manage alarms

Ok so I was reading on the library DS3231 - Rinky-Dink Electronics and might have a hypothesis. In this section

IMPORTANT:

The library has not been tested in combination with the Wire library and I have no idea if they can share pins. Do not send me any questions about this. If you experience problems with pin-sharing you can move the DS3231/DS3232 SDA and SCL pins to any available pins on your development board. This library will in this case fall back to a software-based, TWI-/I2C-like protocol which will require exclusive access to the pins used.

Now in my program I am using the Wire library. I will have to check my wiring diagram but I am also pretty sure that I may be using the pin configuration he's talking about. Could this be a pin sharing problem that this refers to?
If so would I have to do a lot of rewriting to my program to correct this?

What he is saying is this

If you experience problems with pin-sharing you can move the DS3231/DS3232 SDA and SCL pins to any available pins on your development board. This library will in this case fall back to a software-based, TWI-/I2C-like protocol which will require exclusive access to the pins used.

That is if you have issues by sharing SDA / SCL (the wire protocol is meant to be shared between multiple devices) then you can use his library with non SDA/SCL pins of your hardware and his library will handle that OK so that the rest of your wire needs works fine

I see. So if I wanted to use the "Rinky-Dink" library would I just substitute the libraries? I guess i just don't understand, keep in mind I know very little about coding. This is a real learning experience.

I looked at the manual and an example sketch for the "serial easy" and I can't tell if it uses the same Variables/phrases to accomplishes tasks.

Ideally what I am trying to do with this is to set time, and recall minutes data to set a timer for XX:00-XX:03, and XX:10-XX:13, and XX:20-XX:23, etc... to activate a relay. This will also be occurring while the Mega reads my DS3231 to activate a separate relay based on 12 hour on/off cycles and reads a DHT11 to manage another relay based on the Humidity information.

Use unix timestamps instead, it will be much easier. You can use the Time library to convert time from/to unix timestamp.

guix:
Use unix timestamps instead, it will be much easier. You can use the Time library to convert time from/to unix timestamp.

Is there any example code I could use? I'm beginning to think I'll have to completely rewrite my program won't I?

guix:
Use unix timestamps instead, it will be much easier. You can use the Time library to convert time from/to unix timestamp.

Anything?

guix:
Use unix timestamps instead, it will be much easier. You can use the Time library to convert time from/to unix timestamp.

I was doing some reading this morning and came across this interesting post
http://forum.arduino.cc/index.php?topic=380592.0
and was curious if something like this could help me achieve what I'm trying to do? I have been trying to find something that explains how to use unix timestamps but I'm still a little confused I guess.

I think you are going distracted by other things than your case at hand.

You stated your intent was as follow "I am trying to get one of my relays to switch on during the first 10 minutes of the hour, and a 10 minute block in the middle of the hour (XX:30-XX:40). "

The hardware you have available for this is

  • Mega 2560
  • an RTC3231.
  • a DHT11 temp/humidity sensor
  • 4 relays to take actions

From a programming standpoint you have 2 options:

Option 1
use to loop() and poll the RTC
see if you have reached a time where action needs to be start and action is not started
if so take the action and mark in some way that this action is started
see if you have reached a time where action needs to be stop (and is started)
if so take the action and mark in some way that this action is stopped

this is pretty straightforward to code assuming your RTC is properly set and you know how to extract time information. Usually best way to proceed is to build a unique number from hour, minute, second by doing (hour x 3600 + minute x 60 + second) which gives you a unique time stamp for a day and compare that to the timestamp of your actions.

Option 2
The RTC component you have has "alarm" capabilities. so instead of polling constantly in the loop() the RTC, use the alarm functions the RTC to call you back when something needs to happen.

Does this help?

I'm still a little confused I guess.

That makes two of us.

I still don't know which library you are using. I strongly recommend that you start over with the Christensen library. It integrates with the time library well, and will handle alarms.

Break your project into smaller pieces, and learn how to handle the relays and RTC by themselves. Then add in the DHT.

The way I currently have it written causes a complete failure of the function all together and the relay just doesn't turn on at all.

I'm not sure I see why this is the code you posted, so I would go back to a known and reliable library and verify how the relays are driven.

cattledog:
That makes two of us.

I still don't know which library you are using. I strongly recommend that you start over with the Christensen library. It integrates with the time library well, and will handle alarms.

Break your project into smaller pieces, and learn how to handle the relays and RTC by themselves. Then add in the DHT.

I'm not sure I see why this is the code you posted, so I would go back to a known and reliable library and verify how the relays are driven.

Ok so in response to this I have downloaded the suggested libraries. I agree with breaking this into smaller pieces. You have to understand the existing device I built/programmed was the first electronics project I have ever taken on and I haven't tried to refine in almost a year so Please, Please be patient. I am trying to get back into this.

J-M-L:
I think you are going distracted by other things than your case at hand.

You stated your intent was as follow "I am trying to get one of my relays to switch on during the first 10 minutes of the hour, and a 10 minute block in the middle of the hour (XX:30-XX:40). "

The hardware you have available for this is

  • Mega 2560
  • an RTC3231.
  • a DHT11 temp/humidity sensor
  • 4 relays to take actions

From a programming standpoint you have 2 options:

Option 1
use to loop() and poll the RTC
see if you have reached a time where action needs to be start and action is not started
if so take the action and mark in some way that this action is started
see if you have reached a time where action needs to be stop (and is started)
if so take the action and mark in some way that this action is stopped

this is pretty straightforward to code assuming your RTC is properly set and you know how to extract time information. Usually best way to proceed is to build a unique number from hour, minute, second by doing (hour x 3600 + minute x 60 + second) which gives you a unique time stamp for a day and compare that to the timestamp of your actions.

Option 2
The RTC component you have has "alarm" capabilities. so instead of polling constantly in the loop() the RTC, use the alarm functions the RTC to call you back when something needs to happen.

Does this help?

In response to this. I would like to do this using the Alarm capabilities and am trying to base this off of the Time Alarms library. I think I would be using

"Alarm.timerRepeat(Period, TimerFunction);
Description: Continuously calls user provided TimerFunction after the given period in seconds has elapsed."

to accomplish this. Also, I assume that "TimerFunction" is a generic phrase? Would I place my own callback function? For instance, can i have my on/off function assigned as AlarmOn and AlarmOff in the setup?

Let me ask this. Is there a way to express this so that I am only using recalled minutes data to perform an action like this for every hour without writing 24 blocks?
"
if time = 00,00,00 - relay on
if time = 00,08,00 - relay off
if time = 00,30,00 - relay on
if time = 00,38,00 - relay off
"
DoW is not any concern.
Seconds are not any concern.

This is not an emergency situation mind you. I have my current microcontroller running but in the coming months i am going to need the freedom to adjust things so that I can manipulate the amount of times per hour this relay turns on and for what period of minutes.

Is there a way to express this so that I am only using recalled minutes data to perform an action like this for every hour without writing 24 blocks?

  // Sets fan interval
  if ( minute >= 0 && minute < 10 )
  {
    digitalWrite ( RELAY2, HIGH );
  }
  else
  {
    digitalWrite ( RELAY2, LOW );
  }
  if ( minute >= 30 && minute < 35 )
  {
    digitalWrite ( RELAY2, HIGH );
  }
  else
  {
    digitalWrite ( RELAY2, LOW );
  }

It's not clear to me why this code did not work as you intended. I'm not sure if you had the correct syntax for reading the RTC, or if the relays were not connected properly or of the correct logic. You could add some serial debug commands to see what the actual value of minute going into our conditional tests.

You really do need to break your project into pieces. Can you make the relays operate correctly with digitalWrite() commands? Can you get the correct time from the RTC? Linking the two, or using the time library will not be difficult if you have all the pieces working on their own.

cattledog:

  // Sets fan interval

if ( minute >= 0 && minute < 10 )
  {
    digitalWrite ( RELAY2, HIGH );
  }
  else
  {
    digitalWrite ( RELAY2, LOW );
  }
  if ( minute >= 30 && minute < 35 )
  {
    digitalWrite ( RELAY2, HIGH );
  }
  else
  {
    digitalWrite ( RELAY2, LOW );
  }





It's not clear to me why this code did not work as you intended. I'm not sure if you had the correct syntax for reading the RTC, or if the relays were not connected properly or of the correct logic. You could add some serial debug commands to see what the actual value of minute going into our conditional tests.

You really do need to break your project into pieces. Can you make the relays operate correctly with digitalWrite() commands? Can you get the correct time from the RTC? Linking the two, or using the time library will not be difficult if you have all the pieces working on their own.

I am not entirely sure why it didn't work either. It has been cause for much frustration.
The clock is reset every time I hook the controller up to my computer and I open the serial monitor so the time is always synchronized. There are no problems displaying time in the serial monitor. If I have the second portion of the timer commented out so that the only thing that reads is the first action of 0-10 minutes the relay operates as it should. It is only when the second line is active that the controller glitches. It will sometimes work for a while and just simply stop writing the pin on, or it just doesn't turn on at all.
Is there a chance that the system is getting caught in a loop of trying to determine if the time is correct for the first or second block?

cattledog:

  // Sets fan interval

if ( minute >= 0 && minute < 10 )
  {
    digitalWrite ( RELAY2, HIGH );
  }
  else
  {
    digitalWrite ( RELAY2, LOW );
  }
  if ( minute >= 30 && minute < 35 )
  {
    digitalWrite ( RELAY2, HIGH );
  }
  else
  {
    digitalWrite ( RELAY2, LOW );
  }





It's not clear to me why this code did not work as you intended. I'm not sure if you had the correct syntax for reading the RTC, or if the relays were not connected properly or of the correct logic. You could add some serial debug commands to see what the actual value of minute going into our conditional tests.

You really do need to break your project into pieces. Can you make the relays operate correctly with digitalWrite() commands? Can you get the correct time from the RTC? Linking the two, or using the time library will not be difficult if you have all the pieces working on their own.

Would it be possible to rewrite the expression as follows?

if ( minute >= 0 && minute <10 ) || (minute >= 30 && minute < 40 );
{
  digitalWrite ( Relay2, HIGH);
}
else
{
  digitalWrite ( Relay2, LOW);
}

I would be using the "||" ("or") logic function.

I apologize. I did not look at your code carefully enough. The cascaded if/else conditions are turning the relays back off.

Your latest formulation looks correct. but remove the semicolon on the first line and check the parenthesis.

if( ( minute >= 0 && minute <10 ) || (minute >= 30 && minute < 40 ) )
{
  digitalWrite ( Relay2, HIGH);
}
else
{
  digitalWrite ( Relay2, LOW);
}

You could also try

 // Sets fan interval
  if ( minute >= 0 && minute < 10 )
  {
    digitalWrite ( RELAY2, HIGH );
  }
  //else
 // {
 //   digitalWrite ( RELAY2, LOW );
 // }
else  if ( minute >= 30 && minute < 35 )
  {
    digitalWrite ( RELAY2, HIGH );
  }

  else
  {
    digitalWrite ( RELAY2, LOW );
  }