Adding a countdown timer to a two click-counters

This is the same sketch as in #8 but this version has some variable name changes and comments added.

//
//https://forum.arduino.cc/t/adding-a-countdown-timer-to-a-two-click-counters/1050342
//

//********************************************^************************************************
//  Version   YY/MM/DD     Comments
//  =======   ========     ========================================================
//  1.00      22/11/06     Running code
//  1.01      22/11/07     Changed some of the variable names and added some comments
//
//
//********************************************^************************************************


/*
   This is Arduino "Hot-Wire foam cutter checkpoint counter" using a pair of TM1637 seven-segment LED Displays.
   Long pieces of Styrofoam require two people to cut the length. This sketch allows for each user to increment the counter
   as they arrive at each check-point marked on the piece, as well as have a visual read-out showing their location as well as their partner's.

   The original code is based on "Robojax Touch Counter V3 using TM1637 4 digits LED display"
   Link: https://robojax.com/learn/arduino/?vid=robojax_touch_counter_V3_TM1637
*/

#include <Arduino.h>
#include <TM1637Display.h>

//*********************************************************************************
//Master Display connection pins (Digital Pins)
#define CLK1               6
#define DIO1               7

//Slave Display connection pins (Digital Pins)
#define CLK2               8
#define DIO2               9

TM1637Display display1(CLK1, DIO1);      //define display 1 (Master) object
TM1637Display display2(CLK2, DIO2);      //define display 2 (Slave) object

//     01
//  20    02
//     40
//  10    04
//     08

uint8_t blank[]    = { 0x0, 0x0, 0x0, 0x0 };      //data to clear the screen
uint8_t data8888[] = { 0xff, 0xff, 0xff, 0xff };  //show all segments.
uint8_t donE[]     = { 0x5e, 0x5c, 0x54, 0x79 };  //donE

//*********************************************************************************

#define PUSHED             LOW
#define RELEASED           HIGH

#define ENABLED            true
#define DISABLED           false

const byte heartbeatLED  = 13;
const byte resetPin      = 12;
const byte slavePin      = 11;
const byte masterPin     = 10;

//9, 8, 7, and 6 are used for the displays

const byte increment     = 5;
const byte decrement     = 4;

bool timerCountFlag      = DISABLED;  //ENABLE means we are currently counting down the seconds
bool adjustingTimerFlag  = DISABLED;  //Enabled means we are waiting for the user to stop adjusting the target time
bool newPositionFlag     = DISABLED;  //Enabled means either the Master or Slave has reached a milestone

const byte maximumCount  = 10;        //adjust as needed

//the last state the switches were in
byte lastMasterState;
byte lastSlaveState;
byte lastResetState;
byte lastIncrementState;
byte lastDecrementState;

int targetCount;                      //the starting time value the Master has entered for every countdown period
int counter;                          //a decreasing value showing the number of seconds left to go
int MasterCount;                      //the milestone the Master is sitting at
int SlaveCount;                       //the milestone the Slave is sitting at

//timing stuff
unsigned long heartbeatMillis;
unsigned long switchMillis;
unsigned long setCountMillis;
unsigned long adjustingMillis;

//*********************************************************************************
void setup()
{
  Serial.begin(9600);
  Serial.println("Hotwire Checkpoint Counter");

  pinMode(heartbeatLED, OUTPUT);

  pinMode(masterPin, INPUT_PULLUP);
  pinMode(slavePin,  INPUT_PULLUP);
  pinMode(resetPin,  INPUT_PULLUP);
  pinMode(increment, INPUT_PULLUP);
  pinMode(decrement, INPUT_PULLUP);

  display1.setBrightness(0x0f);
  display2.setBrightness(0x0f);

  display1.setSegments(data8888); //display 8888 on display1 for test.
  display2.setSegments(data8888); //display 8888 on display2 for test.
  delay(3000);                    //3 second 8888 display at start-up.

  // Display "00:00" on both displays
  //display Master count and colon on first part of Master display.
  display1.showNumberDecEx(MasterCount, 0b01000000, true, 2, 0);

  //display Slave count  on second part of Master display.
  display1.showNumberDec(SlaveCount, true, 2, 2);

  //display Slave count and colon on first part of Slave display.
  display2.showNumberDecEx(SlaveCount, 0b01000000, true, 2, 0);

  //display Master count on second part of Slave display.
  display2.showNumberDec(MasterCount, true, 2, 2);

} //END of   setup()


//*********************************************************************************
void loop()
{
  //***********************************************         heartbeat T I M E R
  //time to toggle the heartbeat LED ?
  if (millis() - heartbeatMillis >= 500)
  {
    //restart the TIMER
    heartbeatMillis = millis();

    //toggle LED
    digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));
  }

  //***********************************************         check switches T I M E R
  //is it time to check the switches ?
  if (millis() - switchMillis >= 100)
  {
    //restart the TIMER
    switchMillis = millis();

    checkSwitches();
  }

  //***********************************************         adjusting targetCount T I M E R
  //if enabled is it time to once again display Master and Slave milestones ?
  if (adjustingTimerFlag == ENABLED && millis() - adjustingMillis >= 2000ul)
  {
    //2 seconds has gone by without the Master either incrementing or decrementing the targetCount    
    //stop this TIMER
    adjustingTimerFlag = false;

    //re-display the Master and Slave milestones
    //display Master count and colon on first part of Master display.
    display1.showNumberDecEx(MasterCount, 0b01000000, true, 2, 0);

    //display Slave count on second part of Master display.
    display1.showNumberDec(SlaveCount, true, 2, 2);

    //display Slave count and colon on first part of Slave display.
    display2.showNumberDecEx(SlaveCount, 0b01000000, true, 2, 0);

    //display Master count on second part of Slave display.
    display2.showNumberDec(MasterCount, true, 2, 2);

  }

  //***********************************************         counting down T I M E R
  //are we counting down ?
  if (timerCountFlag == ENABLED)
  {
    //has 1 second gone by ?
    if (millis() - setCountMillis >= 1000ul)
    {
      //restart this TIMER
      setCountMillis = millis();

      //update the displays
      //display count on Master display.
      display1.setSegments(blank); //clear the Master screen from previous values.
      display1.showNumberDecEx(counter, 0b00000000, false, 4, 0);


      //display count on Slave display.
      display2.setSegments(blank); //clear the Slave screen from previous values.
      display2.showNumberDecEx(counter, 0b00000000, false, 4, 0);

      counter--;

      //have we finished with this setCount ?
      if (counter < 0)
      {
        display1.setSegments(donE); //Display donE on Master
        display2.setSegments(donE); //Display donE on Slave
        delay(1000);

        //stop this TIMER
        timerCountFlag = DISABLED;

        //display Master count and colon on first part of Master display.
        display1.showNumberDecEx(MasterCount, 0b01000000, true, 2, 0);

        //display Slave count  on second part of Master display.
        display1.showNumberDec(SlaveCount, true, 2, 2);

        //display Slave count and colon on first part of Slave display.
        display2.showNumberDecEx(SlaveCount, 0b01000000, true, 2, 0);

        //display Master count on second part of Slave display.
        display2.showNumberDec(MasterCount, true, 2, 2);
      }
    }
  }

  //***********************************************
  //are we ready to check for a milestone match ?
  if (newPositionFlag == ENABLED)
  {
    //is there a match between the two milestones
    if (MasterCount == SlaveCount)
    {
      //both milestones are now at the same value
      //enable the countdown timing operation
      timerCountFlag = ENABLED;

      //reload the counter with the target value
      counter = targetCount;

      //we do not need to check any further, disable checking
      newPositionFlag = DISABLED;
    }
  }

  //***********************************************
  //     Other none blocking code goes here
  //***********************************************

} //END of   loop()


//*******************************************************************************
//switches are checked every 100ms
void checkSwitches()
{
  byte currentState;

  //***********************************************         m a s t e r  P i n
  //masterPin switch
  currentState = digitalRead(masterPin);

  if (lastMasterState != currentState)
  {
    //update to the new state
    lastMasterState = currentState;

    //************************
    //if we are not timing, is the switch pushed ?
    if (timerCountFlag == DISABLED && currentState == PUSHED)
    {
      newPositionFlag = ENABLED;

      MasterCount++; 

      //display Master count and colon on first part of Master display.
      display1.showNumberDecEx(MasterCount, 0b01000000, true, 2, 0);

      //display Slave count  on second part of Master display.
      display1.showNumberDec(SlaveCount, true, 2, 2);

      //display Slave count and colon on first part of Slave display.
      display2.showNumberDecEx(SlaveCount, 0b01000000, true, 2, 0);

      //display Master count on second part of Slave display.
      display2.showNumberDec(MasterCount, true, 2, 2);

      Serial.print("Master: ");
      Serial.print(MasterCount);
      Serial.print(" | Slave: ");
      Serial.print(SlaveCount);
      Serial.println(".");
    }

  } //END of this switch

  //***********************************************         s l a v e P i n
  //slavePin switch
  currentState = digitalRead(slavePin);

  if (lastSlaveState != currentState)
  {
    //update to the new state
    lastSlaveState = currentState;

    //************************
    //if we are not timing, is the switch pushed ?
    if (timerCountFlag == DISABLED && currentState == PUSHED)
    {
      newPositionFlag = ENABLED;

      SlaveCount++;

      //display Master count and colon on first part of Master display.
      display1.showNumberDecEx(MasterCount, 0b01000000, true, 2, 0);

      //display Slave count  on second part of Master display.
      display1.showNumberDec(SlaveCount, true, 2, 2);

      //display Slave count and colon on first part of Slave display.
      display2.showNumberDecEx(SlaveCount, 0b01000000, true, 2, 0);

      //display Master count on second part of Slave display.
      display2.showNumberDec(MasterCount, true, 2, 2);

      Serial.print("Master: ");
      Serial.print(MasterCount);
      Serial.print(" | ");
      Serial.print("Slave: ");
      Serial.print(SlaveCount);
      Serial.println(".");
    }

  } //END of this switch

  //***********************************************         r e s e t P i n
  //resetPin switch
  currentState = digitalRead(resetPin);

  if (lastResetState != currentState)
  {
    //update to the new state
    lastResetState = currentState;

    //************************
    //if we are not timing, is the switch pushed ?
    if (timerCountFlag == DISABLED && currentState == PUSHED)
    {
      MasterCount = 0;
      SlaveCount = 0;
      Serial.println("Milestones Reset.");

      display1.showNumberDecEx(MasterCount, 0b01000000, true, 2, 0);
      display1.showNumberDec(SlaveCount, true, 2, 2);

      display2.showNumberDecEx(SlaveCount, 0b01000000, true, 2, 0);
      display2.showNumberDec(MasterCount, true, 2, 2);
    }

  } //END of this switch

  //***********************************************         i n c r e m e n t
  //increment switch
  currentState = digitalRead(increment);

  if (lastIncrementState != currentState)
  {
    //update to the new state
    lastIncrementState = currentState;

    //************************
    //if we are not timing, is the switch pushed ?
    if (timerCountFlag == DISABLED && currentState == PUSHED)
    {
      //enable the TIMER
      adjustingTimerFlag = ENABLED;

      //restart the TIMER
      adjustingMillis = millis();

      targetCount++;

      if (targetCount > maximumCount)
      {
        targetCount = maximumCount;
      }

      //update the displays
      //display targetCount on the Master display.
      display1.setSegments(blank); //clear the Master screen from previous values.
      display1.showNumberDecEx(targetCount, 0b00000000, false, 4, 0);

      //display targetCount on the Slave display.
      display2.setSegments(blank); //clear the Slave screen from previous values.
      display2.showNumberDecEx(targetCount, 0b00000000, false, 4, 0);

      Serial.print("targetCount = ");
      Serial.println(targetCount);
    }

  } //END of this switch

  //***********************************************         d e c r e m e n t
  //decrement switch
  currentState = digitalRead(decrement);

  if (lastDecrementState != currentState)
  {
    //update to the new state
    lastDecrementState = currentState;

    //************************
    //if we are not timing, is the switch pushed ?
    if (timerCountFlag == DISABLED && currentState == PUSHED)
    {
      //enable the TIMER
      adjustingTimerFlag = ENABLED;

      //restart the TIMER
      adjustingMillis = millis();

      targetCount--;

      if (targetCount < 0)
      {
        targetCount = 0;
      }

      //update the displays
      //display targetCount Master display.
      display1.setSegments(blank); //clear the Master screen from previous values.
      display1.showNumberDecEx(targetCount, 0b00000000, false, 4, 0);

      //display targetCount Slave display.
      display2.setSegments(blank); //clear the Slave screen from previous values.
      display2.showNumberDecEx(targetCount, 0b00000000, false, 4, 0);

      Serial.print("targetCount = ");
      Serial.println(targetCount);
    }

  } //END of this switch

} //END of   checkSwithes()

In your spare time ;) , make a more permanent solderless breadboard setup.