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
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.