Need help adjusting time on Seven Segment Display clock

Hello, I have built a seven segment display clock that have the capability to have its minute and hour number increase via button press. However, I am having an issue where if I let go of the minute/ hour button, the minute/hour number will immediately revert back to their original state. Can someone help me figure out how to permanently adjust the time? Thank you. I can not post the code as a file so I will have the entire thing paste down here.

//this version is working, don't change it. Make a copy instead.
#include <Adafruit_BusIO_Register.h>
#include <Adafruit_GenericDevice.h>
#include <Adafruit_I2CDevice.h>
#include <Adafruit_I2CRegister.h>
#include <Adafruit_SPIDevice.h>
//renember to include the entire Adafruit BusIO library, the original <Adafruit_I2CRegister.h> library is missing for some reason
#include <RTClib.h>
RTC_DS3231 rtc;
//set up for the Shift registers and numbers
//check the datasheet for the SN74HC595 to see the individual pins
#define Hourbutton 8//button used to adjust the hour
#define Minutebutton 9//button used to adjust the minutes
#define DS_pin 4//blue
#define STCP_pin 5//yellow
#define SHCP_pin 6//green
//color coded so you don't blows it up
int numbers[10] {126, 48, 109, 121, 51, 91, 95, 112, 127, 123}; //use [int digits [10] { 1, 79, 18, 12, 76, 36, 32, 15, 0, 4};] instead if
//your display is the common Annode type.
int digits[4]; //int d1; int d2; int d3; int d4;// has to define all of these, they represents the individual digits and the time number
int hbstate;
int mbstate;
int minute;
int hour;

void setup() {
pinMode(Hourbutton, INPUT);
pinMode(Minutebutton, INPUT);
pinMode(DS_pin, OUTPUT);
pinMode(STCP_pin, OUTPUT);
pinMode(SHCP_pin, OUTPUT);
hbstate = 0;
mbstate = 0;
// initializing the rtc
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    while (1) delay(10);
  }
  // When time needs to be set on a new device, or after a power loss, 
  //the following line sets the RTC to the date & time this sketch was compiled
   if (rtc.lostPower()) {
  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));// This line sets the RTC with the time from the pc when compiled
    //rtc.adjust(DateTime(2026, 4, 21, 11, 55, 30));//uncomment this line once to manually set the time
  }
//The entire if section above enable the RTC to read correct time, do not delete. thanks Nuetral, I owe you one.
  rtc.disable32K();
}

void loop() {
    //minute = now.minute();
    //hour = now.hour();
    hbstate = digitalRead(Hourbutton);
    mbstate = digitalRead(Minutebutton);
    DateTime now = rtc.now();
    //Formula to display Hours
        digits[1]= ((hour/10)%10);//formula for the first digit
        digits[2]= (hour%10);//formula for the second digit
    //Formua to display Minutes
        digits[3]= ((minute/10)%10);//formula for the third digit
        digits[4]= (minute%10);//formula for the fourth digit
    if (hbstate == HIGH){
      if (hour == 25){
        hour = 1;
      }
      else{
        hour = now.hour() + 1;
      }
      }
      else{
        hour = now.hour();
      }
    if (mbstate == HIGH){
      if (minute == 61){
        minute = 1;
      }
      else{
        minute = now.minute() + 1;
      }
    }
      else{
        minute = now.minute();
      }
    digitalWrite(STCP_pin, LOW);
        //The lines of code below is the shiftout command
        //use least LSBFIRST instead of MSBFIRST
        shiftOut(DS_pin, SHCP_pin, LSBFIRST, numbers[digits[4]]); // shift in the digit, last digit.
        shiftOut(DS_pin, SHCP_pin, LSBFIRST, numbers[digits[3]]); // shift in the digit, third digit.
        shiftOut(DS_pin, SHCP_pin, LSBFIRST, numbers[digits[2]]); // shift in the digit, second digit.
        shiftOut(DS_pin, SHCP_pin, LSBFIRST, numbers[digits[1]]); // shift in the digit, first digit.
        //The sequenece is important
    digitalWrite(STCP_pin, HIGH); // flash the digit in the correct place
        delay (100);
   
}

At no point do you actually update the hours or minutes on RTC module, you just read from it. So once you let go of either button, it will read the current value instead of the new one that you wanted it to be changed to.

Instead of always reading the current hour or minute. Have them read into new hour and minute variables first, inside your setup function and just manipulate the hour and minute afterwards in the loop. Think of these variables as offsets.

Btw, you might want to clean up the code a bit. It’s a little hard to read, even though it’s not very long.

So do I need to create a new int for new hour and new minute, and by update do you mean using the rtc.adjut()? For the "read into new hour and minute variable first", are you suggesting that I move this entire section section

digits[1]= ((hour/10)%10);//formula for the first digit
        digits[2]= (hour%10);//formula for the second digit
    //Formua to display Minutes
        digits[3]= ((minute/10)%10);//formula for the third digit
        digits[4]= (minute%10);//formula for the fourth digit

into void setup? I do need to clean the code afterward, thanks for pointing out.

I would make H checks > 24 and M checks > 59.
I also would make good use of the ternary operator (there is even a compound situation in your code. This is the classroom textbook example of one use of ternary.
Conceptually,

 hour = (hour > 24) ? 1 : (now.hour() + 1);

Even that code can be simplified but I will leave that to you.

Start the loop() like this... so you have minute and hour

void loop() {
  DateTime now = rtc.now();
  minute = now.minute();
  hour = now.hour();
  .
  .
}

[edit]

Here is a minimal sketch for your digit isolation sketch...

#include <RTClib.h>
RTC_DS3231 rtc;
uint8_t digits[4]; // four element array

void setup() {
  Serial.begin(115200);
  rtc.begin();
  // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // set sketch "compile" time
  // rtc.adjust(DateTime(2021, 1, 21, 3, 45, 0)); // set manual time  January 21, 2021 at 3:45.0 am
}

void loop () {
  DateTime now = rtc.now();
  uint8_t hour = now.hour();
  uint8_t minute = now.minute();

  digits[1] = ((hour / 10) % 10); //formula for the first digit
  digits[2] = (hour % 10); //formula for the second digit
  digits[3] = ((minute / 10) % 10); //formula for the third digit
  digits[4] = (minute % 10); //formula for the fourth digit

  for (int i = 1; i < 5; i++) {
    Serial.print(digits[i]);
    Serial.print(" ");
  }
  Serial.println();
  delay(1000); // replace delay() with millis() timer
}

I assume your button-pushing is to adjust the (H)our and (M)inute...

  • monitor each button for "WAS PRESSED" (read about button debounce)
  • add "1" to the element (hour or minute)
  • check for rollover (9 >> 0, 12 >> 1 and 59 >> 0)
  • call rtc.adjust(); with the new time.

Yes but the thing is once I increment hour or minute or hour, the number will imidiately revert back.

The numbers will be exactly the result of rtc.now();... so you need to rtc.adjust(); after you change the hour/minute.

I have been thinking. What is "i" in this scenario for?

Be more descriptive, like "copy quote" to show your reference...

Do you mean here?

  for (int i = 1; i < 5; i++) {
    Serial.print(digits[i]);
    Serial.print(" ");
  }

If so, "i" is just a counter from 1 to 4, to count through the elements of your digits[] array.

Yes, that is exactly what I meant. Sorry for not being more descriptive with what I wanted. So the purpose of this is just to let you know how many digits there are?

 for (int i = 1; i < 5; i++) {
    Serial.print(digits[i]);
    Serial.print(" ");
  }

The first line counts from 1 to 4 (not 5... see the "less than" "<" sign)

The second line prints an element from your digits[] array... so when "i" increases, so does the element number to be printed from digits[element]

The third line is just to put a separator between the elements (a "space").

It's the "index" of the for() loop, a subject that's worth your time to research.

Very late reply, but how do you actually use rtc.adjust()? Especially in the scenario you mentioned.

Post #5 shows these two lines...

  // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // set sketch "compile" time
  // rtc.adjust(DateTime(2021, 1, 21, 3, 45, 0)); // set manual time  January 21, 2021 at 3:45.0 am
}

Un-comment one of these lines and upload the sketch.

Then, re-comment the line and upload again.

This is to say: run rtc.adjust() one time, then remove it. The RTC battery will allow the RTC to keep time until the battery dies.

No what I meant is in your first post. In the first post, at the part where you instructed me how to adjust the time, you mentioned calling rtc.adjust(); to have the time adjusted permanetly. How does that works? rtc.adjust(); I always ask me to put a value inside it, I can't just drop it at the end by itself.

This is the best I can come up with based on your instruction

//this version is working, don't change it. Make a copy instead.
#include <Adafruit_BusIO_Register.h>
#include <Adafruit_GenericDevice.h>
#include <Adafruit_I2CDevice.h>
#include <Adafruit_I2CRegister.h>
#include <Adafruit_SPIDevice.h>
//renember to include the entire Adafruit BusIO library, the original <Adafruit_I2CRegister.h> library is missing for some reason
#include <RTClib.h>
RTC_DS3231 rtc;
//set up for the Shift registers and numbers
//check the datasheet for the SN74HC595 to see the idividual pins
#define Hourbutton 8//button used to adjust the hour
#define Minutebutton 9//button used to adjust the minutes
#define DS_pin 4//blue
#define STCP_pin 5//yellow
#define SHCP_pin 6//green
//color coded so you don't blows it up
int numbers[10] {126, 48, 109, 121, 51, 91, 95, 112, 127, 123}; //use [int digits [10] { 1, 79, 18, 12, 76, 36, 32, 15, 0, 4};] instead if
//your display is the common Annode type.
uint8_t digits[4]; //int d1; int d2; int d3; int d4;// has to define all of these, they reperesent the individual digits and the time number
int hbstate;
int mbstate;
int lasthbstate = LOW;
int lastmbstate = LOW;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;
void setup() {
pinMode(Hourbutton, INPUT);
pinMode(Minutebutton, INPUT);
pinMode(DS_pin, OUTPUT);
pinMode(STCP_pin, OUTPUT);
pinMode(SHCP_pin, OUTPUT);
// initializing the rtc
  rtc.begin();
  if (rtc.lostPower()){
  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
  //rtc.adjust(DateTime(2026,6,6,22,40,30);// This line sets the RTC with the time from the pc when compile
}
void loop() {
  //DateTime hour = now.hour();
  //DateTime hour = now.minute();
  DateTime now = rtc.now();
  uint8_t hour = now.hour();
  uint8_t minute = now.minute();
  int hreading = digitalRead(Hourbutton);
  int mreading = digitalRead(Minutebutton);
    //Formula to display Hours
        digits[1]= ((hour/10)%10);//formula for the first digit
        digits[2]= (hour%10);//formula for the second digit
    //Formua to display Minutes
        digits[3]= ((minute/10)%10);//formula for the third digit
        digits[4]= (minute%10);//formula for the fourth digit
   if (hreading != lasthbstate) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (hreading != hbstate) {
      hbstate = hreading;
      if (hbstate == HIGH) {
        if (hour == 24){
          hour = 0;
          rtc.adjust(hour);
        }
        else {
          hour ++;
          rtc.adjust(hour);
        }
      }
    }
  }
  if (mreading != lastmbstate) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (mreading != mbstate) {
      mbstate = mreading;
      if (mbstate == HIGH) {
        if (minute == 60){
          minute = 0;
          rtc.adjust(minute);
        }
        else {
          minute ++;
          rtc.adjust(minute);
        }
      }
    }
  }


  // save the reading. Next time through the loop, it'll be the lastButtonState:

    digitalWrite(STCP_pin, LOW);
        //The lines of code below is the shiftout command
        //use least LSBFIRST instead of MSBFIRST
        shiftOut(DS_pin, SHCP_pin, LSBFIRST, numbers[digits[4]]); // shift in the digit, last digit.
        shiftOut(DS_pin, SHCP_pin, LSBFIRST, numbers[digits[3]]); // shift in the digit, third digit.
        shiftOut(DS_pin, SHCP_pin, LSBFIRST, numbers[digits[2]]); // shift in the digit, second digit.
        shiftOut(DS_pin, SHCP_pin, LSBFIRST, numbers[digits[1]]); // shift in the digit, first digit.
        //The sequenece is important
    digitalWrite(STCP_pin, HIGH); // flash the digit in the correct place
        delay (100);
   
}

When using rtc.adjust(), you need to provide the full data and time. In the case of adjusting the hour, just take the current data/time you have read from the RTC and only change the hour:

          rtc.adjust(DateTime(now.year(), now.month(), now.day(), hour, now.minute(), now.second()));

When adjusting the minute, take the hour from the RTC, and only change the minute. You could also set the second to zero when adjusting minutes, so that you can control more precisely when the clock advances to the next minute.

Ok so I got this. It doesn't give me errors anymore but it still doesn't work as intended.

//this version is working, don't change it. Make a copy instead.
//yo I am goated
#include <Adafruit_I2CRegister.h>
#include <RTClib.h>
RTC_DS3231 rtc;
//set up for the Shift registers and numbers
//check the datasheet for the SN74HC595 to see the idividual pins
#define Hourbutton 8//button used to adjust the hour
#define Minutebutton 9//button used to adjust the minutes
#define DS_pin 4//blue
#define STCP_pin 5//yellow
#define SHCP_pin 6//green
//color coded so you don't blows it up
int numbers[10] {126, 48, 109, 121, 51, 91, 95, 112, 127, 123}; //use [int digits [10] { 1, 79, 18, 12, 76, 36, 32, 15, 0, 4};] instead if
//your display is the common Annode type. I did all the binary conversion, you are welcome.
uint8_t digits[4]; //int d1; int d2; int d3; int d4;// has to define all of these, they reperesent the individual digits and the time number
int hbstate;
int mbstate;
int lasthbstate = 0;
int lastmbstate = 0;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;
void setup() {
pinMode(Hourbutton, INPUT);
pinMode(Minutebutton, INPUT);
pinMode(DS_pin, OUTPUT);
pinMode(STCP_pin, OUTPUT);
pinMode(SHCP_pin, OUTPUT);
// initializing the rtc
if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    while (1) delay(10);
  }
  if (rtc.lostPower()){
  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
  //rtc.adjust(DateTime(2026,6,6,22,40,30);// This line sets the RTC with the time from the pc when compile
}
void loop() {
  //DateTime hour = now.hour();
  //DateTime hour = now.minute();
  DateTime now = rtc.now();
  uint8_t hour = now.hour();
  uint8_t minute = now.minute();
  int hreading = digitalRead(Hourbutton);
  int mreading = digitalRead(Minutebutton);
    //Formula to display Hours
        digits[1]= ((hour/10)%10);//formula for the first digit
        digits[2]= (hour%10);//formula for the second digit
    //Formua to display Minutes
        digits[3]= ((minute/10)%10);//formula for the third digit
        digits[4]= (minute%10);//formula for the fourth digit
   if (hreading != lasthbstate) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (hreading != hbstate) {
      hbstate = hreading;
      if (hbstate == 1) {
        if (hour == 24){
          hour = 0;
          rtc.adjust(now.hour());
        }
        else {
          hour + 1;
          rtc.adjust(now.hour());
        }
      }
    }
  }
  if (mreading != lastmbstate) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (mreading != mbstate) {
      mbstate = mreading;
      if (mbstate == 1) {
        if (minute == 60){
          minute = 0;
          rtc.adjust(now.minute());
        }
        else {
          minute + 1;
          rtc.adjust(now.minute());
        }
      }
    }
  }
  // save the reading. Next time through the loop, it'll be the lastButtonState:
    digitalWrite(STCP_pin, LOW);
        //The lines of code below is the shiftout command
        //use least LSBFIRST instead of MSBFIRST
        shiftOut(DS_pin, SHCP_pin, LSBFIRST, numbers[digits[4]]); // shift in the digit, last digit.
        shiftOut(DS_pin, SHCP_pin, LSBFIRST, numbers[digits[3]]); // shift in the digit, third digit.
        shiftOut(DS_pin, SHCP_pin, LSBFIRST, numbers[digits[2]]); // shift in the digit, second digit.
        shiftOut(DS_pin, SHCP_pin, LSBFIRST, numbers[digits[1]]); // shift in the digit, first digit.
        //The sequenece is important
    digitalWrite(STCP_pin, HIGH); // flash the digit in the correct place
        delay (100);
   
}

Describe the sequence of events when your sketch "does not work", then describe how you intended your sketch to work.

This compiles but I don't have the hardware to test it.

//this version is working, don't change it. Make a copy instead.
//yo I am goated
#include <Adafruit_I2CRegister.h>
#include <RTClib.h>
RTC_DS3231 rtc;
//set up for the Shift registers and numbers
//check the datasheet for the SN74HC595 to see the idividual pins
#define Hourbutton 8    //button used to adjust the hour
#define Minutebutton 9  //button used to adjust the minutes
#define DS_pin 4        //blue
#define STCP_pin 5      //yellow
#define SHCP_pin 6      //green
//color coded so you don't blows it up
int numbers[10]{ 126, 48, 109, 121, 51, 91, 95, 112, 127, 123 };  //use [int digits [10] { 1, 79, 18, 12, 76, 36, 32, 15, 0, 4};] instead if
//your display is the common Annode type. I did all the binary conversion, you are welcome.
uint8_t digits[4];  //int d1; int d2; int d3; int d4;// has to define all of these, they reperesent the individual digits and the time number
int hbstate;
int mbstate;
int lasthbstate = 0;
int lastmbstate = 0;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;

void setup() {
  pinMode(Hourbutton, INPUT);
  pinMode(Minutebutton, INPUT);
  pinMode(DS_pin, OUTPUT);
  pinMode(STCP_pin, OUTPUT);
  pinMode(SHCP_pin, OUTPUT);
  // initializing the rtc
  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    while (1) delay(10);
  }
  if (rtc.lostPower()) {
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
  //rtc.adjust(DateTime(2026,6,6,22,40,30);// This line sets the RTC with the time from the pc when compile
}
void loop() {
  //DateTime hour = now.hour();
  //DateTime hour = now.minute();
  DateTime now = rtc.now();
  uint8_t hour = now.hour();
  uint8_t minute = now.minute();
  int hreading = digitalRead(Hourbutton);
  int mreading = digitalRead(Minutebutton);
  //Formula to display Hours
  digits[1] = ((hour / 10) % 10);    //formula for the first digit
  digits[2] = (hour % 10);           //formula for the second digit
                                     //Formua to display Minutes
  digits[3] = ((minute / 10) % 10);  //formula for the third digit
  digits[4] = (minute % 10);         //formula for the fourth digit

  if (hreading != lasthbstate) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (hreading != hbstate) {
      hbstate = hreading;
      if (hbstate == 1) {
        if (hour == 24) {
          hour = 0;
        } else {
          hour += 1;
        }
      }
    }
  }

  if (mreading != lastmbstate) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (mreading != mbstate) {
      mbstate = mreading;
      if (mbstate == 1) {
        if (minute == 60) {
          minute = 0;
        } else {
          minute += 1;
        }
      }
    }
  }

  rtc.adjust(DateTime(F(__DATE__), hour, minute, now.second())); // Update the hours and minutes

  // save the reading. Next time through the loop, it'll be the lastButtonState:
  digitalWrite(STCP_pin, LOW);
  //The lines of code below is the shiftout command
  //use least LSBFIRST instead of MSBFIRST
  shiftOut(DS_pin, SHCP_pin, LSBFIRST, numbers[digits[4]]);  // shift in the digit, last digit.
  shiftOut(DS_pin, SHCP_pin, LSBFIRST, numbers[digits[3]]);  // shift in the digit, third digit.
  shiftOut(DS_pin, SHCP_pin, LSBFIRST, numbers[digits[2]]);  // shift in the digit, second digit.
  shiftOut(DS_pin, SHCP_pin, LSBFIRST, numbers[digits[1]]);  // shift in the digit, first digit.
                                                             //The sequenece is important
  digitalWrite(STCP_pin, HIGH);                              // flash the digit in the correct place
  delay(100);
}