DS3231 RTC counter

Hi,

I want to use DS3231 to check the status of a variable after every 20 minutes. How can i do this? Any code available.

Dave

Read the RTC every 1 second when the time is on the hour, 20 and 40 minutes after the hour AND seconds = 0, go ahead and read what you need to.

Hi,

Thanks for the reply! How can I read RTC every second? Do you have any code example?

Dave

Post the code you have, using code tags ("</>" button).

Have you written any sketches that uses millis() for timing?

Got to go out right now but, here is some code (note compiled or otherwise checked out) which may help you to see how to use millis() to read the RTC every 1000ms (1 second):

#include "Wire.h"
#define DS3231_I2C_ADDRESS 0x68

byte Second;
byte Minute;
byte Hour;
byte DayOfWeek;
byte DayOfMonth;
byte Month;
byte Year;

unsigned long currentMillis; 
unsigned long clockMillis;  

void setup()
{
  Wire.begin(); 
}

void loop()
{
  if(millis() - clockMillis >=1000) //every 1000ms
  {  
    clockMillis = clockMillis +1000;
    updateClock();
  }
}

void updateClock()
{
  //get the current time from the RTC
  readDS3231time(&Second, &Minute, &Hour, &DayOfWeek, &DayOfMonth, &Month, &Year);
  //Other clock code here
}

//                        r e a d D S 3 2 3 1 t i m e ( )
//=================================================================================
// From Tronixstuff
//
void readDS3231time(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  // request seven bytes of data from DS3231 starting from register 00h
  *second     = bcdToDec(Wire.read() & 0x7f);
  *minute     = bcdToDec(Wire.read());
  *hour       = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek  = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month      = bcdToDec(Wire.read());
  *year       = bcdToDec(Wire.read());

} // END of readDS3231time()

//                            b c d T o D e c ( )
//=================================================================================
// Convert binary coded decimal to normal decimal numbers 
//
byte bcdToDec(byte val) 
{
  return( (val / 16 * 10) + (val % 16) );

} // END of bcdToDec()

Hello and welcome,

Using millis() and checking if RTC's second is 0, as suggested by LarryD, is NOT a good method because it will fail sometimes.

The DS3231 have an alarm feature, that you can set to every minute. I recommend using this library.

Example:

In setup()

RTC.alarm( ALARM_1 ); // clear alarm1 flag, just in case
RTC.setAlarm( ALM1_MATCH_SECONDS, 0, 0, 0, 0 ); // alarm1 flag will be set every minute

Then in loop() you can do something like this, if you don't care about which minutes it will run (most likely not at HH:00, HH:20, HH:40 )

if ( RTC.alarm( ALARM_1 ) ) // if alarm1 flag is set (calling this function will reset the flag for the next alarm)
{
    static uint8_t counter;

    if ( ++counter == 20 )
    {
        doSomethingEvery20Minutes();
        counter = 0;
    }
}

Or, if you want the code to run at HH:00, HH:20, HH:40, you could do something like this:

if ( RTC.alarm( ALARM_1 ) ) // if alarm1 flag is set (calling this function will reset the flag for the next alarm)
{
    tmElements_t tm;
    RTC.read( tm );

    if ( tm.Minute % 20 == 0 )
    {
        doSomethingEvery20Minutes();
    }
}

If you want to save some power you can also put your arduino into sleep mode and have the RTC's alarm to wake the Arduino, but that is another story :wink:

You can also set the RTC up to generate a 1Hz o/p and then monitor this on an input pin.

Using millis() and checking if RTC's second is 0, as suggested by LarryD, is NOT a good method because it will fail sometimes.

All you have to do is read the RTC more frequent. example every 50ms or100ms etc.

Hi,

I set the DS3231 to 7 AM. ( 7 : 00:00). Then after half an hour, I reset the power of DS3231. The DS3231 did not set itself to the current local time. It reset itself to 7AM.

I repeated this experiment for several different times and duration but got the same results.

I am using the following module / kit

Dave

I set the DS3231 to 7 AM. ( 7 : 00:00). Then after half an hour, I reset the power of DS3231. The DS3231 did not set itself to the current local time. It reset itself to 7AM.

Post the code you are using, and a link to any library involved.

Here, you go

#define DS3231_I2C_ADDRESS 0x68
// Convert normal decimal numbers to binary coded decimal

byte decToBcd(byte val)
{
  return( (val/10*16) + (val%10) );
}
#include <RTClib.h>
#include <DS3231.h>
#include <DS3232RTC.h> 
#include <Time.h>

void setup() 
{
  Wire.begin();
  Serial.begin(9600);
  
  // set the initial time here:
 // DS3231 seconds, minutes, hours, day, date, month, year;
 
  setDS3231time(00,24,23,07,28,12,15);
  
  pinMode(enable, OUTPUT);
  pinMode(PWMA, OUTPUT);
  pinMode(PWMB, OUTPUT);//three pins for MegaMoto
  digitalWrite(enable,HIGH);

}

bool IsDST(int dayOfMonth, int month, int dayOfWeek)
{
  if (month < 3 || month > 11)
  {
    return false;
  }
  if (month > 3 && month < 11)
  {
    return true;
  }
  
  int previousSunday = dayOfMonth - (dayOfWeek - 1); // Spark Sunday = 1
  //In march, we are DST if our previous sunday was on or after the 8th.
  if (month == 3)
  {
    return previousSunday >= 8;
  }
  //In November we must be before the first sunday to be dst.
  //That means the previous sunday must be before the 1st.
  return previousSunday <= 0;
}

//void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte
//dayOfMonth, byte month, byte year, float Minutes)

void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year)

{
  // sets time and date data to DS3231
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set next input to start at the seconds register
  Wire.write(decToBcd(second)); // set seconds
  Wire.write(decToBcd(minute)); // set minutes
  Wire.write(decToBcd(hour)); // set hours
  Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday)
  Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31)
  Wire.write(decToBcd(month)); // set month
  Wire.write(decToBcd(year)); // set year (0 to 99)
  Wire.endTransmission();
 // setYear(byte Year); 
}


void readDS3231time(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
int *year)

{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  // request seven bytes of data from DS3231 starting from register 00h
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = 2000+bcdToDec(Wire.read());
}

void displayTime(int second, int minute, int hour, int dayOfWeek, int dayOfMonth, int month, int year)
{
  char buf[26];
  snprintf(buf,sizeof(buf),"%02d.%02d.%04d  %02d:%02d:%02d  ", dayOfMonth, month, year, hour, minute, second);
  Serial.print(buf);
  Serial.print("\n");
}

void loop()  

{


  int year;
  
  byte month,dayOfWeek,dayOfMonth,hour,minute,second;
  
  readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
  
  displayTime(second, minute, hour, dayOfWeek, dayOfMonth, month, year);


 }
 setDS3231time(00,24,23,07,28,12,15);

This line should be commented out after you set the time. It keeps resetting the time each time the sketch is started.

#include <RTClib.h>
#include <DS3231.h>
#include <DS3232RTC.h>

One library should do you. I recommend Jack Christensen’s DS3232RTC.h http://github.com/JChristensen/DS3232RTC

If you are using a library, you do not need all the low level functions in your sketch.