Get rid of delay(), solve buttons debounce [solved]

With the help of the suggestions received below, I got a version of the program in which I used millis () instead of delay (), and I did button debounce, as much as I knew how. You can see the code below, I will continue to try to improve it.
Hello everyone!
Following on from a post I opened yesterday; I have 'arranged' a program, which should display the time (on Display No. 1) and the date (on Display No. 2), these will be adjusted by buttons.
In the Program_1 sketch I used delay (), so the program works slower; button commands are a bit difficult; the two dots on the display blink at approx. 1s.
In Program_2 I tried to give up the delay () and solve the commands by buttons, but it turned out to be a mess when the buttons were pressed, it works worse than Program_1.

How it should work: Display 1 shows the time with the blink midpoints at 0.5s; Display 2 shows DDMM date for 1s, short pause, then it shows YYYY year for 1s. I also have 3 buttons; two for increase / decrease hour, minutes and so on; the third one to be able to enter the menu, ie through each pair of digits on the display.

I use Arduino as a hobby, you can see that the program is written simply, but the use of millis () and button debounce led to something that does not lead me to solve.

What suggestions do you offer?

sketch_oct10a.ino (5.4 KB)

Program_2.ino (6.7 KB)
Debouncing
Delay using millis

#include <Wire.h>
#include <RTClib.h>
RTC_DS1307 RTC;

#include <TM1637Display.h>
#define CLK1 2
#define DIO1 3
TM1637Display Display1(CLK1, DIO1); // display no 1 for time
#define CLK2 5
#define DIO2 6
TM1637Display Display2(CLK2, DIO2); // display no 2 for date

int P1 = 8; // Button SET MENU
int P2 = 9; // Button +
int P3 = 10; // Button -

int myHour;
int myMinute;
int myYear;
int myMonth;
int myDay;

int menu = 0;
uint8_t segto;
unsigned long previousMillis = 0;
uint8_t blink_status = 0x40;

void setup()
{
  Display1.setBrightness(2);
  Display1.clear();
  Display2.setBrightness(5);
  Display2.clear();

  pinMode(P1, INPUT);
  pinMode(P2, INPUT);
  pinMode(P3, INPUT);

  Serial.begin(9600);
  Wire.begin();
  RTC.begin();

  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    // Set the date and time at compile time
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
  RTC.adjust(DateTime(__DATE__, __TIME__)); //removing "//" to adjust the time
  // The default display shows the date and time
  Display1.showNumberDecEx(myHour * 100 + myMinute, 0x00, true, 4, 0);
}

void loop()
{
#define buttonPressed LOW                             // When the button is pressed the input will be low, this is to remove the confusion this migth cause.
  uint32_t currentMillis = millis();                    // Millis times uses to debounce the button
  static uint32_t lastMillis;                           // Start of the debounce timeout
  const uint32_t BOUNCETIMEOUT = 20;                    // Debounce time in milliseconds
  bool currentButtonState = digitalRead(P1);     // Reads the current state of the button and saves the result in a bool
  static bool lastButtonState;
  if (lastButtonState != currentButtonState) {          // Checks to see if the button has been pressed or released, at this point the button has not been debounced
    if (currentMillis - lastMillis >= BOUNCETIMEOUT) {  // Checks to see if the state of the button has been stable for at least bounceTimeout duration
      lastButtonState = currentButtonState;
      // check if you press the SET button and increase the menu index
      if (currentButtonState == buttonPressed)
      {
        menu = menu + 1;
      }
    }
  } else {
    lastMillis = currentMillis;                         // Saves the current value of millis in last millis so the debounce timer starts from current millis
  }
  // ******************** select subroutine
  if (menu == 0)
  {
    DisplayDateTime();
  }
  if (menu == 1)
  {
    DisplaySetHour();
  }
  if (menu == 2)
  {
    DisplaySetMinute();
  }
  if (menu == 3)
  {
    DisplaySetYear();
  }
  if (menu == 4)
  {
    DisplaySetMonth();
  }
  if (menu == 5)
  {
    DisplaySetDay();
  }
  if (menu == 6)
  {
    //SaveSettings();
    //delay(500); // using millis() instead of this delay
    if (millis() >= 500) {
      SaveSettings();
      menu = 0;
    }
  }
}

void DisplayDateTime()
{
  unsigned long currentMillis = millis();
  DateTime now = RTC.now();
  myMinute = now.minute();
  myHour = now.hour();
  myYear = now.year();
  myDay = now.day();
  myMonth = now.month();

  // make the midpoints blink  - method 2
  if ((currentMillis - previousMillis) > 500) {
    previousMillis = millis();
    if (blink_status == 0) {
      blink_status = 0x40;
    } else {
      blink_status = 0;
      //previousMillis = 0;
    }
    Display1.showNumberDecEx(myHour * 100 + myMinute, blink_status, true, 4, 0);
  }

  int mySecond = now.second();
  if ((mySecond % 3) < 2) {
    // show the day and month for 2 seconds out of every 3 seconds
    Display2.showNumberDec((myDay / 10) % 10, false, 1, 0);
    Display2.showNumberDec(myDay % 10, false, 1, 1);
    Display2.showNumberDec((myMonth / 10) % 10, false, 1, 2);
    Display2.showNumberDec(myMonth % 10, false, 1, 3);
  }
  else {
    // show the year for 1 second out of every 3 seconds
    Display2.showNumberDec(myYear);
  }
}

void DisplaySetHour()
{
  Display1.clear(); // refresh the display
#define buttonPressed LOW                             // When the button is pressed the input will be low, this is to remove the confusion this migth cause.
  uint32_t currentMillis = millis();                    // Millis times uses to debounce the button
  static uint32_t lastMillis;                           // Start of the debounce timeout
  const uint32_t BOUNCETIMEOUT = 20;                    // Debounce time in milliseconds
  bool currentButtonState = digitalRead(P2);            // Reads the current state of the button and saves the result in a bool
  static bool lastButtonState;                          // Holds the previous debounced state of the button

  if (lastButtonState != currentButtonState) {          // Checks to see if the button has been pressed or released, at this point the button has not been debounced
    if (currentMillis - lastMillis >= BOUNCETIMEOUT) {  // Checks to see if the state of the button has been stable for at least bounceTimeout duration
      lastButtonState = currentButtonState;             // At this point the button has been debounced, so save the last state
      if (currentButtonState == buttonPressed) {
        if (currentButtonState == LOW)
        {
          if (myHour == 23)
          {
            myHour = 0;
          }
          else
          {
            myHour = myHour + 1;
          }
        }
      }
    }
  } else {
    lastMillis = currentMillis;                         // Saves the current value of millis in last millis so the debounce timer starts from current millis
  }
  // ***********************************************************
#define buttonPressed1 LOW                             // When the button is pressed the input will be low, this is to remove the confusion this migth cause.
  bool currentButtonState1 = digitalRead(P3);     // Reads the current state of the button and saves the result in a bool
  static bool lastButtonState1;                         // Holds the previous debounced state of the button
  if (lastButtonState1 != currentButtonState1) {          // Checks to see if the button has been pressed or released, at this point the button has not been debounced
    if (currentMillis - lastMillis >= BOUNCETIMEOUT) {  // Checks to see if the state of the button has been stable for at least bounceTimeout duration
      lastButtonState1 = currentButtonState1;             // At this point the button has been debounced, so save the last state
      if (currentButtonState1 == buttonPressed1) {
        if (currentButtonState1 == LOW)
        {
          if (myHour == 0)
          {
            myHour = 23;
          }
          else
          {
            myHour = myHour - 1;
          }
        }
      }
    }
  } else {
    lastMillis = currentMillis;                // Saves the current value of millis in last millis so the debounce timer starts from current millis
  }

  Display1.showNumberDec((myHour / 10) % 10, false, 1, 0);
  Display1.showNumberDec(myHour % 10, false, 1, 1);
}
void DisplaySetMinute()
{
  Display1.clear(); // refresh the display
#define buttonPressed LOW                             // When the button is pressed the input will be low, this is to remove the confusion this migth cause.
  uint32_t currentMillis = millis();                    // Millis times uses to debounce the button
  static uint32_t lastMillis;                           // Start of the debounce timeout
  const uint32_t BOUNCETIMEOUT = 20;                    // Debounce time in milliseconds
  bool currentButtonState = digitalRead(P2);     // Reads the current state of the button and saves the result in a bool
  static bool lastButtonState;                          // Holds the previous debounced state of the button

  if (lastButtonState != currentButtonState) {          // Checks to see if the button has been pressed or released, at this point the button has not been debounced
    if (currentMillis - lastMillis >= BOUNCETIMEOUT) {  // Checks to see if the state of the button has been stable for at least bounceTimeout duration
      lastButtonState = currentButtonState;             // At this point the button has been debounced, so save the last state
      if (currentButtonState == buttonPressed) {
        if (currentButtonState == LOW)
        {
          if (myMinute == 59)
          {
            myMinute = 0;
          }
          else
          {
            myMinute = myMinute + 1;
          }
        }
      }
    }
  } else {
    lastMillis = currentMillis;                         // Saves the current value of millis in last millis so the debounce timer starts from current millis
  }
  //***********************************************************8
#define buttonPressed1 LOW                             // When the button is pressed the input will be low, this is to remove the confusion this migth cause.
  bool currentButtonState1 = digitalRead(P3);     // Reads the current state of the button and saves the result in a bool
  static bool lastButtonState1;                         // Holds the previous debounced state of the button
  if (lastButtonState1 != currentButtonState1) {          // Checks to see if the button has been pressed or released, at this point the button has not been debounced
    if (currentMillis - lastMillis >= BOUNCETIMEOUT) {  // Checks to see if the state of the button has been stable for at least bounceTimeout duration
      lastButtonState1 = currentButtonState1;             // At this point the button has been debounced, so save the last state
      if (currentButtonState1 == buttonPressed1) {
        if (currentButtonState1 == LOW)
        {
          if (myMinute == 0)
          {
            myMinute = 59;
          }
          else
          {
            myMinute = myMinute - 1;
          }
        }
      }
    }
  } else {
    lastMillis = currentMillis;                         // Saves the current value of millis in last millis so the debounce timer starts from current millis
  }
  Display1.showNumberDec((myMinute / 10) % 10, false, 1, 2);
  Display1.showNumberDec(myMinute % 10, false, 1, 3);
}
void DisplaySetYear()
{
  Display2.clear(); // refresh the display
#define buttonPressed LOW                             // When the button is pressed the input will be low, this is to remove the confusion this migth cause.
  uint32_t currentMillis = millis();                    // Millis times uses to debounce the button
  static uint32_t lastMillis;                           // Start of the debounce timeout
  const uint32_t BOUNCETIMEOUT = 20;                    // Debounce time in milliseconds
  bool currentButtonState = digitalRead(P2);     // Reads the current state of the button and saves the result in a bool
  static bool lastButtonState;                          // Holds the previous debounced state of the button

  if (lastButtonState != currentButtonState) {          // Checks to see if the button has been pressed or released, at this point the button has not been debounced
    if (currentMillis - lastMillis >= BOUNCETIMEOUT) {  // Checks to see if the state of the button has been stable for at least bounceTimeout duration
      lastButtonState = currentButtonState;             // At this point the button has been debounced, so save the last state
      if (currentButtonState == buttonPressed) {
        if (currentButtonState == LOW)
        {
          myYear = myYear + 1;
        }
      }
    }
  } else {
    lastMillis = currentMillis;                         // Saves the current value of millis in last millis so the debounce timer starts from current millis
  }
  //***********************************************************8
#define buttonPressed1 LOW                             // When the button is pressed the input will be low, this is to remove the confusion this migth cause.
  bool currentButtonState1 = digitalRead(P3);     // Reads the current state of the button and saves the result in a bool
  static bool lastButtonState1;                         // Holds the previous debounced state of the button
  if (lastButtonState1 != currentButtonState1) {          // Checks to see if the button has been pressed or released, at this point the button has not been debounced
    if (currentMillis - lastMillis >= BOUNCETIMEOUT) {  // Checks to see if the state of the button has been stable for at least bounceTimeout duration
      lastButtonState1 = currentButtonState1;             // At this point the button has been debounced, so save the last state
      if (currentButtonState1 == buttonPressed1) {
        if (currentButtonState1 == LOW)
        {
          myYear = myYear - 1;
        }
      }
    }
  } else {
    lastMillis = currentMillis;                         // Saves the current value of millis in last millis so the debounce timer starts from current millis
  }
  Display2.showNumberDec(myYear);
}
void DisplaySetMonth()
{
  Display2.clear(); // refresh the display
#define buttonPressed LOW                             // When the button is pressed the input will be low, this is to remove the confusion this migth cause.
  uint32_t currentMillis = millis();                    // Millis times uses to debounce the button
  static uint32_t lastMillis;                           // Start of the debounce timeout
  const uint32_t BOUNCETIMEOUT = 20;                    // Debounce time in milliseconds
  bool currentButtonState = digitalRead(P2);     // Reads the current state of the button and saves the result in a bool
  static bool lastButtonState;                          // Holds the previous debounced state of the button

  if (lastButtonState != currentButtonState) {          // Checks to see if the button has been pressed or released, at this point the button has not been debounced
    if (currentMillis - lastMillis >= BOUNCETIMEOUT) {  // Checks to see if the state of the button has been stable for at least bounceTimeout duration
      lastButtonState = currentButtonState;             // At this point the button has been debounced, so save the last state
      if (currentButtonState == buttonPressed) {
        if (currentButtonState == LOW)
        {
          if (myMonth == 12)
          {
            myMonth = 1;
          }
          else
          {
            myMonth = myMonth + 1;
          }
        }
      }
    }
  } else {
    lastMillis = currentMillis;                         // Saves the current value of millis in last millis so the debounce timer starts from current millis
  }
  //***********************************************************8
#define buttonPressed1 LOW                             // When the button is pressed the input will be low, this is to remove the confusion this migth cause.
  bool currentButtonState1 = digitalRead(P3);     // Reads the current state of the button and saves the result in a bool
  static bool lastButtonState1;                         // Holds the previous debounced state of the button
  if (lastButtonState1 != currentButtonState1) {          // Checks to see if the button has been pressed or released, at this point the button has not been debounced
    if (currentMillis - lastMillis >= BOUNCETIMEOUT) {  // Checks to see if the state of the button has been stable for at least bounceTimeout duration
      lastButtonState1 = currentButtonState1;             // At this point the button has been debounced, so save the last state
      if (currentButtonState1 == buttonPressed1) {
        if (currentButtonState1 == LOW)
        {
          if (myMonth == 1)
          {
            myMonth = 12;
          }
          else
          {
            myMonth = myMonth - 1;
          }
        }
      }

    }
  } else {
    lastMillis = currentMillis;                         // Saves the current value of millis in last millis so the debounce timer starts from current millis
  }
  Display2.showNumberDec((myMonth / 10) % 10, false, 1, 2);
  Display2.showNumberDec(myMonth % 10, false, 1, 3);
}
void DisplaySetDay()
{
  Display2.clear(); // refresh the display
#define buttonPressed LOW                             // When the button is pressed the input will be low, this is to remove the confusion this migth cause.
  uint32_t currentMillis = millis();                    // Millis times uses to debounce the button
  static uint32_t lastMillis;                           // Start of the debounce timeout
  const uint32_t BOUNCETIMEOUT = 20;                    // Debounce time in milliseconds
  bool currentButtonState = digitalRead(P2);     // Reads the current state of the button and saves the result in a bool
  static bool lastButtonState;                          // Holds the previous debounced state of the button

  if (lastButtonState != currentButtonState) {          // Checks to see if the button has been pressed or released, at this point the button has not been debounced
    if (currentMillis - lastMillis >= BOUNCETIMEOUT) {  // Checks to see if the state of the button has been stable for at least bounceTimeout duration
      lastButtonState = currentButtonState;             // At this point the button has been debounced, so save the last state
      if (currentButtonState == buttonPressed) {
        if (currentButtonState == LOW)
        {
          if (myDay == 31)
          {
            myDay = 1;
          }
          else
          {
            myDay = myDay + 1;
          }
        }
      }
    }
  } else {
    lastMillis = currentMillis;                         // Saves the current value of millis in last millis so the debounce timer starts from current millis
  }

  //***********************************************************8
#define buttonPressed1 LOW                             // When the button is pressed the input will be low, this is to remove the confusion this migth cause.
  bool currentButtonState1 = digitalRead(P3);     // Reads the current state of the button and saves the result in a bool
  static bool lastButtonState1;                         // Holds the previous debounced state of the button
  if (lastButtonState1 != currentButtonState1) {          // Checks to see if the button has been pressed or released, at this point the button has not been debounced
    if (currentMillis - lastMillis >= BOUNCETIMEOUT) {  // Checks to see if the state of the button has been stable for at least bounceTimeout duration
      lastButtonState1 = currentButtonState1;             // At this point the button has been debounced, so save the last state
      if (currentButtonState1 == buttonPressed1) {
        if (currentButtonState1 == LOW)
        {
          if (myDay == 1)
          {
            myDay = 31;
          }
          else
          {
            myDay = myDay - 1;
          }
        }
      }

    }
  } else {
    lastMillis = currentMillis;                         // Saves the current value of millis in last millis so the debounce timer starts from current millis
  }
  Display2.showNumberDec((myDay / 10) % 10, false, 1, 0);
  Display2.showNumberDec(myDay % 10, false, 1, 1);
}

void SaveSettings()
{
  if (millis() >= 200) {
    Display1.clear();
    Display2.clear();
    Display1.showNumberDec(0123);
    Display2.showNumberDec(0123);
    RTC.adjust(DateTime(myYear, myMonth, myDay, myHour, myMinute, 0));
    //delay(200); // using millis() instead of this delay
  }
}

I suggest that you post the code here so that we don't have to download it. Read the forum guidelines to see how to properly post code and some information on how to get the most from this forum.
Use the IDE autoformat tool (ctrl-t or Tools, Auto format) before posting code in code tags.

What Arduino board?

Please edit your question here and include a link to your other question so people can find it.

This is my tutorial on buttons: Buttons and other electro-mechanical inputs (introduction)

There are plenty of others if you search.

@cristian10001

I have an obsession a special interest in debouncing switches and unblocking code, and I have to write saying the two sites you linked are very good small examples and seem to not make mistakes that many well meant articles do.

Imma read them carefully and will adjust my quickly acquired opinion if I discover anything untoward… I’ve been through many articles and libraries and usually see the flaws, even if the presented solutions work fine, that make them less than universal applicable.

Getting them right does not mean they have to be complex or expressed in anything other than straight ahead C.

a7

Unless you just want to go through the exercise of writing some button code yourself, I wouldn't re-invent the wheel.
I'd recommend using a full featured button library.
Easy to use and keeps the main code simple and clean.
By using a library you integrate it quickly to be up and running very quickly with something that is already working and fully debugged.
You can do things like check for button pressed, just pressed, just released, long pressed, etc...

I recommend the JC_BUTTON library.
It is available in the IDE library manager.
I've used it for years on many different projects.
Here is a link to the github page:

--- bill

I check it. Thanks.

The question, if you will, was about how I tried to get rid of delay () using millis (), and do button debounce, which seems to have made things worse.

I check the info you provided and I will try to implement it.

On getting rid of delay I think others have pointed you in the right direction, I have nothing useful to add to that. On doing button debounce without delay I hope my tutorial will help you. Note that it only works properly with responsive, co-operative non-blocking code. No delay() anywhere.

#include <Wire.h>
#include <RTClib.h>
RTC_DS1307 RTC;

#include <TM1637Display.h>
#define CLK1 2
#define DIO1 3
TM1637Display Display1(CLK1, DIO1); // display no 1 for time
#define CLK2 5
#define DIO2 6
TM1637Display Display2(CLK2, DIO2); // display no 2 for date

int P1 = 8; // Button SET MENU
int P2 = 9; // Button +
int P3 = 10; // Button -

int myHour;
int myMinute;
int myYear;
int myMonth;
int myDay;

int menu = 0;
uint8_t segto;
unsigned long previousMillis = 0;
uint8_t blink_status = 0x40;
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup()
{
  Display1.setBrightness(2);
  Display1.clear();
  Display2.setBrightness(5);
  Display2.clear();

  pinMode(P1, INPUT);
  pinMode(P2, INPUT);
  pinMode(P3, INPUT);

  Serial.begin(9600);
  Wire.begin();
  RTC.begin();

  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    // Set the date and time at compile time
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
  RTC.adjust(DateTime(__DATE__, __TIME__)); //removing "//" to adjust the time
  // The default display shows the date and time
  Display1.showNumberDecEx(myHour * 100 + myMinute, 0x00, true, 4, 0);
}

void loop()
{

  // check if you press the SET button and increase the menu index
  if ( (millis() - lastDebounceTime) > debounceDelay) {
    if (digitalRead(P1) == LOW)
    {
      lastDebounceTime = millis();
      menu = menu + 1;
    }
  }
  // select subroutine
  if (millis() >= 100) {
    if (menu == 0)
    {
      DisplayDateTime();
    }
    if (menu == 1)
    {
      DisplaySetHour();
    }
    if (menu == 2)
    {
      DisplaySetMinute();
    }
    if (menu == 3)
    {
      DisplaySetYear();
    }
    if (menu == 4)
    {
      DisplaySetMonth();
    }
    if (menu == 5)
    {
      DisplaySetDay();
    }
    if (menu == 6)
    {
      SaveSettings();
      if (millis() >= 500) {
        menu = 0;
      }
    }
  }
}

void DisplayDateTime()
{
  DateTime now = RTC.now();
  myMinute = now.minute();
  myHour = now.hour();
  myYear = now.year();
  myDay = now.day();
  myMonth = now.month();

  /*Display1.showNumberDec(myHour*100+myMinute, true);
    // make the midpoints blink  - method 1
    delay(500);
    segto = 0x80 | Display1.encodeDigit(myHour%10);
    Display1.setSegments(&segto, 1, 1);
    delay(50);*/

  // make the midpoints blink  - method 2
  if (millis() >= 200) {
    if (blink_status == 0) {
      blink_status = 0x40;
    } else {
      blink_status = 0;
      //previousMillis = 0;
    }
    Display1.showNumberDecEx(myHour * 100 + myMinute, blink_status, true, 4, 0);
  }
  Display2.clear();
  Display2.showNumberDec((myDay / 10) % 10, false, 1, 0);
  Display2.showNumberDec(myDay % 10, false, 1, 1);
  Display2.showNumberDec((myMonth / 10) % 10, false, 1, 2);
  Display2.showNumberDec(myMonth % 10, false, 1, 3);
  myDelay(60);
  Display2.showNumberDec(myYear);
  myDelay(30);
  Display2.clear();
  myDelay(5);
}

void DisplaySetHour()
{
  Display1.clear(); // refresh the display
  if ( (millis() - lastDebounceTime) > debounceDelay) {
    if (digitalRead(P2) == LOW)
    {
      lastDebounceTime = millis();
      if (myHour == 23)
      {
        myHour = 0;
      }
      else
      {
        myHour = myHour + 1;
      }
    }
  }
  if ( (millis() - lastDebounceTime) > debounceDelay) {
    if (digitalRead(P3) == LOW)
    {
      lastDebounceTime = millis();
      if (myHour == 0)
      {
        myHour = 23;
      }
      else
      {
        myHour = myHour - 1;
      }
    }
  }
  Display1.showNumberDec((myHour / 10) % 10, false, 1, 0);
  Display1.showNumberDec(myHour % 10, false, 1, 1);
}

void DisplaySetMinute()
{
  Display1.clear();
  if ( (millis() - lastDebounceTime) > debounceDelay) {
    if (digitalRead(P2) == LOW)
    {
      lastDebounceTime = millis();
      if (myMinute == 59)
      {
        myMinute = 0;
      }
      else
      {
        myMinute = myMinute + 1;
      }
    }
  }
  if ( (millis() - lastDebounceTime) > debounceDelay) {
    if (digitalRead(P3) == LOW)
    {
      lastDebounceTime = millis();
      if (myMinute == 0)
      {
        myMinute = 59;
      }
      else
      {
        myMinute = myMinute - 1;
      }
    }
  }
  Display1.showNumberDec((myMinute / 10) % 10, false, 1, 2);
  Display1.showNumberDec(myMinute % 10, false, 1, 3);
}

void DisplaySetYear()
{
  Display2.clear();
  if ( (millis() - lastDebounceTime) > debounceDelay) {
    if (digitalRead(P2) == LOW)
    {
      lastDebounceTime = millis();
      myYear = myYear + 1;
    }
  }
  if ( (millis() - lastDebounceTime) > debounceDelay) {
    if (digitalRead(P3) == LOW)
    {
      lastDebounceTime = millis();
      myYear = myYear - 1;
    }
  }
  Display2.showNumberDec(myYear);
}

void DisplaySetMonth()
{
  Display2.clear();
  if ( (millis() - lastDebounceTime) > debounceDelay) {
    if (digitalRead(P2) == LOW)
    {
      lastDebounceTime = millis();
      if (myMonth == 12)
      {
        myMonth = 1;
      }
      else
      {
        myMonth = myMonth + 1;
      }
    }
  }
  if ( (millis() - lastDebounceTime) > debounceDelay) {
    if (digitalRead(P3) == LOW)
    {
      lastDebounceTime = millis();
      if (myMonth == 1)
      {
        myMonth = 12;
      }
      else
      {
        myMonth = myMonth - 1;
      }
    }
  }
  Display2.showNumberDec((myMonth / 10) % 10, false, 1, 2);
  Display2.showNumberDec(myMonth % 10, false, 1, 3);
}

void DisplaySetDay()
{
  Display2.clear();
  if ( (millis() - lastDebounceTime) > debounceDelay) {
    if (digitalRead(P2) == LOW)
    {
      lastDebounceTime = millis();
      if (myDay == 31)
      {
        myDay = 1;
      }
      else
      {
        myDay = myDay + 1;
      }
    }
  }
  if ( (millis() - lastDebounceTime) > debounceDelay) {
    if (digitalRead(P3) == LOW)
    {
      lastDebounceTime = millis();
      if (myDay == 1)
      {
        myDay = 31;
      }
      else
      {
        myDay = myDay - 1;
      }
    }
  }
  Display2.showNumberDec((myDay / 10) % 10, false, 1, 0);
  Display2.showNumberDec(myDay % 10, false, 1, 1);
}
// delay between DDMM and YYYY
void myDelay(int n)
{
  for (int i = 1; i <= n; i++)
  {
    delayMicroseconds(16000); delayMicroseconds(16000);
  }
}
void SaveSettings()
{
  if (millis() >= 200) {
    Display1.clear();
    Display2.clear();
    Display1.showNumberDec(0123);
    Display2.showNumberDec(0123);
    RTC.adjust(DateTime(myYear, myMonth, myDay, myHour, myMinute, 0));
  }
}
1 Like
#include <Wire.h>
#include <RTClib.h>
RTC_DS1307 RTC;

#include <TM1637Display.h>
#define CLK1 2
#define DIO1 3
TM1637Display Display1(CLK1, DIO1); // display no 1 for time
#define CLK2 5
#define DIO2 6
TM1637Display Display2(CLK2, DIO2); // display no 2 for date

int P1 = 8; // Button SET MENU
int P2 = 9; // Button +
int P3 = 10; // Button -

int myHour;
int myMinute;
int myYear;
int myMonth;
int myDay;

int menu = 0;
uint8_t segto;
unsigned long previousMillis = 0;
uint8_t blink_status = 0x40;

void setup()
{
  Display1.setBrightness(2);
  Display1.clear();
  Display2.setBrightness(5);
  Display2.clear();

  pinMode(P1, INPUT);
  pinMode(P2, INPUT);
  pinMode(P3, INPUT);

  Serial.begin(9600);
  Wire.begin();
  RTC.begin();

  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    // Set the date and time at compile time
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
  RTC.adjust(DateTime(__DATE__, __TIME__)); //removing "//" to adjust the time
  // The default display shows the date and time
  Display1.showNumberDecEx(myHour * 100 + myMinute, 0x00, true, 4, 0);
}

void loop()
{

  // check if you press the SET button and increase the menu index
  if (digitalRead(P1) == LOW)
  {
    menu = menu + 1;
  }
  // select subroutine
  if (menu == 0)
  {
    DisplayDateTime();
  }
  if (menu == 1)
  {
    DisplaySetHour();
  }
  if (menu == 2)
  {
    DisplaySetMinute();
  }
  if (menu == 3)
  {
    DisplaySetYear();
  }
  if (menu == 4)
  {
    DisplaySetMonth();
  }
  if (menu == 5)
  {
    DisplaySetDay();
  }
  if (menu == 6)
  {
    SaveSettings();
    delay(500); // I must get rid of delay()
    menu = 0;
  }
  delay(100);
}

void DisplayDateTime()
{
  unsigned long currentMillis = millis();
  DateTime now = RTC.now();
  myMinute = now.minute();
  myHour = now.hour();
  myYear = now.year();
  myDay = now.day();
  myMonth = now.month();

  /*Display1.showNumberDec(myHour*100+myMinute, true);
    // make the midpoints blink  - method 1
    delay(500);
    segto = 0x80 | Display1.encodeDigit(myHour%10);
    Display1.setSegments(&segto, 1, 1);
    delay(50);*/

  // make the midpoints blink  - method 2
  if ((currentMillis - previousMillis) > 500) {
    previousMillis = millis();
    if (blink_status == 0) {
      blink_status = 0x40;
    } else {
      blink_status = 0;
      //previousMillis = 0;
    }
    Display1.showNumberDecEx(myHour * 100 + myMinute, blink_status, true, 4, 0);
  }
  //previousMillis = 0;
  Display2.clear();
  Display2.showNumberDec((myDay / 10) % 10, false, 1, 0);
  Display2.showNumberDec(myDay % 10, false, 1, 1);
  Display2.showNumberDec((myMonth / 10) % 10, false, 1, 2);
  Display2.showNumberDec(myMonth % 10, false, 1, 3);
  myDelay(60);
  Display2.showNumberDec(myYear);
  myDelay(30);
  Display2.clear(); myDelay(5);
}

void DisplaySetHour()
{
  Display1.clear(); // refresh the display

  if (digitalRead(P2) == LOW)
  {
    if (myHour == 23)
    {
      myHour = 0;
    }
    else
    {
      myHour = myHour + 1;
    }
  }
  if (digitalRead(P3) == LOW)
  {
    if (myHour == 0)
    {
      myHour = 23;
    }
    else
    {
      myHour = myHour - 1;
    }
  }
  Display1.showNumberDec((myHour / 10) % 10, false, 1, 0);
  Display1.showNumberDec(myHour % 10, false, 1, 1);
  delay(200); // I must get rid of delay()
}

void DisplaySetMinute()
{
  Display1.clear();

  if (digitalRead(P2) == LOW)
  {
    if (myMinute == 59)
    {
      myMinute = 0;
    }
    else
    {
      myMinute = myMinute + 1;
    }
  }
  if (digitalRead(P3) == LOW)
  {
    if (myMinute == 0)
    {
      myMinute = 59;
    }
    else
    {
      myMinute = myMinute - 1;
    }
  }
  Display1.showNumberDec((myMinute / 10) % 10, false, 1, 2);
  Display1.showNumberDec(myMinute % 10, false, 1, 3);
  delay(200);
}

void DisplaySetYear()
{
  Display2.clear();

  if (digitalRead(P2) == LOW)
  {
    myYear = myYear + 1;
  }
  if (digitalRead(P3) == LOW)
  {
    myYear = myYear - 1;
  }
  Display2.showNumberDec(myYear);
  delay(200);
}

void DisplaySetMonth()
{
  Display2.clear();

  if (digitalRead(P2) == LOW)
  {
    if (myMonth == 12)
    {
      myMonth = 1;
    }
    else
    {
      myMonth = myMonth + 1;
    }
  }
  if (digitalRead(P3) == LOW)
  {
    if (myMonth == 1)
    {
      myMonth = 12;
    }
    else
    {
      myMonth = myMonth - 1;
    }
  }
  Display2.showNumberDec((myMonth / 10) % 10, false, 1, 2);
  Display2.showNumberDec(myMonth % 10, false, 1, 3);
  delay(200);
}

void DisplaySetDay()
{
  Display2.clear();

  if (digitalRead(P2) == LOW)
  {
    if (myDay == 31)
    {
      myDay = 1;
    }
    else
    {
      myDay = myDay + 1;
    }
  }
  if (digitalRead(P3) == LOW)
  {
    if (myDay == 1)
    {
      myDay = 31;
    }
    else
    {
      myDay = myDay - 1;
    }
  }
  Display2.showNumberDec((myDay / 10) % 10, false, 1, 0);
  Display2.showNumberDec(myDay % 10, false, 1, 1);
  delay(200);
}
// delay between DDMM and YYYY
void myDelay(int n)
{
  for (int i = 1; i <= n; i++)
  {
    delayMicroseconds(16000); delayMicroseconds(16000);
  }
}
void SaveSettings()
{
  Display1.clear();
  Display2.clear();
  Display1.showNumberDec(0123);
  Display2.showNumberDec(0123);
  RTC.adjust(DateTime(myYear, myMonth, myDay, myHour, myMinute, 0));
  delay(200);
}

Okay, now you can see the code directly in the post, this is to make a small difference between programs.
I will try again, maybe I can improve the operation of the program.
The main problem is the replacement of delay () with something better, millis ().

That's a good one, thanks.

IMO it does all and everything anyone should try to get out of a button on a microprocessro.

Maybe it's just age, but I am really not good at double clicking, short versus medium versus long hold times and so forth.

A long press is tolerable but I like them better when they are only used to mean sometheing extreme and/or rare, like RESET or LAUNCH MISSLE.

Just Sayin'.

a7

To switch between day/month and year, why not try something like this?
(You don't even need millis() for this!)

int mySecond = now.second();

if ((mySecond % 3) < 2) {
  // show the day and month for 2 seconds out of every 3 seconds
  Display2.showNumberDec((myDay / 10) % 10, false, 1, 0);
  Display2.showNumberDec(myDay % 10, false, 1, 1);
  Display2.showNumberDec((myMonth / 10) % 10, false, 1, 2);
  Display2.showNumberDec(myMonth % 10, false, 1, 3);
}
else {
  // show the year for 1 second out of every 3 seconds
  Display2.showNumberDec(myYear);
}

Thanks.I managed to reduce the number of delay () functions used in the program.
You can see the entire program on top in the post.
Now, the menu created allows me to go through each DisplaySetWhatever function; now I will add another button, and I will have B1 for clock setting, and B2 for date setting; and the other two buttons will be for increase / decrease.
I will continue to try to improve it, because I have to put it on an ATMega8, and now it doesn't fit.

Thanks. Your suggestion helped me. I managed to improve the program.
You can see it up in the post.
I will continue to try to improve it, because I have to put it on an ATMega8, and now it doesn't fit.

1 Like
  Serial.begin(9600);
  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    // Set the date and time at compile time
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }

What happens if you get rid of Serial? Would that save enough space?

Wow, I didn't know that Serial.begin() will "eat" so much space. Now that I've gained some space, I could try one more thing. Thank you.

hi all,
i have problem with running jc_button-lib

  1. jc_button is messaged as "installed" in IDE "Arduino 1.8.15"
    2)#include <JC_Button.h> is at begin of sketch

  2. an additional lib "VarSpeedServo" is installed and its ...h is high-lighted,
    but <JC_Button.h> is not highlighted

  3. downloading generates zip-file named "arduino/JC_Button-..long hexnumber...", extracting generates directory arduino/JC_Button-..long hexnumber...
    there are subdirs "src" and "examples"

but then in code
before Setup
Button myButtonR(pin_reset_btn,BOUNCETIMEOUT); ´ //-compiled ok in loop myButtonR(begin); `
raises ERROR !
begin was not declared is this scope

can someone show me how to install correctly !?

If you have
myButtonR(begin);
in your code you have the incorrect syntax.
You need to call the begin() method and it should be done in setup() not loop()

See the library examples for the proper syntax for calling begin() in setup() and how to use the library and what must be called in loop()

--- bill

many thanks, bperrybap,

i have "tomatoes on my eyes" :sweat_smile:

naturally, my code coud not work !

after correcting sketch compiled ok !