Newbie - Building a Surf Comp Timer. Does my Code look ok?

Hi there all,
I'm very green when it comes to Arduino and coding. i did an electronics trade 25 years ago and did basic programming way back then.
Anyway I'm feeling my way through the arduino world as my Surfboard club needs a new timing system and i thought i could build one. i thought use a PLC to start with but that's expensive and found the Arduino world!

So I am part way through writing my code, I focused on the hard part first (for me) the timing and output functions.

anyway i learnt along the way that delays dont allow the timer to run in the background :slight_smile:
so i have been learning about Millis and how to use it.

I have updated my code with Millis to control pin 10.
I'm wondering if anyone could spare 5 minutes and look at my code, tell me if I've done things right and / or if there are area's i could improve?

I'm using an Arduino UNO minima

much appreciate all.

// Surf Comp Timer
// 2 x Position switches controll the timer function (off/Run/Pause) & (timer set 20,25,30,35,40 minutes)
// when timer starts hooter sounds for 3 seconds, green light on and timer counts down (no delays)
// when timer reaches 5 minute mark - Green light off and Amber light on
// when timer reaches 0 - amber light off, red light on, hooter sounds (high 3 seconds, low 1 second, high 3 Seconds, Low)
// when timer reaches 0 a 30 second reset time starts ( time frame between heats)
// when 30 second reset timer reaches 0 the main timer restarts - hooter, green light etc.
// once timers starts the selected time can not change unless timer is turned off / reset.
// if pause is selected - count down time paused, hooter sounds twice and red light on.
// if un paused - timer resumes from current state, hooter sounds for 3 seconds

// for testing purpose shorter times have been set.
// hooter hi 1.5 seconds, hooter off 1 second
// timer default to 2 minutes, amber light on at 1 minute.

#include <TM1637Display.h>

// Countdown Timer
const unsigned long COUNTDOWN_TIME = 120; // 2 minutes in seconds
const unsigned long COUNTDOWN_RESET_TIME = 30; // 30 seconds countdown after reaching 0

// Variables for timing 
unsigned long previousMillisStart = 0; // Stores the last time action was performed at the start 
unsigned long previousMillisEnd = 0; // Stores the last time action was performed at the end 
unsigned long actionInterval = 1500; // 1.5 seconds in milliseconds 
unsigned long waitInterval = 1000; // 1 second in milliseconds 

// Flags to track pulse status 
bool pulseStartedAtStart = false; 
bool pulseSecondPhaseEnd = false;

// Pins for TM1637 display module
#define CLK_PIN 9
#define DIO_PIN 8
#define PIN_10 10
#define PIN_11 11
#define PIN_12 12
#define PIN_13 13
#define PIN_0 0  // Pin 0 for reset mode
#define PIN_1 1  // Pin 1 for starting timer mode
#define PIN_2 2  // Pin 2 for pause/resume timer

TM1637Display display(CLK_PIN, DIO_PIN);

unsigned long startTime;
unsigned long currentTime;
unsigned long elapsedTime;
unsigned long resetStartTime;
unsigned long resetElapsedTime;

bool countdownReset = false;
unsigned long lastUpdateTime = 0; // For handling 1-second intervals in reset countdown
bool inResetMode = false; // Flag to track if we are in reset mode
bool timerPaused = false; // Flag to track if the timer is paused

void setup() {
  // Setup pins
  pinMode(PIN_10, OUTPUT);
  pinMode(PIN_11, OUTPUT);
  pinMode(PIN_12, OUTPUT);
  pinMode(PIN_13, OUTPUT);
  pinMode(PIN_0, INPUT);  // Pin 0 as input for reset mode
  pinMode(PIN_1, INPUT);  // Pin 1 as input for timer mode
  pinMode(PIN_2, INPUT);  // Pin 2 as input for pause/resume
  
  display.setBrightness(7); // Set the brightness of the display (0-7)
  display.clear(); // Clear the display
  startTime = millis(); // Record the starting time
  
  // Initial states for Pins
  digitalWrite(PIN_10, LOW);
  digitalWrite(PIN_11, LOW);
  digitalWrite(PIN_12, LOW);
  digitalWrite(PIN_13, LOW);
}

void loop() {
  currentTime = millis(); // Get the current time
  
  // Check if Pin 2 is low or high (pause/resume functionality)
  if (digitalRead(PIN_2) == LOW) {
    if (!timerPaused) {
      timerPaused = true; // Pause the timer
      // Show the current time on the display (formatted as MM:SS)
      unsigned long remainingTime = COUNTDOWN_TIME - elapsedTime;
      unsigned int minutes = remainingTime / 60;
      unsigned int seconds = remainingTime % 60;
      display.showNumberDecEx(minutes * 100 + seconds, 0b01000000, true); // Show time with colon
      
      // set pin 13 to high
      digitalWrite(PIN_13, HIGH);  // Pin 13 = high

      // This part of the code functions only when the timer is being paused so the delays do not effect the count down. 
      // Set Pin 10 high for 1.5 seconds, low for 1 second, high for 1.5 seconds, then low
      digitalWrite(PIN_10, HIGH);
      delay(1500);
      digitalWrite(PIN_10, LOW);
      delay(1000);
      digitalWrite(PIN_10, HIGH);
      delay(1500);
      digitalWrite(PIN_10, LOW);
    }
  } else {
    if (timerPaused) {
      timerPaused = false; // Resume the timer
      startTime = millis() - elapsedTime * 1000; // Adjust startTime to continue from where it was paused
      
      // Set Pin 13 low after pause
      digitalWrite(PIN_13, LOW);  // Pin 13 = low
     
     // This part of the code only effects the timer during pause mode and does not effect the timer sequence as the timer will continue after the delay as normal Set Pin 10 high for 1.5 seconds when unpausing the timer
      digitalWrite(PIN_10, HIGH);
      delay(1500);
      digitalWrite(PIN_10, LOW);
    }
  }

  // Only proceed with the timer logic if not paused
  if (!timerPaused) {
    elapsedTime = (currentTime - startTime) / 1000; // Calculate elapsed time in seconds

    // Check if pin 0 is low (reset mode)
    if (digitalRead(PIN_0) == LOW) {
      // Enter reset mode if not already in reset mode
      if (!inResetMode) {
        inResetMode = true;
        display.clear();
        display.showNumberDecEx(0, 0b01000000, true); // Show 00:00
        digitalWrite(PIN_10, LOW);  // Reset loop 1 actions
        digitalWrite(PIN_11, LOW);  // Reset loop 1 actions
        digitalWrite(PIN_12, LOW);  // Reset loop 1 actions
        digitalWrite(PIN_13, LOW);  // Reset loop 1 actions
        startTime = millis(); // Reset the start time for the timer
        countdownReset = false; // Ensure we don't proceed in reset mode
      }
    } 
    // If pin 1 is low, enter timer mode (and reset timer if pin 0 is low)
    else if (digitalRead(PIN_1) == LOW) {
      if (inResetMode) {
        inResetMode = false; // Exit reset mode
        startTime = millis(); // Restart timer when moving to timer mode
      }

      if (countdownReset) {
        // If we're in the reset countdown period (30 seconds)
        resetElapsedTime = (currentTime - resetStartTime) / 1000;

        if (resetElapsedTime <= COUNTDOWN_RESET_TIME) {
          // Only update the display every second to avoid odd number issues
          if (currentTime - lastUpdateTime >= 1000) {  // Check if a second has passed
            lastUpdateTime = currentTime;  // Update the time of the last update
            unsigned long remainingTime = COUNTDOWN_RESET_TIME - resetElapsedTime;
            
            // Display remaining time in Seconds (with colon between minutes and seconds)
            display.showNumberDecEx(remainingTime, 0b01000000, true); // Colon will show
          }
        }

        if (resetElapsedTime == COUNTDOWN_RESET_TIME) {
          // Once the 30-second countdown is complete, set Pin 13 to LOW
          digitalWrite(PIN_13, LOW); // Set Pin 13 to low

          // Reset the timer and start the countdown again after the 30 seconds
          startTime = millis();  // Restart the 5-minute countdown
          countdownReset = false; // Exit the reset countdown
        }
      } else {
        // Regular countdown logic
        if (elapsedTime <= COUNTDOWN_TIME) {
          unsigned long remainingTime = COUNTDOWN_TIME - elapsedTime;

          // Display remaining time in Minutes:Seconds format with colon
          unsigned int minutes = remainingTime / 60;
          unsigned int seconds = remainingTime % 60;

          // Display time with colon
          display.showNumberDecEx(minutes * 100 + seconds, 0b01000000, true);

          // Loop 1 logic (Main counter start)
          if (remainingTime == COUNTDOWN_TIME) {
          
          // Heat Start sequence for hooter
          
          // old digitalWrite(PIN_10, HIGH);  // Pin 10 = high
          // old delay(1500);  // Wait for 1.5 seconds 
          // old digitalWrite(PIN_10, LOW);   // Pin 10 = low
          
          // new code
            digitalWrite(PIN_10, HIGH); // Pin 10 = high 
            // makes previousMillis now = to the current time
            previousMillisStart = currentMillis; // Store current time to start timing pulse 
            pulseStartedAtStart = true; // Flag to indicate that pulse should be performed 
            }
            digitalWrite(PIN_11, HIGH);  // Pin 11 = high
          }
          // Handle the start pulse (1.5 seconds high, then low) 
          if (pulseStartedAtStart && currentMillis - previousMillisStart >= actionInterval) { 
            digitalWrite(PIN_10, LOW); // Pin 10 = low after 1.5 seconds pulseStartedAtStart = false; // Reset the flag so it doesn't pulse again 
            }

          // At 60 seconds remaining
          if (remainingTime == 60) {
            digitalWrite(PIN_11, LOW);  // Pin 11 = low
            digitalWrite(PIN_12, HIGH); // Pin 12 = high
          }

          // End of Loop 1 (Timer reaches 00:00)
          if (remainingTime == 0) {
            // Set Pin 12 to low
            digitalWrite(PIN_12, LOW);

            // Set Pin 13 high at the end of Loop 1
            digitalWrite(PIN_13, HIGH);  // Pin 13 = high

            // Heat end Hooter Sequence
            // Pulse Pin 10 for 1.5 seconds, wait for 1 second, then pulse again
            // old digitalWrite(PIN_10, HIGH);
            // old delay(1500);
            // old digitalWrite(PIN_10, LOW);
            // old delay(1000);
            // old digitalWrite(PIN_10, HIGH);
            // old delay(1500);
            // old digitalWrite(PIN_10, LOW);
            
            //New Code
            // Pulse logic at the end of the countdown (after remainingTime == 0) 
          if (pulseStartedAtStart == false) { 
            // First pulse (1.5 seconds duration) 
          if (currentMillis - previousMillisEnd >= actionInterval && !pulseSecondPhaseEnd) { 
            digitalWrite(PIN_10, LOW); // Turn off pulse after 1.5 seconds 
            previousMillisEnd = currentMillis; // Reset timer for the wait phase pulseSecondPhaseEnd = true; // Move to the next phase (waiting 1 second) 
            } 
          else if (pulseSecondPhaseEnd && currentMillis - previousMillisEnd >= waitInterval) { 
            digitalWrite(PIN_10, HIGH); // Start second pulse 
            previousMillisEnd = currentMillis; // Reset timer 
            pulseSecondPhaseEnd = false; // Move to the next phase (turning off after 1.5 seconds) 
          } 
          else if (!pulseSecondPhaseEnd && currentMillis - previousMillisEnd >= actionInterval) { 
            digitalWrite(PIN_10, LOW); // Turn off pulse after 1.5 seconds 
            pulseStartedAtStart = false; // End the pulse sequence

            // Start Loop 2 (30-second countdown)
            resetStartTime = millis();
            countdownReset = true;
          }
        }
      }
    }
  }

  delay(10); // Short delay to allow for proper loop execution
}



type or paste code here

switches are connected to GND and use a 10k Ohm physically wired pull up resistor. the switches are rotary switches where only 1 contact can be closed at any time. For the outputs they control a 4 channel relay board & using a TM1637 4 digit 7 segment display.

  • Always show us a good schematic of your proposed circuit. Show us good images of your ‘actual’ wiring.

  • Avoid using delay( ) in your code.

  • Switches connect to GND and a GPIO should have pull-up resistors, internal or external.

1 Like

Hi LarryD,

Sorry mate I have added a schematic sketch.
Agree I'm trying to avoid the delays, there are prtions of my code i have left them as i thought it simplified my code.
I have tried to implement what i have learnt from your tube and websites on Millis () for the area's of code that I need to run at the same time.
i have failed a few time with my coding of millis()

switches are connected to GND via a pull up resistor which i have wired through a circuit board.

thanks for taking the time to look at my post.

cheers

  • Your external pull-up resistors can be replaced by the Arduino's internal pull-up resistors.

  • Please elaborate more on how you have the 4 channel relay board wired.
    Also give us a link to the relay module.

  • We like to see images of your actual wiring.

  • Your schematic is not reflected in your software sketch.

  • You have currentMillis and currentTime, which is it ?

  • You have not created the variable remainingTime

  • Every open bracket { needs a closing bracket }

  • With your switch connections, don't use GPIO 0 or 1 ?

  • Suggest you not use HIGH or LOW, instead use:
    greenLightON/greenLightOFF
    hooterON/hooterOFF
    etc . . .

  • Suggest you look at what a State Machine can do for you.

  • Where did you get this sketch from ?

2 Likes
#define PIN_10 10
#define PIN_11 11
#define PIN_12 12
#define PIN_13 13

Using symbols like this serve two purposes. 1. They give a value a meaningful name that explains its use or purpose. 2. They allow the value to be changed without having to change the value at multiple places in the code and avoid the risk of missing changing some of them.

Your symbols serve neither purpose. 1. Their names don't add any meaning, they don't explain their use or purpose. 2. If you did later change one of their values, for example changing PIN_11 to have the value 13, it would be self-contradictory and confusing for anyone reading the code.

So give such symbols names which describe their use/purpose and don't imply a fixed pin number you might later want to change.

For example:

#define PIN_0 0  // Pin 0 for reset mode
#define PIN_1 1  // Pin 1 for starting timer mode
#define PIN_2 2  // Pin 2 for pause/resume timer

would be so much better as

#define RESET_PIN 0  // Pin 0 for reset mode
#define START_PIN 1  // Pin 1 for starting timer mode
#define PAUSE_PIN 2  // Pin 2 for pause/resume timer

2 Likes

Hi Larry,

Before I started I wasn’t aware the arduino had built in pull ups so I made my own pcb with resistors for each of my inputs.

I’m using the relay module from the link below. The board requires a vcc, Gnd and inputs 1-4 for each relay. Link below to the data sheet.

I could give you an image of my wiring but it won’t be real clear as to what’s going on I have a lot of wires already soldered in place to the rotary switches and the resistors.
Sorry.

I know my sketch does not show all the inputs just yet as I’m working on the off/run/pause functionality at the moment. I planned to add the timer inputs later

It will be currentTime sorry. This is a type as I have been using bits of code I have picked up along the way and mashing it together. I’m 4 weeks new to this arduino stuff.

I have the arduino uni minima which says that pin 0 & pin 1 can be used as inputs.

As I said I have been looking at a heap of videos and reading a lot in 4 weeks and I have compiled this sketch from what I have seen learnt and read. I know it’s not the best I’m still very green.

I have been looking up state machines since you mentioned them and yes possibly what I need, Thankyou. Bit of an information overload for me, I need to look into them more and read them so I understand how to they are written. But from my 2hrs of research they seem like what I need.

Thanks for taking the time to read my code and respond I really appreciate it.

https://media.jaycar.com.au/product/resources/XC4440_datasheetMain_67858.pdf?_gl=1n089zg_gcl_au*MTM0OTMzODEyOC4xNzQwMTY3MTkw

Thanks, I understand what you’re saying.
I think because in my head I know what each one does it’s ok but I know I should make it clear.

Thanks for your time much appreciated

In a year or two you may need to debug or enhance the code. Will it be so clear in your head then?

  • Pat yourself on the back for starting on this journey.
  • With respect, we need to see what you see.
    Attach good images (clearly showing connections) of your actual wiring.
  • The road to success includes making one piece of hardware/software work flawlessly.
    Do this one step at a time.

  • Am still not sure what switches you are using, is it a 3 position and a 5 position rotary switch ?

  • Pins 0 and 1 are used for serial communications, using them for INPUTs/OUTPUTs may cause you problems.

  • Are your relay coils 5v or 12v ?




  • If you are willing, we can help you consolidate your schematic and aid in program structure.
    You need to ask questions as things advance otherwise you will not become proficient in either hardware or software.
    Do you want to proceed ?

Thanks Larry,
I've been trying to break my code back down into sections just to get the basic functions working.
The below code works (But I'm using delay() function), i tried to replace the delay() with millis() however so far i have been unsuccessful.

i have tried to add as many comments as possible.

#include <TM1637Display.h>
// Surf Comp Timer
// Counter Counts down from a set Time (default to 2minutes for testing)
// timer uses 2 x Single pole rotary switches ( 1 x 3 position (off / run / Pause) & 1 x 5 position (20, 25,30,35,40 minute selections))
// inputs use physical hard wired pull up resistors, switching the GND
// outputs operate a 4 channel relay module (https://media.jaycar.com.au/product/resources/XC4440_datasheetMain_67858.pdf?_gl=1*6tdtid*_gcl_au*ODYxMjU3NzU2LjE3MzY5ODIxNjA.)
// display is a tm1637 4 digit 7 segment with colon.
//when in off timers are reset and outputs are low


// Countdown Timer
const unsigned long COUNTDOWN_TIME = 120; // 2 minutes in seconds
const unsigned long COUNTDOWN_RESET_TIME = 30; // 30 seconds countdown after reaching 0

// Pins for TM1637 display module
#define CLK_PIN 9
#define DIO_PIN 8
#define PIN_10 10 // hooter
#define PIN_11 11 // green light
#define PIN_12 12 // yellow light
#define PIN_13 13 // red light
#define PIN_0 0  // Pin 0 for reset mode
#define PIN_1 1  // Pin 1 for starting timer mode
#define PIN_2 2  // Pin 2 for pause/resume timer

TM1637Display display(CLK_PIN, DIO_PIN);

unsigned long startTime;
unsigned long currentTime;
unsigned long elapsedTime;
unsigned long resetStartTime;
unsigned long resetElapsedTime;

bool countdownReset = false;
unsigned long lastUpdateTime = 0; // For handling 1-second intervals in reset countdown
bool inResetMode = false; // Flag to track if we are in reset mode
bool timerPaused = false; // Flag to track if the timer is paused

void setup() {
  // Setup pins
  pinMode(PIN_10, OUTPUT); // hooter
  pinMode(PIN_11, OUTPUT); // green light
  pinMode(PIN_12, OUTPUT); // yellow light
  pinMode(PIN_13, OUTPUT); // red light
  pinMode(PIN_0, INPUT);  // Pin 0 as input for reset mode
  pinMode(PIN_1, INPUT);  // Pin 1 as input for timer mode
  pinMode(PIN_2, INPUT);  // Pin 2 as input for pause/resume
  
  display.setBrightness(7); // Set the brightness of the display (0-7)
  display.clear(); // Clear the display
  startTime = millis(); // Record the starting time
  
  // Initial states for Pins
  digitalWrite(PIN_10, LOW);
  digitalWrite(PIN_11, LOW);
  digitalWrite(PIN_12, LOW);
  digitalWrite(PIN_13, LOW);
}

void loop() {
  currentTime = millis(); // Get the current time
  
  // Check if Pin 2 is low or high (pause/resume functionality)
  if (digitalRead(PIN_2) == LOW) {
    if (!timerPaused) {
      timerPaused = true; // Pause the timer
      // Show the current time on the display (formatted as MM:SS)
      unsigned long remainingTime = COUNTDOWN_TIME - elapsedTime;
      unsigned int minutes = remainingTime / 60;
      unsigned int seconds = remainingTime % 60;
      display.showNumberDecEx(minutes * 100 + seconds, 0b01000000, true); // Show time with colon
      
      // red light on set pin 13 to high
      digitalWrite(PIN_13, HIGH);  // Pin 13 = high

      // sound hooter twice - Set Pin 10 high for 1.5 seconds, low for 1 second, high for 1.5 seconds, then low
      digitalWrite(PIN_10, HIGH);
      delay(1500);
      digitalWrite(PIN_10, LOW);
      delay(1000);
      digitalWrite(PIN_10, HIGH);
      delay(1500);
      digitalWrite(PIN_10, LOW);
    }
  } else {
    if (timerPaused) {
      timerPaused = false; // Resume the timer
      startTime = millis() - elapsedTime * 1000; // Adjust startTime to continue from where it was paused
      
      // red light off Set Pin 13 low after pause
      digitalWrite(PIN_13, LOW);  // Pin 13 = low
     
     // sound hooter once Set Pin 10 high for 1.5 seconds when unpausing the timer
      digitalWrite(PIN_10, HIGH);
      delay(1500);
      digitalWrite(PIN_10, LOW);
    }
  }

  // Only proceed with the timer logic if not paused
  if (!timerPaused) {
    elapsedTime = (currentTime - startTime) / 1000; // Calculate elapsed time in seconds

    // Check if pin 0 is low (reset mode)
    if (digitalRead(PIN_0) == LOW) {
      // Enter reset mode if not already in reset mode
      if (!inResetMode) {
        inResetMode = true;
        display.clear();
        display.showNumberDecEx(0, 0b01000000, true); // Show 00:00
        digitalWrite(PIN_10, LOW);  // Reset loop 1 actions
        digitalWrite(PIN_11, LOW);  // Reset loop 1 actions
        digitalWrite(PIN_12, LOW);  // Reset loop 1 actions
        digitalWrite(PIN_13, LOW);  // Reset loop 1 actions
        startTime = millis(); // Reset the start time for the timer
        countdownReset = false; // Ensure we don't proceed in reset mode
      }
    } 
    // If pin 1 is low, enter timer mode (and reset timer if pin 0 is low)
    else if (digitalRead(PIN_1) == LOW) {
      if (inResetMode) {
        inResetMode = false; // Exit reset mode
        startTime = millis(); // Restart timer when moving to timer mode
      }

      if (countdownReset) {
        // If we're in the reset countdown period (30 seconds)
        resetElapsedTime = (currentTime - resetStartTime) / 1000;

        if (resetElapsedTime <= COUNTDOWN_RESET_TIME) {
          // Only update the display every second to avoid odd number issues
          if (currentTime - lastUpdateTime >= 1000) {  // Check if a second has passed
            lastUpdateTime = currentTime;  // Update the time of the last update
            unsigned long remainingTime = COUNTDOWN_RESET_TIME - resetElapsedTime;
            
            // Display remaining time in Seconds (with colon between minutes and seconds)
            display.showNumberDecEx(remainingTime, 0b01000000, true); // Colon will show
          }
        }

        if (resetElapsedTime == COUNTDOWN_RESET_TIME) {
          // Once the 30-second countdown is complete, set Pin 13 to LOW red light off
          digitalWrite(PIN_13, LOW); // Set Pin 13 to low

          // Reset the timer and start the countdown again after the 30 seconds
          startTime = millis();  // Restart the 5-minute countdown
          countdownReset = false; // Exit the reset countdown
        }
      } else {
        // Regular countdown logic
        if (elapsedTime <= COUNTDOWN_TIME) {
          unsigned long remainingTime = COUNTDOWN_TIME - elapsedTime;

          // Display remaining time in Minutes:Seconds format with colon
          unsigned int minutes = remainingTime / 60;
          unsigned int seconds = remainingTime % 60;

          // Display time with colon
          display.showNumberDecEx(minutes * 100 + seconds, 0b01000000, true);

          // Loop 1 logic (Main counter start)
          if (remainingTime == COUNTDOWN_TIME) {
            digitalWrite(PIN_10, HIGH);  // Pin 10 = high
            delay(1500);  // Wait for 1.5 seconds
            digitalWrite(PIN_10, LOW);   // Pin 10 = low
            digitalWrite(PIN_11, HIGH);  // Pin 11 = high green light on
          }

          // At 60 seconds remaining
          if (remainingTime == 60) {
            digitalWrite(PIN_11, LOW);  // Pin 11 = low green light off
            digitalWrite(PIN_12, HIGH); // Pin 12 = high yellow light on
          }

          // End of Loop 1 (Timer reaches 00:00)
          if (remainingTime == 0) {
            // Set Pin 12 to low
            digitalWrite(PIN_12, LOW); // yellow light off

            // Set Pin 13 high at the end of Loop 1
            digitalWrite(PIN_13, HIGH);  // Pin 13 = high red light on

            // hooter twice - Pulse Pin 10 for 1.5 seconds, wait for 1 second, then pulse again
            digitalWrite(PIN_10, HIGH);
            delay(1500);
            digitalWrite(PIN_10, LOW);
            delay(1000);
            digitalWrite(PIN_10, HIGH);
            delay(1500);
            digitalWrite(PIN_10, LOW);

            // Start Loop 2 (30-second countdown)
            resetStartTime = millis();
            countdownReset = true;
          }
        }
      }
    }
  }

  delay(10); // Short delay to allow for proper loop execution
}

  • Congratulations for starting with a program preamble :+1:
    Made some changes, please confirm this is what you intend the program to do ?
// Sketch Notes:
// Surf Competition Timer
// - 2 rotary switches control the timer function (off/Run/Pause) and (timer set 20,25,30,35,40 minutes)
// - when timer starts, hooter sounds for 3 seconds, green light ON and timer counts down (no delays)
// - when timer reaches 5 minute mark - Green light OFF and Amber light ON
// - when timer reaches 0 - amber light OFF, red light ON, hooter sounds (high 3 seconds, low 1 second, high 3 Seconds, Low)
// - when timer reaches 0 a 30 second reset time starts ( time frame between Heats)
//   a 30 second countdown is seen on the TM1637
// - when 30 second reset timer reaches 0, red light OFF, the main timer restarts - hooter, green light etc.
//
// - once timers starts the selected time can not change unless timer is turned Off/Reset.
// - if pause is selected - count down time paused, hooter sounds twice and red light on.
// - if un paused, timer resumes from current state, red light goes OFF, hooter sounds for 3 seconds

Hi LarryD,
yes, this sounds correct. you have done well to decipher my messy comments :slight_smile:
The goal is no delays() during the sequencing.

  • Attached is a preliminary schematic from what you have mentioned so far, plus a few more additions.
  • I do not have your hardware so will need you change your wiring as depicted.
  • Took license to change pin numbers as seen in the schematic below.

* Please confirm your relays operate on 5VDC ?

Wow! what program did you use to draw up the schematic! Thats nice. beats my poor hand sketch of a schematic :frowning:

the VCC on the relay module will be 12VDC. the input pins on the module are driven by the 5VDC.

for reference I am using an Arduino UNO R4 Minima

  • You can use free programs like KICAD and EasyEDA to make schematics.
    I use a program that is no longer is available.
    Drawing a schematic on paper is just fine too.



  • Once you have made the hardware changes seen in the schematic, upload this sketch to the Arduino.

  • Do not try to understand what is happening in the sketch just now.

  • Tell us what you see on the TM1637 ?

  • Also, the schematic shows we have a LED connected to pin 13 on the Arduino.

  • We refer to this LED as a Heartbeat LED; its purpose is to give a us a visual indication that our code is properly execution.

  • The LED should be toggling every 500ms. If the LED does not toggle or toggles erratically, we need to find out why before we continue to make program changes.

//
//================================================^================================================
//                            S u r f   C o m p e t i t i o n   T i m e r
//
//  https://forum.arduino.cc/t/newbie-building-a-surf-comp-timer-does-my-code-look-ok/1358758/1
//
//  Name
//
//  Version    YY/MM/DD    Comments
//  =======    ========    ========================================================================
//  1.00       25/03/01    Running code
//
//
//
//
//  For wiring connections, see the     T i m e r S u r f      S c h e m a t i c
//
//

// Sketch Notes:
// Surf Competition Timer
// - 2 rotary switches control the timer function (off/Run/Pause) and (timer set 20,25,30,35,40 minutes)
// - when timer starts, hooter sounds for 3 seconds, green light ON and timer counts down (no delays)
// - when timer reaches 5 minute mark - Green light OFF and Amber light ON
// - when timer reaches 0 - amber light OFF, red light ON, hooter sounds (high 3 seconds, low 1 second, high 3 Seconds, Low)
// - when timer reaches 0 a 30 second reset time starts ( time frame between Heats)
//   a 30 second countdown is seen on the TM1637
// - when 30 second reset timer reaches 0, red light OFF, the main timer restarts - hooter, green light etc.
//
// - once timers starts the selected time can not change unless timer is turned Off/Reset.
// - if pause is selected - count down time paused, hooter sounds twice and red light on.
// - if un paused, timer resumes from current state, red light goes OFF, hooter sounds for 3 seconds


#include <TM1637Display.h>
//TM1637 Notes:
//reference: https://github.com/avishorp/TM1637/blob/master/TM1637Display.h
// showNumberDecEx(int num, uint8_t dots = 0, bool leading_zero = false, uint8_t length = 4, uint8_t pos = 0);


//================================================
#define colon              0b01000000

#define LEDon              HIGH   //PIN---[220R]---A[LED]K---GND
#define LEDoff             LOW

#define PRESSED            LOW    //+5V---[Internal 50k]---PIN---[Switch]---GND
#define RELEASED           HIGH

#define CLOSED             LOW    //+5V---[Internal 50k]---PIN---[Switch]---GND
#define OPENED             HIGH

#define relayON            HIGH
#define relayOFF           LOW

#define ENABLED            true
#define DISABLED           false

#define MAXIMUM            180
#define MINIMUM            0


//                          millis() / micros()   B a s e d   T I M E R S
//================================================^================================================
//To keep the sketch tidy, you can put this structure in a different tab in the IDE
//
//These TIMER objects are non-blocking
struct makeTIMER
{
#define MILLIS             0
#define MICROS             1

#define ENABLED            true
#define DISABLED           false

#define YES                true
#define NO                 false

#define STILLtiming        0
#define EXPIRED            1
#define TIMERdisabled      2

  //these are the bare minimum "members" needed when defining a TIMER
  byte                     TimerType;      //what kind of TIMER is this? MILLIS/MICROS
  unsigned long            Time;           //when the TIMER started
  unsigned long            Interval;       //delay time which we are looking for
  bool                     TimerFlag;      //is the TIMER enabled ? ENABLED/DISABLED
  bool                     Restart;        //do we restart this TIMER   ? YES/NO

  //================================================
  //condition returned: STILLtiming (0), EXPIRED (1) or TIMERdisabled (2)
  //function to check the state of our TIMER  ex: if(myTimer.checkTIMER() == EXPIRED);
  byte checkTIMER()
  {
    //========================
    //is this TIMER enabled ?
    if (TimerFlag == ENABLED)
    {
      //========================
      //has this TIMER expired ?
      if (getTime() - Time >= Interval)
      {
        //========================
        //should this TIMER restart again?
        if (Restart == YES)
        {
          //restart this TIMER
          Time = getTime();
        }

        //this TIMER has expired
        return EXPIRED;
      }

      //========================
      else
      {
        //this TIMER has not expired
        return STILLtiming;
      }

    } //END of   if (TimerFlag == ENABLED)

    //========================
    else
    {
      //this TIMER is disabled
      return TIMERdisabled;
    }

  } //END of   checkTime()

  //================================================
  //function to enable and restart this TIMER  ex: myTimer.enableRestartTIMER();
  void enableRestartTIMER()
  {
    TimerFlag = ENABLED;

    //restart this TIMER
    Time = getTime();

  } //END of   enableRestartTIMER()

  //================================================
  //function to disable this TIMER  ex: myTimer.disableTIMER();
  void disableTIMER()
  {
    TimerFlag = DISABLED;

  } //END of    disableTIMER()

  //================================================
  //function to restart this TIMER  ex: myTimer.restartTIMER();
  void restartTIMER()
  {
    Time = getTime();

  } //END of    restartTIMER()

  //================================================
  //function to force this TIMER to expire ex: myTimer.expireTimer();
  void expireTimer()
  {
    //force this TIMER to expire
    Time = getTime() - Interval;

  } //END of   expireTimer()

  //================================================
  //function to set the Interval for this TIMER ex: myTimer.setInterval(100);
  void setInterval(unsigned long value)
  {
    //set the Interval
    Interval = value;

  } //END of   setInterval()

  //================================================
  //function to return the current time
  unsigned long getTime()
  {
    //return the time             i.e. millis() or micros()
    //========================
    if (TimerType == MILLIS)
    {
      return millis();
    }

    //========================
    else
    {
      return micros();
    }

  } //END of   getTime()

}; //END of   struct makeTIMER


//                             D e f i n e   a l l   o u r   T I M E R S
//================================================^================================================
/*example
  //========================
  makeTIMER toggleLED =
  {
     MILLIS/MICROS, 0, 500ul, ENABLED/DISABLED, YES/NO  //.TimerType, .Time, .Interval, .TimerFlag, .Restart
  };

  TIMER functions we can access:
  toggleLED.checkTIMER();
  toggleLED.enableRestartTIMER();
  toggleLED.disableTIMER();
  toggleLED.expireTimer();
  toggleLED.setInterval(100ul);
*/

//========================
makeTIMER heartbeatTIMER =
{
  MILLIS, 0, 500ul, ENABLED, YES       //.TimerType, .Time, .Interval, .TimerFlag, .Restart
};

//========================
makeTIMER switchesTIMER =
{
  MILLIS, 0, 50ul, ENABLED, YES        //.TimerType, .Time, .Interval, .TimerFlag, .Restart
};

//========================
makeTIMER machineTIMER =
{
  MICROS, 0, 1000ul, ENABLED, YES      //.TimerType, .Time, .Interval, .TimerFlag, .Restart
};

//========================
makeTIMER countDownTIMER =
{
  MILLIS, 0, 1000ul, DISABLED, YES      //.TimerType, .Time, .Interval, .TimerFlag, .Restart
};

//========================
makeTIMER hooterTIMER =
{
  MILLIS, 0, 1000ul, DISABLED, YES     //.TimerType, .Time, .Interval, .TimerFlag, .Restart
};

//========================
makeTIMER heatTIMER =
{
  MILLIS, 0, 1000ul, DISABLED, YES     //.TimerType, .Time, .Interval, .TimerFlag, .Restart
};


//                                   S t a t e   M a c h i n e s
//================================================^================================================
//

//========================
//states in our countdown machine
enum STATES : byte
{
  POWERUP, RESET, START, RUNNING, RESTARTtiming, HOOTERsequence, WAITING, PAUSED, FINISHED
};
STATES mState = POWERUP;  //mState is machine state

//========================
//states in our hooter sequence machine
enum {sequenceStart = 0, sequence1, sequence2, sequence3, sequence4, sequenceTiming};

byte sequenceState                = 0;
byte lastSequenceState            = 0;


//                              G P I O s   A n d   V a r i a b l e s
//================================================^================================================
//

//GPIOs
//================================================
//
//5 position switch
const byte switch1                = 2;
const byte switch2                = 3;
const byte switch3                = 4;
const byte switch4                = 5;
const byte switch5                = 6;

//TM1637 display module
const byte CLK_PIN                = 7;
const byte DIO_PIN                = 8;

//relays
const byte RedLight               = 9;
const byte AmberLight             = 10;
const byte GreenLight             = 11;
const byte Hooter                 = 12;

const byte heartbeatLED           = 13;

//3 position switch
const byte RESET_PIN              = 14;  //A0
const byte START_PIN              = 15;  //A1
const byte PAUSE_PIN              = 16;  //A2

//create display object
TM1637Display display(CLK_PIN, DIO_PIN);


//VARIABLES
//================================================
//
bool restartFlag                  = DISABLED; //when ENABLED, the next "Heat" will start in 30 seconds

//const byte Time1                = 20 * 60;  //seconds
const unsigned int Time1          = 40;       //40 seconds for testing                                 <---------------<<<<<<
const unsigned int Time2          = 25 * 60;  //seconds
const unsigned int Time3          = 30 * 60;  //seconds
const unsigned int Time4          = 35 * 60;  //seconds
const unsigned int Time5          = 40 * 60;  //seconds

unsigned int  timeSelected;

byte lastSwitch1                  = OPENED;
byte lastSwitch2                  = OPENED;
byte lastSwitch3                  = OPENED;
byte lastSwitch4                  = OPENED;
byte lastSwitch5                  = OPENED;

byte lastRESET_PIN                = OPENED;
byte lastSTART_PIN                = OPENED;
byte lastPAUSE_PIN                = OPENED;

//timing stuff
const unsigned int GreenOffTime   = 5 * 60;    //seconds
const unsigned int nextHeatTime   = 30;        //seconds

const unsigned int hooterOnTime   = 3 * 1000;  //3000 milliseconds

unsigned int heatRestartCounter;
unsigned int heatCounter ;


//                                           s e t u p ( )
//================================================^================================================
//
void setup()
{
  Serial.begin(115200);
  //wait for the serial
  while (!Serial);

  //========================
  //internal pull-ups are turned on
  pinMode(switch1, INPUT_PULLUP);
  pinMode(switch2, INPUT_PULLUP);
  pinMode(switch3, INPUT_PULLUP);
  pinMode(switch4, INPUT_PULLUP);
  pinMode(switch5, INPUT_PULLUP);

  pinMode(RESET_PIN, INPUT_PULLUP);
  pinMode(START_PIN, INPUT_PULLUP);
  pinMode(PAUSE_PIN, INPUT_PULLUP);

  //========================
  //relays are off at power up time
  digitalWrite(RedLight, relayOFF);
  pinMode(RedLight, OUTPUT);

  digitalWrite(AmberLight, relayOFF);
  pinMode(AmberLight, OUTPUT);

  digitalWrite(GreenLight, relayOFF);
  pinMode(GreenLight, OUTPUT);

  digitalWrite(Hooter, relayOFF);
  pinMode(Hooter, OUTPUT);

  digitalWrite(heartbeatLED, LEDoff);
  pinMode(heartbeatLED, OUTPUT);

  //========================
  display.setBrightness(7);         //display brightness (0-7)
  display.clear();
  updateTM1637(0);

} //END of   setup()


//                                            l o o p ( )
//================================================^================================================
//
void loop()
{
  static unsigned int myCounter = 0;

  //========================================================================  T I M E R  heartbeatLED
  //is it time to toggle the heartbeat LED ?
  if (heartbeatTIMER.checkTIMER() == EXPIRED)
  {
    //toggle the heartbeat LED
    digitalWrite(heartbeatLED, digitalRead(heartbeatLED) == HIGH ? LOW : HIGH);

    //next count
    myCounter++;  
    updateTM1637(myCounter);
  }

  //========================================================================  T I M E R  switches
  //is it time to check our switches ?
  if (switchesTIMER.checkTIMER() == EXPIRED)
  {
    checkSwitches();
  }

  //========================================================================  T I M E R  machine
  //is it time to service our State Machine ?
  if (machineTIMER.checkTIMER() == EXPIRED)
  {
    checkMachine();
  }


  //================================================
  //other non blocking code goes here
  //================================================


} //END of   loop()


//                                    c h e c k M a c h i n e ( )
//================================================^================================================
//
void checkMachine()
{

} //END of   checkMachine()


//                                   c h e c k S w i t c h e s ( )
//================================================^================================================
//
void checkSwitches()
{

} //END of   checkSwitches()


//                                    u p d a t e T M 1 6 3 7 ( )
//================================================^================================================
//
void updateTM1637(unsigned int counter)
{
  unsigned int minutes = counter / 60;
  unsigned int seconds = counter % 60;
  unsigned int num = minutes * 100 + seconds;

  //update TM1637
  //                      num,  dots, leading 0s, digits, LSD position
  display.showNumberDecEx(num, colon,       true,      4,    0);

} //END of   updateTM1637()


//================================================^================================================

thanks LarryD,
I will try it tonight, I'm at work at the moment sorry.
I will need to call into the electronics store and get the LED D1 and 220 Ohm resistor to update my circuit also.
(I know the onboard LED will operate as the heartbeat)

I wasn't aware i could use the A0-A3 pins for digital inputs either.

again i can't thankyou enough for your help and support.

kind regards Pridelec

  • Using a 12 Volt relay module needs to be addressed.

  • Seeing good closeup, clear images of the relay module, top and bottom, would be beneficial for us to see ?

  • Have you had success in getting the relays to operating in the past ?

  • I use the Arduino UNO, same pinout.

  • Just use the onboard LED as the Heartbeat LED.

  • New schematic attached below.


EDIT

Updated the Schematic

BTW

  • Pins 0 and 1 are avoided as we use Serial.print( ) to aid in sketch debugging.

Thanks for the update.
yes while bench testing the code i pasted i was using 12VDC and the relays were operating.

i will get an image of the board / relays for you.

i am in Australia (sydney time zone)

Ok i will use the onboard for testing tonight.

  • What is the actual Hooter voltage and current requirements ?
  • What is the actual Light voltage and current requirements ?



  • Upload the attached sketch, what happens on the relay module ?
//
//================================================^================================================
//                            S u r f   C o m p e t i t i o n   T i m e r
//
//  https://forum.arduino.cc/t/newbie-building-a-surf-comp-timer-does-my-code-look-ok/1358758/1
//
//  Name
//
//  Version    YY/MM/DD    Comments
//  =======    ========    ========================================================================
//  1.00       25/03/01    Running code
//
//
//
//
//  For wiring connections, see the     T i m e r S u r f      S c h e m a t i c
//
//

// Sketch Notes:
// Surf Competition Timer
// - 2 rotary switches control the timer function (off/Run/Pause) and (timer set 20,25,30,35,40 minutes)
// - when timer starts, hooter sounds for 3 seconds, green light ON and timer counts down (no delays)
// - when timer reaches 5 minute mark - Green light OFF and Amber light ON
// - when timer reaches 0 - amber light OFF, red light ON, hooter sounds (high 3 seconds, low 1 second, high 3 Seconds, Low)
// - when timer reaches 0 a 30 second reset time starts ( time frame between Heats)
//   a 30 second countdown is seen on the TM1637
// - when 30 second reset timer reaches 0, red light OFF, the main timer restarts - hooter, green light etc.
//
// - once timers starts the selected time can not change unless timer is turned Off/Reset.
// - if pause is selected - count down time paused, hooter sounds twice and red light on.
// - if un paused, timer resumes from current state, red light goes OFF, hooter sounds for 3 seconds


#include <TM1637Display.h>
//TM1637 Notes:
//reference: https://github.com/avishorp/TM1637/blob/master/TM1637Display.h
// showNumberDecEx(int num, uint8_t dots = 0, bool leading_zero = false, uint8_t length = 4, uint8_t pos = 0);


//================================================
#define colon              0b01000000

#define LEDon              HIGH   //PIN---[220R]---A[LED]K---GND
#define LEDoff             LOW

#define PRESSED            LOW    //+5V---[Internal 50k]---PIN---[Switch]---GND
#define RELEASED           HIGH

#define CLOSED             LOW    //+5V---[Internal 50k]---PIN---[Switch]---GND
#define OPENED             HIGH

#define relayON            HIGH
#define relayOFF           LOW

#define ENABLED            true
#define DISABLED           false

#define MAXIMUM            180
#define MINIMUM            0


//                          millis() / micros()   B a s e d   T I M E R S
//================================================^================================================
//To keep the sketch tidy, you can put this structure in a different tab in the IDE
//
//These TIMER objects are non-blocking
struct makeTIMER
{
#define MILLIS             0
#define MICROS             1

#define ENABLED            true
#define DISABLED           false

#define YES                true
#define NO                 false

#define STILLtiming        0
#define EXPIRED            1
#define TIMERdisabled      2

  //these are the bare minimum "members" needed when defining a TIMER
  byte                     TimerType;      //what kind of TIMER is this? MILLIS/MICROS
  unsigned long            Time;           //when the TIMER started
  unsigned long            Interval;       //delay time which we are looking for
  bool                     TimerFlag;      //is the TIMER enabled ? ENABLED/DISABLED
  bool                     Restart;        //do we restart this TIMER   ? YES/NO

  //================================================
  //condition returned: STILLtiming (0), EXPIRED (1) or TIMERdisabled (2)
  //function to check the state of our TIMER  ex: if(myTimer.checkTIMER() == EXPIRED);
  byte checkTIMER()
  {
    //========================
    //is this TIMER enabled ?
    if (TimerFlag == ENABLED)
    {
      //========================
      //has this TIMER expired ?
      if (getTime() - Time >= Interval)
      {
        //========================
        //should this TIMER restart again?
        if (Restart == YES)
        {
          //restart this TIMER
          Time = getTime();
        }

        //this TIMER has expired
        return EXPIRED;
      }

      //========================
      else
      {
        //this TIMER has not expired
        return STILLtiming;
      }

    } //END of   if (TimerFlag == ENABLED)

    //========================
    else
    {
      //this TIMER is disabled
      return TIMERdisabled;
    }

  } //END of   checkTime()

  //================================================
  //function to enable and restart this TIMER  ex: myTimer.enableRestartTIMER();
  void enableRestartTIMER()
  {
    TimerFlag = ENABLED;

    //restart this TIMER
    Time = getTime();

  } //END of   enableRestartTIMER()

  //================================================
  //function to disable this TIMER  ex: myTimer.disableTIMER();
  void disableTIMER()
  {
    TimerFlag = DISABLED;

  } //END of    disableTIMER()

  //================================================
  //function to restart this TIMER  ex: myTimer.restartTIMER();
  void restartTIMER()
  {
    Time = getTime();

  } //END of    restartTIMER()

  //================================================
  //function to force this TIMER to expire ex: myTimer.expireTimer();
  void expireTimer()
  {
    //force this TIMER to expire
    Time = getTime() - Interval;

  } //END of   expireTimer()

  //================================================
  //function to set the Interval for this TIMER ex: myTimer.setInterval(100);
  void setInterval(unsigned long value)
  {
    //set the Interval
    Interval = value;

  } //END of   setInterval()

  //================================================
  //function to return the current time
  unsigned long getTime()
  {
    //return the time             i.e. millis() or micros()
    //========================
    if (TimerType == MILLIS)
    {
      return millis();
    }

    //========================
    else
    {
      return micros();
    }

  } //END of   getTime()

}; //END of   struct makeTIMER


//                             D e f i n e   a l l   o u r   T I M E R S
//================================================^================================================
/*example
  //========================
  makeTIMER toggleLED =
  {
     MILLIS/MICROS, 0, 500ul, ENABLED/DISABLED, YES/NO  //.TimerType, .Time, .Interval, .TimerFlag, .Restart
  };

  TIMER functions we can access:
  toggleLED.checkTIMER();
  toggleLED.enableRestartTIMER();
  toggleLED.disableTIMER();
  toggleLED.expireTimer();
  toggleLED.setInterval(100ul);
*/

//========================
makeTIMER heartbeatTIMER =
{
  MILLIS, 0, 500ul, ENABLED, YES       //.TimerType, .Time, .Interval, .TimerFlag, .Restart
};

//========================
makeTIMER switchesTIMER =
{
  MILLIS, 0, 50ul, ENABLED, YES        //.TimerType, .Time, .Interval, .TimerFlag, .Restart
};

//========================
makeTIMER machineTIMER =
{
  MICROS, 0, 1000ul, ENABLED, YES      //.TimerType, .Time, .Interval, .TimerFlag, .Restart
};

//========================
makeTIMER countDownTIMER =
{
  MILLIS, 0, 1000ul, DISABLED, YES      //.TimerType, .Time, .Interval, .TimerFlag, .Restart
};

//========================
makeTIMER hooterTIMER =
{
  MILLIS, 0, 1000ul, DISABLED, YES     //.TimerType, .Time, .Interval, .TimerFlag, .Restart
};

//========================
makeTIMER heatTIMER =
{
  MILLIS, 0, 1000ul, DISABLED, YES     //.TimerType, .Time, .Interval, .TimerFlag, .Restart
};


//                                   S t a t e   M a c h i n e s
//================================================^================================================
//

//========================
//states in our countdown machine
enum STATES : byte
{
  POWERUP, RESET, START, RUNNING, RESTARTtiming, HOOTERsequence, WAITING, PAUSED, FINISHED
};
STATES mState = POWERUP;  //mState is machine state

//========================
//states in our hooter sequence machine
enum {sequenceStart = 0, sequence1, sequence2, sequence3, sequence4, sequenceTiming};

byte sequenceState                = 0;
byte lastSequenceState            = 0;


//                              G P I O s   A n d   V a r i a b l e s
//================================================^================================================
//

//GPIOs
//================================================
//
//5 position switch
const byte switch1                = 2;
const byte switch2                = 3;
const byte switch3                = 4;
const byte switch4                = 5;
const byte switch5                = 6;

//TM1637 display module
const byte CLK_PIN                = 7;
const byte DIO_PIN                = 8;

//relays
const byte RedLight               = 9;
const byte AmberLight             = 10;
const byte GreenLight             = 11;
const byte Hooter                 = 12;

const byte heartbeatLED           = 13;

//3 position switch
const byte RESET_PIN              = 14;  //A0
const byte START_PIN              = 15;  //A1
const byte PAUSE_PIN              = 16;  //A2

//create display object
TM1637Display display(CLK_PIN, DIO_PIN);


//VARIABLES
//================================================
//
bool restartFlag                  = DISABLED; //when ENABLED, the next "Heat" will start in 30 seconds

//const byte Time1                = 20 * 60;  //seconds
const unsigned int Time1          = 40;       //40 seconds for testing                                 <---------------<<<<<<
const unsigned int Time2          = 25 * 60;  //seconds
const unsigned int Time3          = 30 * 60;  //seconds
const unsigned int Time4          = 35 * 60;  //seconds
const unsigned int Time5          = 40 * 60;  //seconds

unsigned int  timeSelected;

byte lastSwitch1                  = OPENED;
byte lastSwitch2                  = OPENED;
byte lastSwitch3                  = OPENED;
byte lastSwitch4                  = OPENED;
byte lastSwitch5                  = OPENED;

byte lastRESET_PIN                = OPENED;
byte lastSTART_PIN                = OPENED;
byte lastPAUSE_PIN                = OPENED;

//timing stuff
const unsigned int GreenOffTime   = 5 * 60;    //seconds
const unsigned int nextHeatTime   = 30;        //seconds

const unsigned int hooterOnTime   = 3 * 1000;  //3000 milliseconds

unsigned int heatRestartCounter;
unsigned int heatCounter ;


//                                           s e t u p ( )
//================================================^================================================
//
void setup()
{
  Serial.begin(115200);
  //wait for the serial
  while (!Serial);

  //========================
  //internal pull-ups are turned on
  pinMode(switch1, INPUT_PULLUP);
  pinMode(switch2, INPUT_PULLUP);
  pinMode(switch3, INPUT_PULLUP);
  pinMode(switch4, INPUT_PULLUP);
  pinMode(switch5, INPUT_PULLUP);

  pinMode(RESET_PIN, INPUT_PULLUP);
  pinMode(START_PIN, INPUT_PULLUP);
  pinMode(PAUSE_PIN, INPUT_PULLUP);

  //========================
  //relays are off at power up time
  digitalWrite(RedLight, relayOFF);
  pinMode(RedLight, OUTPUT);

  digitalWrite(AmberLight, relayOFF);
  pinMode(AmberLight, OUTPUT);

  digitalWrite(GreenLight, relayOFF);
  pinMode(GreenLight, OUTPUT);

  digitalWrite(Hooter, relayOFF);
  pinMode(Hooter, OUTPUT);

  digitalWrite(heartbeatLED, LEDoff);
  pinMode(heartbeatLED, OUTPUT);

  //========================
  display.setBrightness(7);         //display brightness (0-7)
  display.clear();
  updateTM1637(0);

} //END of   setup()


//                                            l o o p ( )
//================================================^================================================
//
void loop()
{
  static unsigned int myCounter = 0;
  static unsigned int relayCounter = 0;
  static byte selectedRelay = 9;

  //========================================================================  T I M E R  heartbeatLED
  //is it time to toggle the heartbeat LED ?
  if (heartbeatTIMER.checkTIMER() == EXPIRED)
  {
    //toggle the heartbeat LED
    digitalWrite(heartbeatLED, digitalRead(heartbeatLED) == HIGH ? LOW : HIGH);

    //next count
    myCounter++;  
    updateTM1637(myCounter);

    //next relay, toggle the relay
    digitalWrite(selectedRelay, !digitalRead(selectedRelay));
    selectedRelay++;
    
    //are we finished with the last relay ?
    if(selectedRelay >= 13)
    {
      selectedRelay = 9;
    }
    
  }

  //========================================================================  T I M E R  switches
  //is it time to check our switches ?
  if (switchesTIMER.checkTIMER() == EXPIRED)
  {
    checkSwitches();
  }

  //========================================================================  T I M E R  machine
  //is it time to service our State Machine ?
  if (machineTIMER.checkTIMER() == EXPIRED)
  {
    checkMachine();
  }


  //================================================
  //other non blocking code goes here
  //================================================


} //END of   loop()


//                                    c h e c k M a c h i n e ( )
//================================================^================================================
//
void checkMachine()
{

} //END of   checkMachine()


//                                   c h e c k S w i t c h e s ( )
//================================================^================================================
//
void checkSwitches()
{

} //END of   checkSwitches()


//                                    u p d a t e T M 1 6 3 7 ( )
//================================================^================================================
//
void updateTM1637(unsigned int counter)
{
  unsigned int minutes = counter / 60;
  unsigned int seconds = counter % 60;
  unsigned int num = minutes * 100 + seconds;

  //update TM1637
  //                      num,  dots, leading 0s, digits, LSD position
  display.showNumberDecEx(num, colon,       true,      4,    0);

} //END of   updateTM1637()


//================================================^================================================