Help changing time on RTC1307 with buttons

I have had trouble finding help with changing time on a RTC with a few buttons (Set, Hour, Min). I am making a large scale clock with Arduino Mega 2560. I have most everything set up except for the being able to change the time on the clock without having to reconnect it to the computer. I am also working on calling each minute, but have been trying to figure out the time change issue.

#include <Wire.h>
#include "RTClib.h"
#include <Charlieplex.h>

#define NUMBER_OF_PINS 10


byte pins[] = {2,3,4,5,6,7,8,9,10,11};
Charlieplex charlieplex = Charlieplex(pins,NUMBER_OF_PINS);
charliePin led1 = { 0 , 9 };  //HOUR 1 (led1 is indicated by current flow from 1 to 10)
charliePin led2 = { 1 , 9 };  //HOUR 2
charliePin led3 = { 2 , 9 };  //HOUR 3
charliePin led4 = { 3 , 9 };  //HOUR 4
charliePin led5 = { 4 , 9 };  //HOUR 5
charliePin led6 = { 5 , 9 };  //HOUR 6
charliePin led7 = { 6 , 9 };  //HOUR 7
charliePin led8 = { 7 , 9 };  //HOUR 8
charliePin led9 = { 8 , 9 };  //HOUR 9
charliePin led10 = { 9 , 8 }; //HOUR 10
charliePin led11 = { 0 , 8 }; //HOUR 11
charliePin led12 = { 1 , 8 }; //HOUR 12
//1mins
charliePin led13 = { 2 , 8 }; //MIN 1
charliePin led14 = { 3 , 8 }; //MIN 2
charliePin led15 = { 4 , 8 }; //MIN 3
charliePin led16 = { 5 , 8 }; //MIN 4
charliePin led17 = { 6 , 8 }; //MIN 5
charliePin led18 = { 7 , 8 }; //MIN 6
charliePin led19 = { 8 , 7 }; //MIN 7
charliePin led20 = { 9 , 7 }; //MIN 8
charliePin led21 = { 0 , 7 }; //MIN 9
//10mins
charliePin led22 = { 1 , 7 }; //MIN 10
charliePin led23 = { 2 , 7 }; //MIN 11
charliePin led24 = { 3 , 7 }; //MIN 12
charliePin led25 = { 4 , 7 }; //MIN 13
charliePin led26 = { 5 , 7 }; //MIN 14
charliePin led27 = { 6 , 7 }; //MIN 15
charliePin led28 = { 7 , 6 }; //MIN 16
charliePin led29 = { 8 , 6 }; //MIN 17
charliePin led30 = { 9 , 6 }; //MIN 18
charliePin led31 = { 0 , 6 }; //MIN 19
//20mins
charliePin led32 = { 1 , 6 }; //MIN 20
charliePin led33 = { 2 , 6 }; //MIN 21
charliePin led34 = { 3 , 6 }; //MIN 22
charliePin led35 = { 4 , 6 }; //MIN 23
charliePin led36 = { 5 , 6 }; //MIN 24
charliePin led37 = { 6 , 5 }; //MIN 25
charliePin led38 = { 7 , 5 }; //MIN 26
charliePin led39 = { 8 , 5 }; //MIN 27
charliePin led40 = { 9 , 5 }; //MIN 28
charliePin led41 = { 0 , 5 }; //MIN 29
//30mins
charliePin led42 = { 1 , 5 }; //MIN 30
charliePin led43 = { 2 , 5 }; //MIN 31
charliePin led44 = { 3 , 5 }; //MIN 32
charliePin led45 = { 4 , 5 }; //MIN 33
charliePin led46 = { 5 , 4 }; //MIN 34
charliePin led47 = { 6 , 4 }; //MIN 35
charliePin led48 = { 7 , 4 }; //MIN 36
charliePin led49 = { 8 , 4 }; //MIN 37
charliePin led50 = { 9 , 4 }; //MIN 38
charliePin led51 = { 0 , 4 }; //MIN 39
//40mins
charliePin led52 = { 1 , 4 }; //MIN 40
charliePin led53 = { 2 , 4 }; //MIN 41
charliePin led54 = { 3 , 4 }; //MIN 42
charliePin led55 = { 4 , 3 }; //MIN 43
charliePin led56 = { 5 , 3 }; //MIN 44
charliePin led57 = { 6 , 3 }; //MIN 45
charliePin led58 = { 7 , 3 }; //MIN 46
charliePin led59 = { 8 , 3 }; //MIN 47
charliePin led60 = { 9 , 3 }; //MIN 48
charliePin led61 = { 0 , 3 }; //MIN 49
//50mins
charliePin led62 = { 1 , 3 }; //MIN 50
charliePin led63 = { 2 , 3 }; //MIN 51
charliePin led64 = { 3 , 2 }; //MIN 52
charliePin led65 = { 4 , 2 }; //MIN 53
charliePin led66 = { 5 , 2 }; //MIN 54
charliePin led67 = { 6 , 2 }; //MIN 55
charliePin led68 = { 7 , 2 }; //MIN 56
charliePin led69 = { 8 , 2 }; //MIN 57
charliePin led70 = { 9 , 2 }; //MIN 58
charliePin led71 = { 0 , 2 }; //MIN 59
//00mins
charliePin led72 = { 1 , 2 }; //MIN 00

RTC_DS1307 RTC;

boolean singleOn = true;

void setup () {
    Serial.begin(57600);
    Wire.begin();
    RTC.begin();
    // following line sets the RTC to the date & time this sketch was compiled
    //RTC.adjust(DateTime(__DATE__, __TIME__));
    if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
  }
 
}
 
void loop () {
    DateTime now = RTC.now();
    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(' ');
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();


  
  if (singleOn){ charlieplex.clear(); }


     if (now.minute() == 0) {
       charlieplex.charlieWrite(led1,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led2,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led3,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led4,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led5,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led6,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led7,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led8,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led9,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led10,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led11,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led12,HIGH);
       delay(50);charlieplex.clear(); 
       charlieplex.charlieWrite(led1,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led2,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led3,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led4,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led5,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led6,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led7,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led8,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led9,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led10,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led11,HIGH);
       delay(50);charlieplex.clear();
       charlieplex.charlieWrite(led12,HIGH);
       delay(50);charlieplex.clear();
       }
       
     if (now.hour() == 1) {
       charlieplex.charlieWrite(led1,HIGH);
       Serial.println("led1");
     }
     if (now.hour() == 2) {
       charlieplex.charlieWrite(led2,HIGH);
       Serial.println("led2");
     }
     if (now.hour() == 3) {
       charlieplex.charlieWrite(led3,HIGH);
       Serial.println("led3");
     }
     if (now.hour() == 4) {
       charlieplex.charlieWrite(led4,HIGH);
       Serial.println("led4");
     }
     if (now.hour() == 5) {
       charlieplex.charlieWrite(led5,HIGH);
       Serial.println("led5");
     }
     if (now.hour() == 6) {
       charlieplex.charlieWrite(led6,HIGH);
       Serial.println("led6");
     }
     if (now.hour() == 7) {
       charlieplex.charlieWrite(led7,HIGH);
       Serial.println("led7");
     }
     if (now.hour() == 8) {
       charlieplex.charlieWrite(led8,HIGH);
       Serial.println("led8");
     }
     if (now.hour() == 9) {
       charlieplex.charlieWrite(led9,HIGH);
       Serial.println("led9");
     }
     if (now.hour() == 10) {
       charlieplex.charlieWrite(led10,HIGH);
       Serial.println("led10");
     }
     if (now.hour() == 11) {
       charlieplex.charlieWrite(led11,HIGH);
       Serial.println("led11");
     }
     if (now.hour() == 12) {
       charlieplex.charlieWrite(led12,HIGH);
       Serial.println("led12");
     }
//24 Hour Clock                               
     if (now.hour() == 13) {
       charlieplex.charlieWrite(led1,HIGH);
       Serial.println("led1");
     }
     if (now.hour() == 14) {
       charlieplex.charlieWrite(led2,HIGH);
       Serial.println("led2");
     }
     if (now.hour() == 15) {
       charlieplex.charlieWrite(led3,HIGH);
       Serial.println("led3");
     }
     if (now.hour() == 16) {
       charlieplex.charlieWrite(led4,HIGH);
       Serial.println("led4");
     }
     if (now.hour() == 17) {
       charlieplex.charlieWrite(led5,HIGH);
       Serial.println("led5");
     }
     if (now.hour() == 18) {
       charlieplex.charlieWrite(led6,HIGH);
       Serial.println("led6");
     }
     if (now.hour() == 19) {
       charlieplex.charlieWrite(led7,HIGH);
       Serial.println("led7");
     }
     if (now.hour() == 20) {
       charlieplex.charlieWrite(led8,HIGH);
       Serial.println("led8");
     }
     if (now.hour() == 21) {
       charlieplex.charlieWrite(led9,HIGH);
       Serial.println("led9");
     }
     if (now.hour() == 22) {
       charlieplex.charlieWrite(led10,HIGH);
       Serial.println("led10");
     }
     if (now.hour() == 23) {
       charlieplex.charlieWrite(led11,HIGH);
       Serial.println("led11");
     }
     if (now.hour() == 0) {
       charlieplex.charlieWrite(led12,HIGH);
       Serial.println("led12");
     }   


  delay(1000);
  singleOn=!singleOn;

}

you can do it with one button... and a few states

Check for a long button press - start a timer when the button is pressed for more than say 7 seconds

then press press press to change the hour... 7 seconds of inactivity will change to allow you to set the minutes... press press press... another 7 seconds without a change... returns to ignoring the set cycle

something like this, which you need to put into your program.

just put a pushbutton on pin3 and ground...

try it on its own first, notice led13 change its rate as you set the hours and minutes...

int pushButton = 3;
unsigned long setTime = 7000UL;
unsigned long timerStart;
int state = 0;
int buttonState, lastButtonState;
unsigned long lastFlash;

void setup()
{
  Serial.begin(115200);
  pinMode(pushButton, INPUT_PULLUP);
  pinMode(13, OUTPUT);
}

void loop()
{
  if (state == 0)
  {
    flash(1000);
    buttonState = digitalRead(pushButton);
    if (buttonState == LOW) //button pressed
    {
      if (lastButtonState == HIGH) // button state changed
      {
        timerStart = millis();
      }
      else if (millis() - timerStart >= setTime)//held for setTime
      {
        state = 1;
        timerStart = millis();
        Serial.print(F("Setting Hour"));
      }
    }
    lastButtonState = buttonState;
  }
  else if (state == 1)// set the hour
  {
    flash(50);
    buttonState = digitalRead(pushButton);
    if (buttonState == LOW && lastButtonState == HIGH)
    {
      timerStart = millis();
      //add one hour to RTC here
      Serial.print(F("One Hour Added!!!"));
    }
    lastButtonState = buttonState;
    if (millis() - timerStart >= setTime)
    {
      state = 2;// timed out
      timerStart = millis();
      Serial.print(F("Setting Minute"));
    }
  }
  else if (state == 2)// set the minute
  {
    flash(250);
    buttonState = digitalRead(pushButton);
    if (buttonState == LOW && lastButtonState == HIGH)//only on button change
    {
      timerStart = millis();
      //add one minute to RTC here
      Serial.print(F("One Minute Added!!!"));
    }
    lastButtonState = buttonState;
    if (millis() - timerStart >= setTime)
    {
      state = 0;// timed out
      timerStart = millis();
      Serial.print(F("Completed setting Time"));
    }
  }
  //
  //Your Clock loop() function goes here
  //
}

void flash(unsigned long rate)
{
  if (millis() - lastFlash > rate)
  {
    digitalWrite(13, !digitalRead(13));
    lastFlash = millis();
  }   
}

This will give you a starting off point to handel your switch timing
See reply #1
http://www.gammon.com.au/Arduino/SwitchManager.zip
From

I was able to finally find a little bit simpler code (at least for me).

  buttonState30 = digitalRead(buttonPin30);
  Serial.println(digitalRead(buttonPin30));
  if (buttonState30 == HIGH) {     
    Serial.println("Switched To Set Clock");
    buttonState32 = digitalRead(buttonPin32);
    buttonState34 = digitalRead(buttonPin34);
    if (buttonState32 == HIGH) {
      DateTime now = RTC.now();
      DateTime then(now.unixtime() + 60); // one hour later
      Serial.println("Button pressed to ADD a minute");
      RTC.adjust(then);
    }  
    if (buttonState34 == HIGH) {
      DateTime now = RTC.now();
      DateTime then(now.unixtime() - 60); // one hour later
      Serial.print("Button pressed to SUBTRACT a minute");
      RTC.adjust(then);
    }      
  }

Also can be used within the program to offset the time if the RTC is not 100% accurate. noticed mine is about 55 seconds fast over 24 hour period. So this if statement subtracts 2 seconds every hour at ##:30:30 and then delays for 3 seconds to avoid a possible loop.

  if (now.minute() == 30) {
    if (now.second() == 30) {
      DateTime now = RTC.now();
      DateTime then(now.unixtime() - 2); // subtracts 2 seconds
      Serial.println("subtracted 2 seconds for time ");
      RTC.adjust(then);  
      delay(3000); //delayed for 3 seconds to prevent the subtraction from looping.
    }
  }
      delay(3000); //delayed for 3 seconds to prevent the subtraction from looping.

How long would you really have to wait for now.second() to not be 30?

Just yesterday i had need to write a user-entered value to a motor as its PWM.

I used the "up" and "down" arrows on the DFR LCD shield to set the value on the screen. But just for the hell of it I didn't want to analogWrite that changing value to the motor on the fly, so I used the "select" key as a sort of "enter" to save the screen value (say, tempVal) when the user was happy to a final value (say finalVal) and analogWrote that to the motor.

That LCD shield has example code that uses switch case to activate a {...} of code depending on which button is pressed.

Same approach could be used to set the time on the LCD a little bit ahead with "up" and "down", then hit "select" at the correct time on a known-good clock to shoot the time into the RTC.

An RTC based on the 1307 should not be 55 seconds off over the course of a day. I've only noticed a few seconds over several months with my RTC module. I'd investigate this first, as something is basically wrong. Doing an hour-by-hour adjustment just shouldn't be necessary.

econjack:
An RTC based on the 1307 should not be 55 seconds off over the course of a day.

Have you got the correct crystal?- you might have the correct frequency but wrong internal capacitance.

JimboZA Good point, there are many different 32 KHZ "Crystals" They are all Piezo tuning forks.. Not resonators or crystals in the normal "sense" of the word. Simply slightly different structures differing only in dimension a different combinations of Piezoelectric materials or both.

It is these small difference that require different loading determined by the RTC internal capacitance of the oscillator... clearly the OP is using the wrong device.
The best method would be to [Gasp] read the data sheet and buy the one recommended for his RTC chip..
There are no one fits all device although the frequency marking are the same.
Doc

I accidentally bought the wrong one for my 1302: got a 6pf instead of 12pF (or vice versa, I forget off hand which is the right one) and it gained time. May well be the same issue here.

Of course, those things are so tiny there are no markings so you have to take the vendor's word for what it is.

Might also be a counterfeit 1307?