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.
