Set/Get Hours with DS3231 rtc

I’m using a3231 rtc and want to let the user set the time/date. This is my function: ResetRTC()
All works fine for year, month, and date.
For hours, I can’t get anywhere.
I’ve attached a test version of the code, which compiles OK, but has a problem with the “hours.”
I’m using the library DS3231.h
I’d prefer to work in 24 hour time, but would also like the option of AM/PM if possible.

I’ve included in the sketch the few lines that really count for the test:
This is between the comment lines “Hour Test Section.”

  • read the hours; change the hours; set the new value; read the new value - and print each one in turn.

My output is to an lcd, and I’ve included the code to make the lcd work.

Incidentally, the function SwitchValue at the bottom (not used for this test) might be of interest to someone else.
It takes the input from two push-buttons (increase & decrease) and generates a value which tells if +,-,both or none is pressed. This is used for the year, month and date which all work well.

I must be missing something - but what is it?

Here is the code extract: (It contains lots of stuff not needed here.)

//  This used for hour test only.
// #ifndef DS3231_h;
// #define DS3231_h

//==================
#include <DS3231.h>
#include <Wire.h>
#include <LiquidCrystal.h>
#include <SoftwareSerial.h>

#include <SPI.h>                 //Serial Peripheral Interface
#include <Time.h>  // should include //#include <TimeLib.h>
// #include <RTCLib.h>
//#include <CurieTime.h>

 //SDA = 19=A5; SCL = 18=A4
  DS3231 Clock;  //  Not including this was the problem!!
//    Clock.begin();  // prevents compile
  bool Century = false;
  // ---- copied from example
byte Year;
byte Month;
byte Date;
byte DoW;
byte Hour;
byte Minute;
byte Second;

bool h12;
bool PM;
byte ADay, AHour, AMinute, ASecond, ABits;
bool ADy, A12h, Apm;

#define RX_PIN 6 // Arduino receive   GREEN WIRE   labeled TX on printer
#define TX_PIN 7 // Arduino transmit  YELLOW WIRE  labeled RX on printer
SoftwareSerial mySerial(RX_PIN, TX_PIN); // Declare SoftwareSerial obj first

const int rs = 8, en = 9, d4 = 5, d5 = 4, d6 = 3, d7 = 2;           //rs was originally pin 10. (either works OK)
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);                          //pins 8,9 work the lcd

int state = 0;
int cycleNum = 0;
float tempo = 0;
byte getYear();
byte getMonth();
byte getDate();

// Example has these before setup:
int swPlusPin = 15;   // The + switch is wired to Pin 15 = A1
int swMinusPin = 16;  // The - switch is wired to Pin 16 = A2  // Inpt_Pullup MUST be placed after Setup()!!

void setup()  {

  Wire.begin();
  pinMode(swPlusPin, INPUT_PULLUP);       //  A1 = 15  sw1   -   Does not compile if these are placed befor setup()
  pinMode(swMinusPin, INPUT_PULLUP);      //  A2 = 16  sw2

//  void setTime(int 15, int39, int 00, int 13, int 11, int 2018);

  // For lcd:
  lcd.begin(16, 2); // Initializes the interface to the LCD screen, and specifies the dimensions (width and height) of the display }
  // lcd display is:(Column, Row)
  mySerial.begin(9600);  // Initialize SoftwareSerial
  printer.begin();        // Init printer (same regardless of serial type
//  Clock.begin();

  //var init
  int state = 0;
  int cycleNum = 0;
  float tempo = 0;
  int swval = 5;   //initial value = nonsense

 }  //  end of setup  -  ready for  loop

void loop()  {  // ===========================================================
   lcd.clear();
  lcd.print("ST");  // start of loop
  delay(1000);
  lcd.clear();

  ResetRTC();  //  Invoke the function! Test only.

  delay(1000);
  lcd.clear();
  
  lcd.print("RTC done-loopend");
  delay(1000);
 
}  //  end of loop

 void ResetRTC()  // function definition
    {

// ------------------ Hour Set ---------------

//   swval = SwitchValue(); 

// while(swval != 3){  //  Keep going until both switches are hit!
                     //  Return is at the bottom    
// ----------------  copied from test example -----------------
byte Hour;
bool h12;
bool PM;
byte ADay, AHour, AMinute, ASecond, ABits;
bool ADy, A12h, Apm;

// ---------------------- Beginning of hour test section  -------------

lcd.clear();
// delay(1000);

    Clock.setClockMode(false);  // set to 24h
    //Clock.setClockMode(true); // set to 12h
  //Serial.print(Clock.getHour(h12, PM), DEC);
   // lcd.print(Clock.getHour(h12, PM), DEC);
   lcd.print("A");
// lcd.print(h12);
 delay(200);
    Clock.getA1Time(ADay, AHour, AMinute, ASecond, ABits, ADy, A12h, Apm);
  Hour = AHour;
lcd.print(AHour);
lcd.print("T");
    Clock.setHour(Hour);
//    Clock.get(Hour);  //  this does nor compile!
    Clock.getA1Time(ADay, AHour, AMinute, ASecond, ABits, ADy, A12h, Apm);
      lcd.print(AHour);
lcd.print(" N ");
  AHour = AHour + 5;
lcd.print(AHour);  // the new value
       Clock.setHour(AHour);
        delay(200);  // in case a wait is needed
    lcd.print("P");
   Clock.getA1Time(ADay, AHour, AMinute, ASecond, ABits, ADy, A12h, Apm);
lcd.print(AHour);
    lcd.print(" End");
 delay(1000);
  
//--------------  end of test hour section ---------------
lcd.clear();
lcd.print("End of RTC Set");
//delay(2000);
             
   }  // ===============  end of the function ResetRTC  ====================
//  ++++++++++++++++  Minute set ( mn ) +++++++++++++++++++++++

  // loop return is above the functions definitions

//====================== below here is the function  SwitchValue ===========

//   Function:  SwitchValue  -  as below, but including the get switch info.
//      It will return an integer (SS)and is invoked with the values of  sw1 and sw2 passed.

//   We have to define the variables to be used in the function:
// These must be defined in "Loop"  (They are Passed to the Function.)
 int sw1;
 int sw2;
 int Ntries;

int SwitchValue()
{ // start of the function
  Ntries = 2;

  // =================  First get the switches ==========================

  //  Get sw1 and sw2 states:
  int sw1p = digitalRead(swPlusPin);  //  The pullups go to + ; "!" to invert doesn't work here!(Switch op'n to gnd = 0; else = 1)
  int sw2p = digitalRead(swMinusPin);
  //  int sw1;  //  must define this here for loop.  Prior doesn't count!

  //===  here we Reverse the switch state
  if (sw1p == 0)
  {
    sw1 = 1;
  }
  else  {
    sw1 = 0;   //It must have been a 1.  Make it a zero
  }
  // ready for sw2
  if (sw2p == 0) {
    sw2 = 1;    // if it was a 0, make it  1
  }
  else {
    sw2 = 0;   //It must have been a 1.  Make it a zero
  }
  //  Here switch sate has been reversed to work with N.O. push-buttons

  //============================================
//  lcd.print("XY");   // to show where we are.
 //  Aboove should NOT show in real display!!
  //  sw1 and sw2  were already printed to lcd
  for (int i = 0; i <= Ntries; i++)
  { // No. 6 - outside loop; n tries
    if (sw1) {   //   No. 2  Was a + hit?
      // yes, Go to 4
      for (int j = 0; j <= Ntries; j++) { // No. 4  check for a -, given a +
        if (sw2) {  //  No.6
          return 3;  //  Both were hit
        }  // No.6  end
        else {
          //  a - was NOT hit after the initial +
        }
      } //  end of for stmt No. 4       // No.4   when No. 6 had no - switch hit  // Plus with no minus
      return 1;  //  Plus only was hit
    }  //  end of No. 2  -
    else {   //  No. 3
    }  // No. 2 return;
    //  Here is where we do  No.3  -  test if  - hit
    if (sw2) {  //  yes, it was a "-"
      for (int j = 0; j <= Ntries; j++) { // No.5
        if (sw1) {  //  No.7   //   SwitchState = 3;   // both  were hit
          return 3;  //  Both were hit
        }  // No.7 return - but still in No. 5
        else {
          //  here when  7  is  NO          // got a - but no +
          return 2;  // we got a  -  with no  + ; therefore SS=2
        }   //  No.5 return       //    return SwitchState;  //  end of for loop No.5
        //      else{  // NOW we start with when No. 3 was a N.
      }  //  end of the "for" loop No. 6
      //  here if neither switch was hit     //    SwitchState = 0;
      return 0;
    }
  }  // Return from No. 6
  return 0;  // mcb


}  // function return
   // (Loop return is above)
   //  End of the story!

RTC_Clock_Set_MCB_Hours_Problem.ino (9.75 KB)

I'm missing the link to the library you're using.

You don't write what your actual problem is. Is it that line:

//    Clock.get(Hour);  //  this does nor compile!

To get the hour you must use code like this:

bool h12;
bool ampm;
Clock.getHour(h12, ampm);

The boolean h12 will tell you if that strange american 12 hour mode is used and if it's true, ampm will tell you if the value returned is before or after noon.

Weren't those strange clocks invented in Europe or GB before there WAS an America? When were the strange European clocks changed to 24 hr? I would guess AFTER digital display clocks became widely available. Why is Big Ben still a 12 hr clock?

Why is Big Ben still a 12 hr clock?

I still couldn't find that AM/PM flag on Big Ben, can you help me? :wink:

I don't have a problem with an analog clock which has 12 hours in one turn but the solution to append that flag to tell people if the hours from 0 to 12 or from 12 to 24 are meant is a rather bad one in my opinion (and that is just my opinion, no offense!).

Thanks, Pylon, for your info.
I’m using the library <DS3231.h> as declared near the top of my code.
I tried using the h12 and ampm codes, but they seem to return nothing - or am I looking for the return incorrectly?

Also, I would prefer to work in 24 hour time - if possible.

Lastly, I must also be able to re-set the hours if the user so requires.
(The year, month and date work just fine for this - both set and get.)

Suggestions?

  • Matt

Problem:
You have a DS3231 RTC.
You also have an Arduino (presumably an Uno), a 16x2 LCD, and two push buttons.
Using the aforementioned hardware, you wish to allow the user to set the date and time on the RTC.

My solution:

Thanks, odometer, for your input.
You seem to be writing directly to the rtc using the wire.h library.
I haven't done this, as it seems that is should be possible more simply using functions in the DS3231.h library.
In fact, these simple statements work fine for get & set of the year, month and date.
I'd like to use similar get & set for the hours, and this is where my problem lies.

Any help will be appreciated. Perhaps a different 3231 library will have a simple command for the hours function.

mattbaum:
I’m using the library <DS3231.h> as declared near the top of my code.

Which one? There are so many with that name. Please provide a link to the one you are using.

And as for 12-hour format, the usual solution is to have the RTC keep time in 24-hour format, and have the Arduino do the math to convert to 12-hour format for display.

mattbaum:
I’d like to use similar get & set for the hours, and this is where my problem lies.

You mean like this? (WARNING: untested code!)

void numberToRTCRegister(byte myRegister, byte myNumber) {
  // convert myNumber to BCD
  byte tens = myNumber / 10;
  byte ones = myNumber % 10;
  byte myBCD = (tens * 0x10) + ones;
  
  // write the number to the appropriate RTC register
  Wire.beginTransmission(0x68); // address DS3231
  Wire.write(myRegister); // select register
  Wire.write(myBCD);
  Wire.endTransmission();
}

byte numberFromRTCRegister(byte myRegister) {
  Wire.beginTransmission(0x68); // 0x68 is DS3231 device address
  Wire.write(myRegister); // start at the appropriate register
  Wire.endTransmission();
  Wire.requestFrom(0x68, 1); // request one byte
  if (Wire.available()) { // check to make sure we received something
    // convert received data from BCD to binary
    byte myBCD = Wire.read();
    byte tens = myBCD / 0x10;
    byte ones = myBCD % 0x10;
    byte myNumber = (tens * 10) + ones;
    return myNumber; // and we're done!
  }
  // even if we did not receive valid data, we still have to return something
  return 255; // number to indicate that no valid data was received
}

void setHours(byte myNumber) {
  numberToRTCRegister(((byte)0x02), myNumber);
}

byte getHours(){
  return numberFromRTCRegister((byte)0x02);
}

You can do the same with year, month, etc.
As for which register to read to or write from, see page 11 of this document:

Thanks again, odometer, for your further info.

  1. As for the library I'm using. I went to the Arduino sketch tab Tools > Manage Libraries, and filtered for 3231.
    Five results were returned. Only one was simply called DS3231 (by Andrew Wickert, Eric Ayers, etc; and referencing Northern Widget.)
    This is the one I used. As I said above, it handled both get and set very neatly for year, month and date with a single statement for each. However I got lost with the hours function.

  2. I'd like to use the library referenced above, as it is easy to use and is the one I've used in the program for the other values. (I assume that minutes will also work smoothly, although I haven't tried this yet.)

  3. I appreciate the info you sent on p. 11 of the data sheet. I hadn't looked at that. If there is no "quick and easy" way to get/set the hours, I could muddle through and work directly with the registers. However it seems much much easier when someone has already done the work, just to use an existing function. Hopefully you can point me toward one of these - or show me how to use some function in the DS3231.h library to do it (in either 12 or 24 hour format).

  • Thanks in advance - Matt

mattbaum:
Thanks again, odometer, for your further info.

  1. As for the library I'm using. I went to the Arduino sketch tab Tools > Manage Libraries, and filtered for 3231.
    Five results were returned. Only one was simply called DS3231 (by Andrew Wickert, Eric Ayers, etc; and referencing Northern Widget.)
    This is the one I used.

Maybe it's this one? GitHub - NorthernWidget/DS3231: Communicates between Arduino-programmed AVR and Maxim DS3231 RTC: splice o

As I said above, it handled both get and set very neatly for year, month and date with a single statement for each. However I got lost with the hours function.

The way the hours function in that library works is more complicated. It tries to return three values at once; I'm not sure exactly how to work it.

  1. I'd like to use the library referenced above, as it is easy to use and is the one I've used in the program for the other values. (I assume that minutes will also work smoothly, although I haven't tried this yet.)

Beware of the sunk cost fallacy.

  1. I appreciate the info you sent on p. 11 of the data sheet. I hadn't looked at that. If there is no "quick and easy" way to get/set the hours, I could muddle through and work directly with the registers. However it seems much much easier when someone has already done the work, just to use an existing function. Hopefully you can point me toward one of these - or show me how to use some function in the DS3231.h library to do it (in either 12 or 24 hour format).
  • Thanks in advance - Matt

If my setHours() and getHours() functions work for you, then modify them for minutes, seconds, date, etc. I could have written setMinutes(), etc., myself, but I didn't, because this is your problem, not mine.

I think I'm finished here.

The way the hours function in that library works is more complicated.

I too have struggled with that library trying to solve your problem, and I have not been able to figure out the correct syntax for what you want to do.

My library of choice for the DS3231 is the Jack Christensen's library DS3232.h which works for the DS3231 as well. It integrates with the time library which is an added advantage. It is available through the library manager and additional information is here GitHub - JChristensen/DS3232RTC: Arduino Library for Maxim Integrated DS3232 and DS3231 Real-Time Clocks</

I recommend that you change the libraries.

outsider:
. Why is Big Ben still a 12 hr clock?

Big Ben is, and always has been, a bell.

Big Ben is, and always has been, a bell.

Completely off-topic. Sorry.

How is the tower called? Tower of Parliament? Does the clock have it's own name?

The tower has been the Elizabeth Tower since about 2012. Before that, it was just the Clock Tower

AFAIK, the clock has no name.

Let's call it "Big Clock" or "Clocky McClockface"

< SOLVED! > Re: Set/Get Hours with DS3231 rtc

I don’t really fully understand this solution, but the important thing for me is that it works!
The method I have used for reading and setting the clock values for year, month and date were, for example:
yr = Clock.getYear(), DEC;
Clock.setYear((byte) ( yr ));
Since these worked for year, month, and date, I couldn’t figure why I should have so much trouble with the hours. My solution seems a bit convoluted, but at least it works.

One illustrative example that compiled used the following:
Clock.getA1Time(ADay, AHour, AMinute, ASecond, ABits, ADy, A12h, Apm);
Clock.setA1Time(ADay, AHour, AMinute, ASecond, ABits, ADy, A12h, Apm);

This worked OK for AHours (Why the A, and the A! I don’t know - but it won’t work without them) but the hours would run only from 1 to 12.
I finally realized that the value “A12h” is a flag which must be set to “false” if the 24 hour clock is to be used.

This cleared up my problem, although I would like a little more understanding of what is actually going on in the DS3231 library, why the convoluted method I finally used works, and whether there is a simpler solution. BUT for now it works, and that is what counts!

mattbaum:
One illustrative example that compiled used the following:
Clock.getA1Time(ADay, AHour, AMinute, ASecond, ABits, ADy, A12h, Apm);
Clock.setA1Time(ADay, AHour, AMinute, ASecond, ABits, ADy, A12h, Apm);

This worked OK for AHours (Why the A, and the A! I don't know - but it won't work without them)

The beauty of Arduino / Open Source is that the source code is available to you right on your computer. Open up ‘DS3231.h’ in a text editor and all will be revealed to you.

You will see that the ‘getA1Time()’ and ‘setA1Time’ functions are accessing Alarm #1 within the DS3231 device (A == “Alarm”). There are similar functions for Alarm #2.

So, it appears you are fooling yourself. You are setting not the current time but the time for Alarm #1 to activate.

Thank you VERY much, gfalvo, for pointing out my folly!
I now realize what I have been doing WRONG, and I think I can set the time hours correctly using the following:
Hour = some value; and
void setHour(byte, Hour);
h12 = false and
void setClockMode(bool h12);

However, I don't know the correct syntax for RETRIEVING the current hours.

Help with this last item will be greatly appreciated!

  • Matt

Have you looked in 'DS3231.h'?

gfvalvo:
Have you looked in 'DS3231.h'?

Or, the example sketches that come with the library?

Yes!
What I found was:

byte getHour(bool& h12, bool& PM_time);
// In addition to returning the hour register, this function
// returns the values of the 12/24-hour flag and the AM/PM flag.

I don’t have much experience with the programming language, and tried to find examples (which were very helpful in other cases) but found nothing about how to use this.
So I’m still stuck!