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.