Set time with one button on DS1307

Hello everyone!

I have build LED clock. 3x60 leds in charlieplexing matrix (60 for seconds, 60 for minutes and 60 for hours). Clock leds are placed in 3 rings and it is working like analog clock hands.
It is display time nicely but i have problem with setting up time. When i write it manually in code it set up time ok but if i want to set up time without changing anyting in code there seems to be some problems (I have try to do it like in comment in code below but it dosent work).
I want to set time like this: When i push button minutes starts going faster and then hours, when i relese button it write time to ds1307 memory. Anyone know how to do it?

void loop() {

  

buttonState = digitalRead(buttonPin); // check if the pushbutton is pressed.
  if (buttonState == HIGH) {     // if it is, the buttonState is HIGH:
  setTime(); 
  
}
  else {  // display time
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(zero);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_ADDRESS, 7);
  int second = bcdToDec(Wire.read());
  int minute = bcdToDec(Wire.read());
  int hour = bcdToDec(Wire.read());
  int weekDay = bcdToDec(Wire.read());
  int monthDay = bcdToDec(Wire.read());
  int month = bcdToDec(Wire.read());
  int year = bcdToDec(Wire.read());
  turnOnsek(second); //turn on one of the 60 leds (second hand)
  turnOnmin(minute); //turn on one of the 60 leds (minute hand)
  if (minute<12) {turnOngodz(hour);} //turn on one of the 60 leds (hour hand)
  else if (minute>11 && minute<24) {turnOngodz(hour+1);}
  else if (minute>23 && minute<36) {turnOngodz(hour+2);}
  else if (minute>35 && minute<48) {turnOngodz(hour+3);}
  else if (minute>47) {turnOngodz(hour+4);}
  }
}

void setTime() {
  byte second = 0; //0-59 sets seconds to zero
  byte minute = bcdToDec(Wire.read()); //0-59 dosent change minute
  byte hour = bcdToDec(Wire.read()); //0-11 dosent change hours 
  byte weekDay = 2; //1-7 i dont use those
  byte monthDay = 24; //1-31
  byte month = 2; //1-12
  byte year  = 14; //0-99
/*
  while (buttonState != LOW) {
  minute=minute+1;
  if (minute > 59) minute = 0;
  turnOnmin(minute);
  delay(750);
*/
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(zero); //stop Oscillator

  Wire.write(decToBcd(second));
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));
  Wire.write(decToBcd(weekDay));
  Wire.write(decToBcd(monthDay));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year)); 

  Wire.write(zero); //start

  Wire.endTransmission();
}

or maybe it can be done with two buttons if one will not work?

Sorry for my poor english. :blush:

The clock in my car gets the time set using one button, so it is possible. It's very hard to set, though.

You need to draw a flowchart of the sequence of button-pushing that you want to implement, and then write the code to implement it.

consider using the duration of the button press to change the state of the clock into set mode

pseudo code:

if (LongButtonPress) setupMode();

then use single button presses to cycle through the settings you want to update.

Set a timer that expires and returns to 'active mode' if no button was pressed for a longish period of time.

look at @Robin2's example of doing multiple things at the same time...

For doing an action depending on the duration of a button press Nick Gammons SwitchManager library works well. It is the last article on that page.

Thanks for anwsers but there is problem with writing to ds1307 memory also.

When I press the button it starts setTime() but clock freezes and nothing is happen.

I read minute state like this:

byte minute = bcdToDec(Wire.read());

add one to it

minute=minute+1;
if (minute > 59) minute = 0;

and try to write to ds1307 memory

Wire.write(decToBcd(minute));

What am I doing wrong?

Could you please post your full sketch. Wire.write(zero); zero is?

Wire.beginTransmission(clockAddress);
Wire.write(byte(0x00));
Wire.write(decToBcd(minute));
Wire.endTransmission();

This is full sketch without ledmatrix def … (The message exceeds the maximum allowed length (9500 characters).)

#include <Time.h>
#include <DS1307RTC.h>
#include <Wire.h>

#define DS1307_ADDRESS 0x68

#define Asek 13
#define Bsek 12
#define Csek 11
#define Dsek 10
#define Esek 9
#define Fsek 8
#define Gsek 7
#define Hsek 6
#define Isek 5

#define Amin 37
#define Bmin 39
#define Cmin 41
#define Dmin 43
#define Emin 45
#define Fmin 47
#define Gmin 49
#define Hmin 51
#define Imin 53

#define Agodz 36
#define Bgodz 38
#define Cgodz 40
#define Dgodz 42
#define Egodz 44
#define Fgodz 46
#define Ggodz 48
#define Hgodz 50
#define Igodz 52
 
#define PIN_CONFIG 0
#define PIN_STATE 1
 
#define LED_COUNT 60
byte zero = 0x00;
const int buttonPin = 22;
int buttonState = 0;
int minuta=0;
int godzina=0;
int matrix[LED_COUNT][2][9] = {
(.......i have to cut it becouse error message "The message exceeds the maximum allowed length (9500 characters)."....)
 
void turnOnsek( int led ) {
  pinMode( Asek, matrix[led][PIN_CONFIG][0] );
  pinMode( Bsek, matrix[led][PIN_CONFIG][1] );
  pinMode( Csek, matrix[led][PIN_CONFIG][2] );
  pinMode( Dsek, matrix[led][PIN_CONFIG][3] );
  pinMode( Esek, matrix[led][PIN_CONFIG][4] );
  pinMode( Fsek, matrix[led][PIN_CONFIG][5] );
  pinMode( Gsek, matrix[led][PIN_CONFIG][6] );
  pinMode( Hsek, matrix[led][PIN_CONFIG][7] );
  pinMode( Isek, matrix[led][PIN_CONFIG][8] );
  digitalWrite( Asek, matrix[led][PIN_STATE][0] );
  digitalWrite( Bsek, matrix[led][PIN_STATE][1] );
  digitalWrite( Csek, matrix[led][PIN_STATE][2] );
  digitalWrite( Dsek, matrix[led][PIN_STATE][3] );
  digitalWrite( Esek, matrix[led][PIN_STATE][4] );
  digitalWrite( Fsek, matrix[led][PIN_STATE][5] );
  digitalWrite( Gsek, matrix[led][PIN_STATE][6] );
  digitalWrite( Hsek, matrix[led][PIN_STATE][7] );
  digitalWrite( Isek, matrix[led][PIN_STATE][8] );
}

void turnOnmin (int ledm) {
  pinMode( Amin, matrix[ledm][PIN_CONFIG][0] );
  pinMode( Bmin, matrix[ledm][PIN_CONFIG][1] );
  pinMode( Cmin, matrix[ledm][PIN_CONFIG][2] );
  pinMode( Dmin, matrix[ledm][PIN_CONFIG][3] );
  pinMode( Emin, matrix[ledm][PIN_CONFIG][4] );
  pinMode( Fmin, matrix[ledm][PIN_CONFIG][5] );
  pinMode( Gmin, matrix[ledm][PIN_CONFIG][6] );
  pinMode( Hmin, matrix[ledm][PIN_CONFIG][7] );
  pinMode( Imin, matrix[ledm][PIN_CONFIG][8] );
  digitalWrite( Amin, matrix[ledm][PIN_STATE][0] );
  digitalWrite( Bmin, matrix[ledm][PIN_STATE][1] );
  digitalWrite( Cmin, matrix[ledm][PIN_STATE][2] );
  digitalWrite( Dmin, matrix[ledm][PIN_STATE][3] );
  digitalWrite( Emin, matrix[ledm][PIN_STATE][4] );
  digitalWrite( Fmin, matrix[ledm][PIN_STATE][5] );
  digitalWrite( Gmin, matrix[ledm][PIN_STATE][6] );
  digitalWrite( Hmin, matrix[ledm][PIN_STATE][7] );
  digitalWrite( Imin, matrix[ledm][PIN_STATE][8] );
}

void turnOngodz (int ledg) {
  pinMode( Agodz, matrix[ledg][PIN_CONFIG][0] );
  pinMode( Bgodz, matrix[ledg][PIN_CONFIG][1] );
  pinMode( Cgodz, matrix[ledg][PIN_CONFIG][2] );
  pinMode( Dgodz, matrix[ledg][PIN_CONFIG][3] );
  pinMode( Egodz, matrix[ledg][PIN_CONFIG][4] );
  pinMode( Fgodz, matrix[ledg][PIN_CONFIG][5] );
  pinMode( Ggodz, matrix[ledg][PIN_CONFIG][6] );
  pinMode( Hgodz, matrix[ledg][PIN_CONFIG][7] );
  pinMode( Igodz, matrix[ledg][PIN_CONFIG][8] );
  digitalWrite( Agodz, matrix[ledg][PIN_STATE][0] );
  digitalWrite( Bgodz, matrix[ledg][PIN_STATE][1] );
  digitalWrite( Cgodz, matrix[ledg][PIN_STATE][2] );
  digitalWrite( Dgodz, matrix[ledg][PIN_STATE][3] );
  digitalWrite( Egodz, matrix[ledg][PIN_STATE][4] );
  digitalWrite( Fgodz, matrix[ledg][PIN_STATE][5] );
  digitalWrite( Ggodz, matrix[ledg][PIN_STATE][6] );
  digitalWrite( Hgodz, matrix[ledg][PIN_STATE][7] );
  digitalWrite( Igodz, matrix[ledg][PIN_STATE][8] );
}
 
void setup() {
  pinMode(buttonPin, INPUT);
  Wire.begin();
  Serial.begin(9600);
  while (!Serial) ; // wait for serial
  delay(200);
}

byte bcdToDec(byte val)  {
// Convert binary coded decimal to normal decimal numbers
  return ( (val/16*10) + (val%16) );
}
byte decToBcd(byte val){
// Convert normal decimal numbers to binary coded decimal
  return ( (val/10*16) + (val%10) );
}
 
void loop() {

  

buttonState = digitalRead(buttonPin); // check if the pushbutton is pressed.
  if (buttonState == HIGH) {     // if it is, the buttonState is HIGH:
  setTime(); 
  
}
  else {  // display time
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(zero);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_ADDRESS, 7);
  int second = bcdToDec(Wire.read());
  int minute = bcdToDec(Wire.read());
  int hour = bcdToDec(Wire.read());
  int weekDay = bcdToDec(Wire.read());
  int monthDay = bcdToDec(Wire.read());
  int month = bcdToDec(Wire.read());
  int year = bcdToDec(Wire.read());
  turnOnsek(second); //turn on one of the 60 leds (second hand)
  turnOnmin(minute); //turn on one of the 60 leds (minute hand)
  if (minute<12) {turnOngodz(hour);} //turn on one of the 60 leds (hour hand)
  else if (minute>11 && minute<24) {turnOngodz(hour+1);}
  else if (minute>23 && minute<36) {turnOngodz(hour+2);}
  else if (minute>35 && minute<48) {turnOngodz(hour+3);}
  else if (minute>47) {turnOngodz(hour+4);}
  }
}

void setTime() {
  byte second = 0; //0-59 sets seconds to zero
  byte minute = bcdToDec(Wire.read()); //0-59 dosent change minute
  byte hour = bcdToDec(Wire.read()); //0-11 dosent change hours 
  byte weekDay = 2; //1-7 i dont use those
  byte monthDay = 24; //1-31
  byte month = 2; //1-12
  byte year  = 14; //0-99
/* i have tried like this 
  while (buttonState != LOW) {
  minute=minute+1;
  if (minute > 59) minute = 0;
  turnOnmin(minute);
  delay(750);
*/

/* and like this
buttonState = digitalRead(buttonPin); // check if the pushbutton is pressed.
  if (buttonState == HIGH) {     // if it is, the buttonState is HIGH:
    // ustawianie zegara
    Wire.write(decToBcd(minute+1));
    turnOnsek(second);
    turnOnmin(minute);
    if (minute<12) {turnOngodz(hour);}
    else if (minute>11 && minute<24) {turnOngodz(hour+1);}
    else if (minute>23 && minute<36) {turnOngodz(hour+2);}
    else if (minute>35 && minute<48) {turnOngodz(hour+3);}
    else if (minute>47) {turnOngodz(hour+4);}
    wait(500);
  } 
  else {
  turnOnsek(second);
  turnOnmin(minute);

  if (minute<12) {turnOngodz(hour);}
  else if (minute>11 && minute<24) {turnOngodz(hour+1);}
  else if (minute>23 && minute<36) {turnOngodz(hour+2);}
  else if (minute>35 && minute<48) {turnOngodz(hour+3);}
  else if (minute>47) {turnOngodz(hour+4);}
  }

*/
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(zero); //stop Oscillator

  Wire.write(decToBcd(second));
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));
  Wire.write(decToBcd(weekDay));
  Wire.write(decToBcd(monthDay));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year)); 

  Wire.write(zero); //start

  Wire.endTransmission();
}

Nobody know why it isn't write to DS1307?

To see if it is your module or if it is your code you can try this sketch, set the time through serial monitor as directions state, then send the command Q2 it will dump the DS1307 memory in the monitor.

It might help if you post all of your code, and if it's too big then add it as an attachment. It's unlikely but the problem could be in the part you have omitted.

elac: To see if it is your module or if it is your code you can try this sketch, set the time through serial monitor as directions state, then send the command Q2 it will dump the DS1307 memory in the monitor.

Module is ok because when I write time manually in code like this:

byte minute = 0;

it works ok and set up minute to 0. But when I try with button like this:

byte minute = bcdToDec(Wire.read());
(...)
minute=minute+1;
(...)
Wire.write(decToBcd(minute));

or like this:

Wire.write(decToBcd(minute+1));

...it dosent work and clock freezes.

dannable: It might help if you post all of your code, and if it's too big then add it as an attachment. It's unlikely but the problem could be in the part you have omitted.

You can't write to the RTC only writing:

Wire.write(decToBcd(minute));

The clock is I2C, so you need to send the address of the device, the address where you want to write, etc.

I use that same RTC and I'm using the RTClib library from Adafriut: https://github.com/adafruit/RTClib

With this library you have one function to adjust the RTC:

RTC.adjust(DateTime(yr, mth, dy, hr, mnt, sc));

You can also open the .cpp file from this library and see how they are preforming that adjust.

Full code in attachment.

protonik_clock1_2.ino (15.3 KB)

You have the DS1307RTC.h library declared in your code but you are not using it, as you have:

  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(zero);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_ADDRESS, 7);
  int second = bcdToDec(Wire.read());
  int minute = bcdToDec(Wire.read());
  int hour = bcdToDec(Wire.read());
  int weekDay = bcdToDec(Wire.read());
  int monthDay = bcdToDec(Wire.read());
  int month = bcdToDec(Wire.read());
  int year = bcdToDec(Wire.read());

this code, for example.

Take a look at the following link: https://www.pjrc.com/teensy/td_libs_DS1307RTC.html

when they use this library to read that RTC. They read the value of date and time with only one line:

RTC.read(tm))

I don’t know if it works, because I don’t have your setup, but your code using the Time.h and DS1307RTC.h libraries (downloaded from the link that I paste earlier) will be what’s in the file attached.

protonik_clock1_2.ino (13.1 KB)

On clocks... Google this guy:

Jack Christensen Arduino Clock

I know this photo. This guy use to write here in the forum, but I didn't know that he writes libraries.

luisilva: I don't know if it works, because I don't have your setup, but your code using the Time.h and DS1307RTC.h libraries (downloaded from the link that I paste earlier) will be what's in the file attached.

Thanks. It is working and it is simplier but how to add one minute with button push? When I want just reset time to zero minute and zero second Im doing it like this and its working

if (buttonState == HIGH) {     // if it is, the buttonState is HIGH:
    RTC.read(tm);
    tm.Second = 0;
    tm.Minute = 0;
    RTC.write(tm);
  }

but when i try to add one minute with button like this

 tm.Minute = tm.Minute + 1;

it dosent work.

I don’t know why your code is not working, because the following little test adjusts the time for me.

#include <Time.h>  
#include <Wire.h>  
#include <DS1307RTC.h>  // a basic DS1307 library that returns time as a time_t

void setup() {

  tmElements_t tm;

  Serial.begin (9600);

  RTC.read(tm);

  Serial.println(tm.Second);
  Serial.println(tm.Minute);
  Serial.println(tm.Hour);

  tm.Minute= tm.Minute +1;

  RTC.write(tm);

  RTC.read(tm);

  Serial.println(tm.Second);
  Serial.println(tm.Minute);
  Serial.println(tm.Hour);

}

void loop (){
}

There must be something wrong with the button wiring or the code related to the button. You might want to consider flagging a state change with the button press and adjusting the time based on the flag (and then resetting it), rather than relying on the button being actively pressed.