3in1 carwash vendo machine

hello everyone I just want to ask for help with my project which is a 3 in 1 carwash vending machine. I am using an Arduino Uno, I2C 20x4, 3 buttons, and 3 relays for Water, Soap, and Blower, along with a coin slot. My problem with the code is that it shows a credit balance: when I press the buttons, it doesn't give time to each relay. I've been troubleshooting this for almost 4 weeks and it still doesn't work. I'm just a beginner in coding, and I hope someone can help me for my personal use. below is the code i am using.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// LCD setup
LiquidCrystal_I2C lcd(0x27, 20, 4);

// Pin assignments
const int coinSlotPin = 2; // Pin for the coin slot sensor
const int waterButton = 3;
const int soapButton = 4;
const int blowerButton = 5;
const int relayWater = 6;
const int relaySoap = 7;
const int relayBlower = 8;
const int buzzer = 9;  // Buzzer pin

// Default times
const int DEFAULT_WATER_TIME = 60; 
const int DEFAULT_SOAP_TIME = 45;
const int DEFAULT_BLOWER_TIME = 75;

// Pause limit
const int MAX_PAUSE_COUNT = 3;  

// Timing constants
const unsigned long BLINK_INTERVAL = 450;  // Blink interval in milliseconds
const unsigned long BUZZER_CHECK_INTERVAL = 1000;  // Buzzer check interval in milliseconds
const unsigned long COIN_DEBOUNCE_TIME = 300;  // Coin slot debounce time in milliseconds

// Buzzer intervals (in seconds)
const int BUZZER_INTERVALS[] = {10, 6, 2};
const int BUZZER_INTERVAL_COUNT = sizeof(BUZZER_INTERVALS) / sizeof(BUZZER_INTERVALS[0]);

// System state
int balance = 0;
int waterTime = 0, soapTime = 0, blowerTime = 0;
bool waterActive = false, soapActive = false, blowerActive = false;
bool waterPaused = false, soapPaused = false, blowerPaused = false;
int waterPauseCount = 0, soapPauseCount = 0, blowerPauseCount = 0;

unsigned long lastCoinTime = 0, lastUpdateTime = 0, lastButtonBlinkTime = 0;
unsigned long lastBuzzerTime = 0, lastInsertCoinBlinkTime = 0;  // Separate variable for --Insert Coin!-- blinking
bool showInsertCoin = true, showPressButton = true;
bool screenInitialized = false;

// Separate blinking states for paused timers
bool waterBlinkState = false, soapBlinkState = false, blowerBlinkState = false;
unsigned long waterLastBlinkTime = 0, soapLastBlinkTime = 0, blowerLastBlinkTime = 0;

// Coin counting variables
volatile int coinsInserted = 0; // Volatile because it's modified in an interrupt
const int COIN_VALUE = 1; // Value of each coin in pesos

// Display update flags
bool balanceChanged = true; // Flag to track balance changes
bool timeChanged = true;    // Flag to track timer changes

// Button debouncing variables
unsigned long lastDebounceTimeWater = 0; // Separate debounce timestamps for each button
unsigned long lastDebounceTimeSoap = 0;
unsigned long lastDebounceTimeBlower = 0;
const unsigned long DEBOUNCE_DELAY = 50; // Debounce delay in milliseconds

// Last button states for debouncing
int lastWaterButtonState = HIGH;
int lastSoapButtonState = HIGH;
int lastBlowerButtonState = HIGH;

void setup() {
    // Initialize pins
    pinMode(coinSlotPin, INPUT_PULLUP);
    pinMode(waterButton, INPUT_PULLUP);
    pinMode(soapButton, INPUT_PULLUP);
    pinMode(blowerButton, INPUT_PULLUP);
    pinMode(relayWater, OUTPUT);
    pinMode(relaySoap, OUTPUT);
    pinMode(relayBlower, OUTPUT);
    pinMode(buzzer, OUTPUT);  

    // Initialize relays to OFF state (HIGH for low-trigger relays)
    digitalWrite(relayWater, HIGH);
    digitalWrite(relaySoap, HIGH);
    digitalWrite(relayBlower, HIGH);

    // Initialize LCD
    lcd.init();
    lcd.backlight();
    displayInitialScreen();

    // Attach interrupt for coin slot
    attachInterrupt(digitalPinToInterrupt(coinSlotPin), Add, FALLING);
}

void loop() {
    unsigned long currentMillis = millis();

    // Handle initial screen and blinking "Insert Coin" message
    if (balance == 0 && waterTime == 0 && soapTime == 0 && blowerTime == 0) {
        if (!screenInitialized) {
            displayInitialScreen();
            screenInitialized = true;
        }
        // Independent blinking for --Insert Coin!--
        if (currentMillis - lastInsertCoinBlinkTime > BLINK_INTERVAL) {
            lastInsertCoinBlinkTime = currentMillis;
            showInsertCoin = !showInsertCoin;
            blinkInsertCoin();
        }
    } else {
        screenInitialized = false;
    }

    // Handle coin insertion
    if (coinsInserted > 0) {
        balance += coinsInserted * COIN_VALUE; // Add the value of inserted coins to the balance
        coinsInserted = 0; // Reset the coin counter
        balanceChanged = true; // Set flag to update balance display
        displayActiveScreen(); // Update the display
    }

    // Check buzzer timing
    checkBuzzerTiming();

    // Update timers every second
    if (currentMillis - lastUpdateTime >= 1000) {
        lastUpdateTime = currentMillis;
        updateTime();
    }

    // Handle button presses and blinking "Press a Button" message
    if (balance >= 5 || waterTime > 0 || soapTime > 0 || blowerTime > 0) {
        if (currentMillis - lastButtonBlinkTime > BLINK_INTERVAL) {
            lastButtonBlinkTime = currentMillis;
            showPressButton = !showPressButton;
            blinkPressButton();
        }

        // Call handleButton with separate debounce timestamps and last button states
        handleButton(waterButton, relayWater, waterTime, waterActive, waterPaused, waterPauseCount, DEFAULT_WATER_TIME, lastDebounceTimeWater, lastWaterButtonState);
        handleButton(soapButton, relaySoap, soapTime, soapActive, soapPaused, soapPauseCount, DEFAULT_SOAP_TIME, lastDebounceTimeSoap, lastSoapButtonState);
        handleButton(blowerButton, relayBlower, blowerTime, blowerActive, blowerPaused, blowerPauseCount, DEFAULT_BLOWER_TIME, lastDebounceTimeBlower, lastBlowerButtonState);
    }

    // Handle blinking for paused timers
    handlePausedBlinking();

    // Ensure --Insert Coin!-- is displayed when balance is 0
    if (balance == 0) {
        if (currentMillis - lastInsertCoinBlinkTime > BLINK_INTERVAL) {
            lastInsertCoinBlinkTime = currentMillis;
            showInsertCoin = !showInsertCoin;
            blinkInsertCoin();
        }
    }
}

// Interrupt Service Routine (ISR) for coin insertion
void Add() {
    coinsInserted++; // Increment the coin counter
}

// Check and sound buzzer at specific intervals
void checkBuzzerTiming() {
    unsigned long currentMillis = millis();
    if (currentMillis - lastBuzzerTime >= BUZZER_CHECK_INTERVAL) {
        lastBuzzerTime = currentMillis;
        if (waterActive && !waterPaused) checkAndSoundBuzzer(waterTime);
        if (soapActive && !soapPaused) checkAndSoundBuzzer(soapTime);
        if (blowerActive && !blowerPaused) checkAndSoundBuzzer(blowerTime);
    }
}

void checkAndSoundBuzzer(int timeLeft) {
    static int lastBuzzerInterval = -1; // Keep track of the last interval the buzzer was sounded

    for (int i = 0; i < BUZZER_INTERVAL_COUNT; i++) {
        if (timeLeft == BUZZER_INTERVALS[i] && timeLeft != lastBuzzerInterval) {
            soundBuzzer();
            lastBuzzerInterval = timeLeft; // Update the last buzzer interval
            break; // Exit after sounding the buzzer
        }
    }

    // Reset the last buzzer interval if the timeLeft is not in the intervals
    if (timeLeft != BUZZER_INTERVALS[0] && timeLeft != BUZZER_INTERVALS[1] && timeLeft != BUZZER_INTERVALS[2]) {
        lastBuzzerInterval = -1;
    }
}

void soundBuzzer() {
    tone(buzzer, 2000, 500);  // 2000 Hz for 500ms
}

void updateTime() {
    bool displayNeedsUpdate = false;

    if (waterActive && !waterPaused && waterTime > 0) {
        waterTime--;
        displayNeedsUpdate = true;
    }
    if (soapActive && !soapPaused && soapTime > 0) {
        soapTime--;
        displayNeedsUpdate = true;
    }
    if (blowerActive && !blowerPaused && blowerTime > 0) {
        blowerTime--;
        displayNeedsUpdate = true;
    }

    if (waterTime == 0 && waterActive) {
        waterActive = false;
        digitalWrite(relayWater, HIGH);
    }
    if (soapTime == 0 && soapActive) {
        soapActive = false;
        digitalWrite(relaySoap, HIGH);
    }
    if (blowerTime == 0 && blowerActive) {
        blowerActive = false;
        digitalWrite(relayBlower, HIGH);
    }

    if (balance == 0 && waterTime == 0 && soapTime == 0 && blowerTime == 0) {
        displayInitialScreen();
    } else if (displayNeedsUpdate) {
        timeChanged = true; // Set flag to update time display
        updateTimeDisplay();
    }
}

void handleButton(int button, int relay, int &time, bool &active, bool &paused, int &pauseCount, int defaultTime, unsigned long &lastDebounceTime, int &lastButtonState) {
    int buttonState = digitalRead(button); // Read the current button state
    unsigned long currentMillis = millis();

    // Check if the button state has changed (due to noise or pressing)
    if (buttonState != lastButtonState) {
        lastDebounceTime = currentMillis; // Reset the debounce timer
    }

    // If the button state has been stable for longer than the debounce delay, consider it a valid press
    if ((currentMillis - lastDebounceTime) > DEBOUNCE_DELAY) {
        // If the button state has changed, handle the press
        if (buttonState == LOW && lastButtonState == HIGH) {
            // Button is pressed and debounced
            if (!active && balance >= 5) {
                // Activate the function if not already active
                balance -= 5;
                time += defaultTime;
                active = true;
                paused = false;
                pauseCount = 0;
                digitalWrite(relay, LOW); // Turn on the relay
                balanceChanged = true; // Set flag to update balance display
                timeChanged = true;    // Set flag to update time display
                Serial.println("Button pressed - Relay activated"); // Debugging
            } else if (active) {
                // Handle pausing/resuming
                if (!paused && pauseCount < MAX_PAUSE_COUNT) {
                    paused = true;
                    pauseCount++;
                    digitalWrite(relay, HIGH); // Turn off the relay (pause)
                    Serial.println("Paused"); // Debugging
                } else if (paused) {
                    paused = false;
                    digitalWrite(relay, LOW); // Turn on the relay (resume)
                    Serial.println("Resumed"); // Debugging
                }
                timeChanged = true; // Set flag to update time display
            }
        }
    }

    // Save the current button state for the next loop iteration
    lastButtonState = buttonState;
}

void displayInitialScreen() {
    lcd.setCursor(3, 0);
    lcd.print(" 3in1 CARWASH");
    lcd.setCursor(0, 2);
    lcd.print("WATER  SOAP   BLOWER");
    lcd.setCursor(0, 3);
    lcd.print("00:00  00:00  00:00");
    lcd.setCursor(0, 1);
    lcd.print("  --Insert Coin!--");
}

void blinkInsertCoin() {
    lcd.setCursor(0, 1);
    if (showInsertCoin) {
        lcd.print("  --Insert Coin!--  ");
    } else {
        lcd.print("                  ");
    }
}

void displayActiveScreen() {
    lcd.setCursor(3, 0);
    if (balance > 0) {
        lcd.print("PRESS A BUTTON");
    } else {
        lcd.print(" 3in1 CARWASH ");
    }
    lcd.setCursor(2, 1);
    if (balance > 0) {
        lcd.print("   Balance: ");
        lcd.print(balance);
    } else {
        lcd.print("--Insert Coin!--");
    }
    lcd.setCursor(0, 2);
    lcd.print("WATER  SOAP   BLOWER");
    updateTimeDisplay();
    blinkPressButton();
}

void blinkPressButton() {
    lcd.setCursor(3, 0);
    if (balance > 0) {
        lcd.print(showPressButton ? "PRESS A BUTTON" : "                ");
    } else {
        lcd.print(" 3in1 CARWASH ");
    }
}

void updateTimeDisplay() {
    if (balanceChanged) {
        lcd.setCursor(2, 1);
        lcd.print("                "); // Clear the entire line
        lcd.setCursor(2, 1); // Reset cursor position
        if (balance > 0) {
            lcd.print("   Balance: ");
            lcd.print(balance);
        } else {
            lcd.print("--Insert Coin!--");
        }
        balanceChanged = false;
    }

    if (timeChanged) {
        lcd.setCursor(0, 3);
        displayTime(waterTime, waterPaused, 0, waterBlinkState, waterLastBlinkTime);
        lcd.setCursor(7, 3);  
        displayTime(soapTime, soapPaused, 7, soapBlinkState, soapLastBlinkTime);
        lcd.setCursor(14, 3); 
        displayTime(blowerTime, blowerPaused, 14, blowerBlinkState, blowerLastBlinkTime);
        timeChanged = false;
    }
}

void displayTime(int seconds, bool paused, int column, bool &blinkState, unsigned long &lastBlinkTime) {
    if (paused) { // Only apply blinking logic if the timer is paused
        if (millis() - lastBlinkTime > BLINK_INTERVAL) {
            lastBlinkTime = millis();
            blinkState = !blinkState;
        }
        if (blinkState) {
            lcd.setCursor(column, 3);
            lcd.print("     ");
        } else {
            lcd.setCursor(column, 3);
            lcd.print(formatTime(seconds));
        }
    } else { // If not paused, display the time normally
        lcd.setCursor(column, 3);
        lcd.print(formatTime(seconds));
    }
}

String formatTime(int seconds) {
    int mins = seconds / 60;
    int secs = seconds % 60;
    char buf[6];
    sprintf(buf, "%02d:%02d", mins, secs);
    return String(buf);
}

void handlePausedBlinking() {
    if (waterPaused) {
        if (millis() - waterLastBlinkTime > BLINK_INTERVAL) {
            waterLastBlinkTime = millis();
            waterBlinkState = !waterBlinkState;
            lcd.setCursor(0, 3);
            displayTime(waterTime, waterPaused, 0, waterBlinkState, waterLastBlinkTime);
        }
    }
    if (soapPaused) {
        if (millis() - soapLastBlinkTime > BLINK_INTERVAL) {
            soapLastBlinkTime = millis();
            soapBlinkState = !soapBlinkState;
            lcd.setCursor(7, 3);
            displayTime(soapTime, soapPaused, 7, soapBlinkState, soapLastBlinkTime);
        }
    }
    if (blowerPaused) {
        if (millis() - blowerLastBlinkTime > BLINK_INTERVAL) {
            blowerLastBlinkTime = millis();
            blowerBlinkState = !blowerBlinkState;
            lcd.setCursor(14, 3);
            displayTime(blowerTime, blowerPaused, 14, blowerBlinkState, blowerLastBlinkTime);
        }
    }
}

Hello nicole0229

Welcome to the best Arduino forum ever :slight_smile:

My tip from practical experience:

Build your own logic analyser using Serial.println("what I want to know") at program locations that interest you.

Who wrote the programme?

2 Likes

i am getting guide from AI on what to do for reference only

I have taken a high-level flight about your code and read your description.

Can we say this is a controller that accepts money, and if there is sufficient funds allows an operator to turn on and off soap, water and blowing?

What is the difference between soap, for example, being on but paused and off?

Your workhouse function handleButton() has an uncountable number of parameters, this is certainly an area where a better design would be, um, better.

Since the three things being purchased and dispensed are very similar, I woukd suggest you to look into structured variables, the keyword in C/C++ is struct.

Structured variables are a way to package up all the little things that are associated with one product, or in computer terms, one object.

An array of three of those identical structures might be useful; in this way talking about any of them would only need to be done by number. Numbers can be given symbolic names, and you code would become something more people might be willing to help with.

As it is, the task of finding the one flaw you are talking about having battled with for weeks is a huge one, and too much to expect from casual or even not-so-casual helpers.

This can best be expressed by saying you need to learn more about some better language features and try again.

I am in agreement with @paulpaulson - you make little use of the easiest debugging tool, serial printing. Make your code talk verbosely, telling you where it is and by printing also the values of key variables, why.

I saw this hours ago and thought I'd take another run at it later. It's later now but too early to tell if I am alone in my assessment.

Since you are using AI, you might feed this hole mess to it and kindly request that it try to show you how handleButton could be done differently if all its parameters were members one structured variable. Just for fun.

But in the abstract, this is a simple sketch.

Another thing that might help is if you put aside for now your plan to use an LCD. Just now it makes things harder to read, modify or fix. Once you have the essential logic talking good sense over the serial monitor, go back and imllement the fancy display.

I could and do say the same thing about messing with relays. Until you can make LEDs or print statements perform the equivalent actions, leave the hardware off to the side.

It's all about dividing for the purpose on conquering.

a7

1 Like

Warning: this was written by chatPGT, prompted

I will paste an Arduino sketch that is meant to control a car wash, selling water, soap and some kind of fan ("blower"). Please rewrite it using an array of structs. The struct should have at least all the parameters that are currently scalar and appear in the function "handleButton".

I have not yet read it, I'm saving that as a reward for doing some house cleaning and I must at least start working on my taxes first:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// LCD setup
LiquidCrystal_I2C lcd(0x27, 20, 4);

// Pin assignments
const int coinSlotPin = 2; // Pin for the coin slot sensor
const int buzzer = 9;  // Buzzer pin

// Timing constants
const unsigned long BLINK_INTERVAL = 450;  // Blink interval in milliseconds
const unsigned long BUZZER_CHECK_INTERVAL = 1000;  // Buzzer check interval in milliseconds
const unsigned long COIN_DEBOUNCE_TIME = 300;  // Coin slot debounce time in milliseconds
const unsigned long DEBOUNCE_DELAY = 50; // Debounce delay in milliseconds

// Coin counting variables
volatile int coinsInserted = 0; // Volatile because it's modified in an interrupt
const int COIN_VALUE = 1; // Value of each coin in pesos

// Default times
const int DEFAULT_WATER_TIME = 60; 
const int DEFAULT_SOAP_TIME = 45;
const int DEFAULT_BLOWER_TIME = 75;

// System state
int balance = 0;
bool balanceChanged = true; // Flag to track balance changes
bool timeChanged = true;    // Flag to track timer changes
bool screenInitialized = false;

// CarWashOption struct to encapsulate the individual parts (water, soap, blower)
struct CarWashOption {
    int buttonPin;
    int relayPin;
    int time;
    bool active;
    bool paused;
    int pauseCount;
    int defaultTime;
    unsigned long lastDebounceTime;
    int lastButtonState;
    bool blinkState;
    unsigned long lastBlinkTime;
};

// Create an array of CarWashOption structs
CarWashOption options[] = {
    {3, 6, 0, false, false, 0, DEFAULT_WATER_TIME, 0, HIGH, false, 0}, // Water
    {4, 7, 0, false, false, 0, DEFAULT_SOAP_TIME, 0, HIGH, false, 0},  // Soap
    {5, 8, 0, false, false, 0, DEFAULT_BLOWER_TIME, 0, HIGH, false, 0}  // Blower
};

const int NUM_OPTIONS = sizeof(options) / sizeof(options[0]);

void setup() {
    // Initialize pins
    pinMode(coinSlotPin, INPUT_PULLUP);
    pinMode(buzzer, OUTPUT);  

    // Initialize relays to OFF state (HIGH for low-trigger relays)
    for (int i = 0; i < NUM_OPTIONS; i++) {
        pinMode(options[i].relayPin, OUTPUT);
        digitalWrite(options[i].relayPin, HIGH); // Set all relays off initially
    }

    // Initialize LCD
    lcd.init();
    lcd.backlight();
    displayInitialScreen();

    // Attach interrupt for coin slot
    attachInterrupt(digitalPinToInterrupt(coinSlotPin), Add, FALLING);
}

void loop() {
    unsigned long currentMillis = millis();

    // Handle initial screen and blinking "Insert Coin" message
    if (balance == 0 && allTimersZero()) {
        if (!screenInitialized) {
            displayInitialScreen();
            screenInitialized = true;
        }
        blinkInsertCoinMessage(currentMillis);
    } else {
        screenInitialized = false;
    }

    // Handle coin insertion
    if (coinsInserted > 0) {
        balance += coinsInserted * COIN_VALUE; // Add the value of inserted coins to the balance
        coinsInserted = 0; // Reset the coin counter
        balanceChanged = true; // Set flag to update balance display
        displayActiveScreen(); // Update the display
    }

    // Handle buzzer timing
    checkBuzzerTiming();

    // Update timers every second
    if (currentMillis - options[0].lastDebounceTime >= 1000) {
        updateTime();
    }

    // Handle button presses and blinking "Press a Button" message
    if (balance >= 5 || anyTimerActive()) {
        handleButtonPresses(currentMillis);
    }

    // Handle blinking for paused timers
    handlePausedBlinking(currentMillis);

    // Ensure --Insert Coin!-- is displayed when balance is 0
    if (balance == 0) {
        blinkInsertCoinMessage(currentMillis);
    }
}

// Interrupt Service Routine (ISR) for coin insertion
void Add() {
    coinsInserted++; // Increment the coin counter
}

// Handle button presses for all options
void handleButtonPresses(unsigned long currentMillis) {
    if (currentMillis - options[0].lastBlinkTime > BLINK_INTERVAL) {
        options[0].lastBlinkTime = currentMillis;
        for (int i = 0; i < NUM_OPTIONS; i++) {
            handleButton(options[i]);
        }
    }
}

// Handle button logic for a single option
void handleButton(CarWashOption &option) {
    int buttonState = digitalRead(option.buttonPin); // Read the current button state

    // Debounce handling
    if (buttonState != option.lastButtonState) {
        option.lastDebounceTime = millis(); // Reset the debounce timer
    }

    if (millis() - option.lastDebounceTime > DEBOUNCE_DELAY) {
        if (buttonState == LOW && option.lastButtonState == HIGH) {
            if (!option.active && balance >= 5) {
                balance -= 5;
                option.time += option.defaultTime;
                option.active = true;
                option.paused = false;
                option.pauseCount = 0;
                digitalWrite(option.relayPin, LOW); // Turn on the relay
                balanceChanged = true; // Set flag to update balance display
                timeChanged = true;    // Set flag to update time display
            } else if (option.active) {
                if (!option.paused && option.pauseCount < 3) {
                    option.paused = true;
                    option.pauseCount++;
                    digitalWrite(option.relayPin, HIGH); // Turn off the relay (pause)
                } else if (option.paused) {
                    option.paused = false;
                    digitalWrite(option.relayPin, LOW); // Turn on the relay (resume)
                }
                timeChanged = true; // Set flag to update time display
            }
        }
    }

    option.lastButtonState = buttonState;
}

// Check if any timer is active
bool anyTimerActive() {
    for (int i = 0; i < NUM_OPTIONS; i++) {
        if (options[i].active) {
            return true;
        }
    }
    return false;
}

// Check if all timers are zero
bool allTimersZero() {
    for (int i = 0; i < NUM_OPTIONS; i++) {
        if (options[i].time > 0) {
            return false;
        }
    }
    return true;
}

// Check and sound buzzer at specific intervals
void checkBuzzerTiming() {
    unsigned long currentMillis = millis();
    if (currentMillis - options[0].lastDebounceTime >= BUZZER_CHECK_INTERVAL) {
        for (int i = 0; i < NUM_OPTIONS; i++) {
            if (options[i].active && !options[i].paused) {
                checkAndSoundBuzzer(options[i].time);
            }
        }
    }
}

// Update timers every second
void updateTime() {
    bool displayNeedsUpdate = false;

    for (int i = 0; i < NUM_OPTIONS; i++) {
        if (options[i].active && !options[i].paused && options[i].time > 0) {
            options[i].time--;
            displayNeedsUpdate = true;
        }

        if (options[i].time == 0 && options[i].active) {
            options[i].active = false;
            digitalWrite(options[i].relayPin, HIGH); // Turn off relay
        }
    }

    if (balance == 0 && allTimersZero()) {
        displayInitialScreen();
    } else if (displayNeedsUpdate) {
        timeChanged = true; // Set flag to update time display
        updateTimeDisplay();
    }
}

// Display initial screen
void displayInitialScreen() {
    lcd.setCursor(3, 0);
    lcd.print(" 3in1 CARWASH");
    lcd.setCursor(0, 2);
    lcd.print("WATER  SOAP   BLOWER");
    lcd.setCursor(0, 3);
    lcd.print("00:00  00:00  00:00");
    lcd.setCursor(0, 1);
    lcd.print("  --Insert Coin!--");
}

// Blink the "Insert Coin" message
void blinkInsertCoinMessage(unsigned long currentMillis) {
    static unsigned long lastInsertCoinBlinkTime = 0;
    static bool showInsertCoin = true;
    if (currentMillis - lastInsertCoinBlinkTime > BLINK_INTERVAL) {
        lastInsertCoinBlinkTime = currentMillis;
        showInsertCoin = !showInsertCoin;
        lcd.setCursor(0, 1);
        if (showInsertCoin) {
            lcd.print("  --Insert Coin!--  ");
        } else {
            lcd.print("                  ");
        }
    }
}

// Handle blinking for paused timers
void handlePausedBlinking(unsigned long currentMillis) {
    for (int i = 0; i < NUM_OPTIONS; i++) {
        if (options[i].paused && currentMillis - options[i].lastBlinkTime > BLINK_INTERVAL) {
            options[i].lastBlinkTime = currentMillis;
            options[i].blinkState = !options[i].blinkState;
            lcd.setCursor(i * 7, 3); // Update the position based on the option
            displayTime(options[i].time, options[i].paused, options[i].blinkState);
        }
    }
}

// Display time in mm:ss format
void displayTime(int seconds, bool paused, bool blinkState) {
    if (paused && blinkState) {
        lcd.print("     ");
    } else {
        lcd.print(formatTime(seconds));
    }
}

// Format seconds into mm:ss string
String formatTime(int seconds) {
    int mins = seconds / 60;
    int secs = seconds % 60;
    char buf[6];
    sprintf(buf, "%02d:%02d", mins, secs);
    return String(buf);
}

// Update time display
void updateTimeDisplay() {
    if (timeChanged) {
        for (int i = 0; i < NUM_OPTIONS; i++) {
            lcd.setCursor(i * 7, 3); // Position for each time
            lcd.print(formatTime(options[i].time));
        }
        timeChanged = false;
    }
}

I can't even say it compiles. L8R.

a7

1 Like

It did not compile for me. Error report below. Sunday papers unfinished so have not pursued further. Perhaps ambiguity over LiquidCrystal_I2C library - there are several contenders.

Arduino: 1.8.19 (Windows 10), Board: "Arduino Uno"

C:\Program Files (x86)\Arduino\arduino-builder -dump-prefs -logger=machine -hardware C:\Program Files (x86)\Arduino\hardware -hardware C:\Users\terry\AppData\Local\Arduino15\packages -hardware C:\Users\terry\Dropbox\Electronics\Arduino\SKETCHES\hardware -tools C:\Program Files (x86)\Arduino\tools-builder -tools C:\Program Files (x86)\Arduino\hardware\tools\avr -tools C:\Users\terry\AppData\Local\Arduino15\packages -built-in-libraries C:\Program Files (x86)\Arduino\libraries -libraries C:\Users\terry\Dropbox\Electronics\Arduino\SKETCHES\libraries -fqbn=arduino:avr:uno -ide-version=10819 -build-path C:\Users\terry\AppData\Local\Temp\arduino_build_374173 -warnings=all -build-cache C:\Users\terry\AppData\Local\Temp\arduino_cache_598274 -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.arduinoOTA.path=C:\Users\terry\AppData\Local\Arduino15\packages\arduino\tools\arduinoOTA\1.3.0 -prefs=runtime.tools.arduinoOTA-1.3.0.path=C:\Users\terry\AppData\Local\Arduino15\packages\arduino\tools\arduinoOTA\1.3.0 -prefs=runtime.tools.avr-gcc.path=C:\Users\terry\AppData\Local\Arduino15\packages\arduino\tools\avr-gcc\7.3.0-atmel3.6.1-arduino7 -prefs=runtime.tools.avr-gcc-7.3.0-atmel3.6.1-arduino7.path=C:\Users\terry\AppData\Local\Arduino15\packages\arduino\tools\avr-gcc\7.3.0-atmel3.6.1-arduino7 -prefs=runtime.tools.avrdude.path=C:\Users\terry\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17 -prefs=runtime.tools.avrdude-6.3.0-arduino17.path=C:\Users\terry\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17 -verbose C:\Users\terry\Dropbox\Electronics\Arduino\SKETCHES\MY SKETCHES\MISC_or_UNASSIGNED\FORUM\3in1-Chat-orig\3in1-Chat-orig.ino

C:\Program Files (x86)\Arduino\arduino-builder -compile -logger=machine -hardware C:\Program Files (x86)\Arduino\hardware -hardware C:\Users\terry\AppData\Local\Arduino15\packages -hardware C:\Users\terry\Dropbox\Electronics\Arduino\SKETCHES\hardware -tools C:\Program Files (x86)\Arduino\tools-builder -tools C:\Program Files (x86)\Arduino\hardware\tools\avr -tools C:\Users\terry\AppData\Local\Arduino15\packages -built-in-libraries C:\Program Files (x86)\Arduino\libraries -libraries C:\Users\terry\Dropbox\Electronics\Arduino\SKETCHES\libraries -fqbn=arduino:avr:uno -ide-version=10819 -build-path C:\Users\terry\AppData\Local\Temp\arduino_build_374173 -warnings=all -build-cache C:\Users\terry\AppData\Local\Temp\arduino_cache_598274 -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.arduinoOTA.path=C:\Users\terry\AppData\Local\Arduino15\packages\arduino\tools\arduinoOTA\1.3.0 -prefs=runtime.tools.arduinoOTA-1.3.0.path=C:\Users\terry\AppData\Local\Arduino15\packages\arduino\tools\arduinoOTA\1.3.0 -prefs=runtime.tools.avr-gcc.path=C:\Users\terry\AppData\Local\Arduino15\packages\arduino\tools\avr-gcc\7.3.0-atmel3.6.1-arduino7 -prefs=runtime.tools.avr-gcc-7.3.0-atmel3.6.1-arduino7.path=C:\Users\terry\AppData\Local\Arduino15\packages\arduino\tools\avr-gcc\7.3.0-atmel3.6.1-arduino7 -prefs=runtime.tools.avrdude.path=C:\Users\terry\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17 -prefs=runtime.tools.avrdude-6.3.0-arduino17.path=C:\Users\terry\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17 -verbose C:\Users\terry\Dropbox\Electronics\Arduino\SKETCHES\MY SKETCHES\MISC_or_UNASSIGNED\FORUM\3in1-Chat-orig\3in1-Chat-orig.ino

Using board 'uno' from platform in folder: C:\Users\terry\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.6

Using core 'arduino' from platform in folder: C:\Users\terry\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.6

Detecting libraries used...

"C:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10819 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\cores\\arduino" "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\variants\\standard" "C:\\Users\\terry\\AppData\\Local\\Temp\\arduino_build_374173\\sketch\\3in1-Chat-orig.ino.cpp" -o nul

Alternatives for Wire.h: [Wire@1.0]

ResolveLibrary(Wire.h)

  -> candidates: [Wire@1.0]

"C:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10819 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\cores\\arduino" "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\variants\\standard" "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\libraries\\Wire\\src" "C:\\Users\\terry\\AppData\\Local\\Temp\\arduino_build_374173\\sketch\\3in1-Chat-orig.ino.cpp" -o nul

Alternatives for LiquidCrystal_I2C.h: [LiquidCrystal_I2C@1.1.2]

ResolveLibrary(LiquidCrystal_I2C.h)

  -> candidates: [LiquidCrystal_I2C@1.1.2]

"C:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10819 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\cores\\arduino" "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\variants\\standard" "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\libraries\\Wire\\src" "-IC:\\Users\\terry\\Dropbox\\Electronics\\Arduino\\SKETCHES\\libraries\\LiquidCrystal_I2C" "C:\\Users\\terry\\AppData\\Local\\Temp\\arduino_build_374173\\sketch\\3in1-Chat-orig.ino.cpp" -o nul

"C:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10819 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\cores\\arduino" "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\variants\\standard" "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\libraries\\Wire\\src" "-IC:\\Users\\terry\\Dropbox\\Electronics\\Arduino\\SKETCHES\\libraries\\LiquidCrystal_I2C" "C:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\libraries\\Wire\\src\\Wire.cpp" -o nul

"C:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10819 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\cores\\arduino" "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\variants\\standard" "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\libraries\\Wire\\src" "-IC:\\Users\\terry\\Dropbox\\Electronics\\Arduino\\SKETCHES\\libraries\\LiquidCrystal_I2C" "C:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\libraries\\Wire\\src\\utility\\twi.c" -o nul

"C:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10819 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\cores\\arduino" "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\variants\\standard" "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\libraries\\Wire\\src" "-IC:\\Users\\terry\\Dropbox\\Electronics\\Arduino\\SKETCHES\\libraries\\LiquidCrystal_I2C" "C:\\Users\\terry\\Dropbox\\Electronics\\Arduino\\SKETCHES\\libraries\\LiquidCrystal_I2C\\LiquidCrystal_I2C.cpp" -o nul

Generating function prototypes...

"C:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10819 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\cores\\arduino" "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\variants\\standard" "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\libraries\\Wire\\src" "-IC:\\Users\\terry\\Dropbox\\Electronics\\Arduino\\SKETCHES\\libraries\\LiquidCrystal_I2C" "C:\\Users\\terry\\AppData\\Local\\Temp\\arduino_build_374173\\sketch\\3in1-Chat-orig.ino.cpp" -o "C:\\Users\\terry\\AppData\\Local\\Temp\\arduino_build_374173\\preproc\\ctags_target_for_gcc_minus_e.cpp"

"C:\\Program Files (x86)\\Arduino\\tools-builder\\ctags\\5.8-arduino11/ctags" -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns --line-directives "C:\\Users\\terry\\AppData\\Local\\Temp\\arduino_build_374173\\preproc\\ctags_target_for_gcc_minus_e.cpp"

Compiling sketch...

"C:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-g++" -c -g -Os -Wall -Wextra -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -MMD -flto -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10819 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\cores\\arduino" "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\variants\\standard" "-IC:\\Users\\terry\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.8.6\\libraries\\Wire\\src" "-IC:\\Users\\terry\\Dropbox\\Electronics\\Arduino\\SKETCHES\\libraries\\LiquidCrystal_I2C" "C:\\Users\\terry\\AppData\\Local\\Temp\\arduino_build_374173\\sketch\\3in1-Chat-orig.ino.cpp" -o "C:\\Users\\terry\\AppData\\Local\\Temp\\arduino_build_374173\\sketch\\3in1-Chat-orig.ino.cpp.o"

C:\Users\terry\Dropbox\Electronics\Arduino\SKETCHES\MY SKETCHES\MISC_or_UNASSIGNED\FORUM\3in1-Chat-orig\3in1-Chat-orig.ino: In function 'void loop()':

3in1-Chat-orig:95:9: error: 'displayActiveScreen' was not declared in this scope

         displayActiveScreen(); // Update the display

         ^~~~~~~~~~~~~~~~~~~

C:\Users\terry\Dropbox\Electronics\Arduino\SKETCHES\MY SKETCHES\MISC_or_UNASSIGNED\FORUM\3in1-Chat-orig\3in1-Chat-orig.ino:95:9: note: suggested alternative: 'displayInitialScreen'

         displayActiveScreen(); // Update the display

         ^~~~~~~~~~~~~~~~~~~

         displayInitialScreen

C:\Users\terry\Dropbox\Electronics\Arduino\SKETCHES\MY SKETCHES\MISC_or_UNASSIGNED\FORUM\3in1-Chat-orig\3in1-Chat-orig.ino: In function 'void checkBuzzerTiming()':

3in1-Chat-orig:198:17: error: 'checkAndSoundBuzzer' was not declared in this scope

                 checkAndSoundBuzzer(options[i].time);

                 ^~~~~~~~~~~~~~~~~~~

Using library Wire at version 1.0 in folder: C:\Users\terry\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.6\libraries\Wire 

Using library LiquidCrystal_I2C at version 1.1.2 in folder: C:\Users\terry\Dropbox\Electronics\Arduino\SKETCHES\libraries\LiquidCrystal_I2C 

exit status 1

'displayActiveScreen' was not declared in this scope


Perhaps the LCD thing. But certainly the fact that there is no function to match the call to displayActiveScreen() in the code can't help.

3in1-Chat-orig:95:9: error: 'displayActiveScreen' was not declared in this scope

Same as checkAndSounBuzzer().

I got chatGPT to explain why there are active and pause flags. Its explanation was interesting but not convincing. I have to go out of my way to see a need for them both. Water button can turn on and off the water, water being on or off don't matter if you press soap, which either just turns on and off soap or additional turns off the water. I don't have a car, and if I did I'm sure it would never get washed…

I can't say when (or even if) I'll lookd to see how badly it did. For a seven minute effort, it at least shows the struct variabke, but since it was not tasked with a rewrite too to bottom the code still looks a bit complicated for what its goal seems to be.

I would probably start by taking my own advice and getting the LCD out of there for the moment.

Be reminded that the only thing there is only so much if is time. :expressionless:

a7

Rarely forget it as the years tick by.
:slightly_smiling_face:

How does the code ensure thread safety when the coinsInserted variable is modified in the interrupt service routine (ISR) Add() while being read in the main loop()? Are there potential race conditions, and if so, how could they be mitigated without disabling interrupts or using more advanced synchronization mechanisms like atomic variables or mutexes?

Continuing with ChatgGPT I asked for possible explanations why the code did not compile. For follow up by Nicole:
P.S I note ChatGPT has disowned its code. My question was
"You recommended the following Arduino code, but it failed to compile. Can you suggest possible explanations?"

Here are a few possible reasons why your Arduino code might be failing to compile:

1. Library Issues (LiquidCrystal_I2C)
The LiquidCrystal_I2C library may not be installed or is incompatible with your version of the Arduino IDE.
Try reinstalling it using the Library Manager (Sketch > Include Library > Manage Libraries).
Ensure you are using a compatible version (fmalpartida’s library is widely used).
2. Incorrect Constructor for LiquidCrystal_I2C
Some versions of LiquidCrystal_I2C require an explicit begin() in setup().
Try adding:
cpp
Copy
Edit
lcd.begin(20, 4);  // Ensure the display initializes correctly
3. Interrupt Function Signature Issue (Add Function)
The Add() function is used as an interrupt service routine (ISR), but it uses a non-ISR-friendly variable (coinsInserted).
ISRs should only modify volatile variables and avoid function calls like lcd.print().
Modify Add() to:
cpp
Copy
Edit
void Add() {
    coinsInserted++; // Ensure this is volatile
}
4. Pin Mode for Buttons
You use digitalRead(option.buttonPin), but button pins are never initialized.
Add in setup():
cpp
Copy
Edit
for (int i = 0; i < NUM_OPTIONS; i++) {
    pinMode(options[i].buttonPin, INPUT_PULLUP); // Enable internal pull-up resistors
}
5. checkBuzzerTiming() Logic
The function calls checkAndSoundBuzzer(options[i].time), but this function isn't defined in your code.
You need to either define it or remove the call.
6. Potential Naming Conflicts (Add)
If another library or built-in function has a name similar to Add, try renaming it to coinInsertedISR:
cpp
Copy
Edit
attachInterrupt(digitalPinToInterrupt(coinSlotPin), coinInsertedISR, FALLING);
void coinInsertedISR() {
    coinsInserted++;
}
7. Memory Usage and Performance
Large LCD updates in loop() might cause performance issues.
Consider optimizing lcd.print() usage to only update when values change.
Next Steps:
Check and update the LiquidCrystal_I2C library.
Ensure lcd.begin(20, 4); is added in setup().
Initialize button pins using pinMode().
Fix the ISR function to avoid unsafe operations.
Remove undefined function calls (checkAndSoundBuzzer).
Try these fixes and let me know if you still get errors! 🚀

The advice down here is to copy out multibyte variables that are used in ISRs by breifly turning off interrupts during.

  noInterrupts();
  int myCoinsInserterCopy = coinsInserted;
  interrupts();

There's a thing atomic.h I can't find just now which is a bit more careful. It too disables interrupts.

I didn't even notice that interrupts are in use. This is something I would eliminate or need convincing that it was impossible to do without.

a7

Reason #3 from ChatGPT possibly relevant?

An even better approach would be to set a single byte flag in the ISR and address it in the main loop() where, if the flag is set, you increment your coin count and reset the flag. This eliminates the need for a multibyte copy.

1 Like

i try this one but here is the error

sketch.ino: In function 'void loop()':
sketch.ino:95:9: error: 'displayActiveScreen' was not declared in this scope
         displayActiveScreen(); // Update the display
         ^~~~~~~~~~~~~~~~~~~
sketch.ino:95:9: note: suggested alternative: 'displayInitialScreen'
         displayActiveScreen(); // Update the display
         ^~~~~~~~~~~~~~~~~~~
         displayInitialScreen
sketch.ino: In function 'void checkBuzzerTiming()':
sketch.ino:198:17: error: 'checkAndSoundBuzzer' was not declared in this scope
                 checkAndSoundBuzzer(options[i].time);
                 ^~~~~~~~~~~~~~~~~~~

As noted in #7, those functions are missing from the code. chatGPT simply did not write them.

Perhaps you could add the ones you wrote. Or add them as dummy functions that do nothing, just to get the code to compile.

TBH I think your time would better be spent learning how to use arrays and structured variables - even if the AI code is bogus, you can see that it is much simpler once you have the right variable types defined.

a7

2 Likes

Can you help me to finish this project? I'm not very familiar with the codes yet, I'm just starting out here.

So... your sketch was written by whom? Whoever wrote it seems to have some good grasp of "the codes", as you put it. It looks plausible, but is somehow not quite right.

Your original is complicated because it makes no use of features that would make it less so; the AI version is bad because, well, who knows? AI has a tendency to make thinga that look good but are just slightly not good, which makes debugging AI code harder than debugging your own.

Read post #4 and answer the questions, we can help but as I said this is a heavy lift.

Can we say this is a controller that accepts money, and if there is sufficient funds allows an operator to turn on and off soap, water and blowing?

and

What is the difference on, off and paused for each of the three items?

I also wonder about your coin logic - using a pushbutton as a proxy, a single press acts like putting in multiple coins. Does the coin accepting device you have work to add but one coin's worth of payment per coin?

I built your project and the buttons don't do anything. Coins go in, albeit too many at a time, and the LCD changes to requesting a button be pressed, but nothing at all happens when I do.

What does your sketch do now? Does anything work other than the coin counter? Does the coin counter work for you, one coin, one balance increment?

a7

1 Like

that code comes from deepseek

this is the sample video i want to achieve

That doesn't help me (to help you) at all. I'm not even sure what language its author is using?

You haven't answered the Q in post 2:
"Who wrote the program"
(IOW, the sketch you attached in your OP.)

Is this your first substantial project? If so that seems over ambitious. And of course that probably means you've not understood the replies we and ChatGPT have offered,

Is the video your only source? If so then please post its code and explain the result of compiling and running it. And why didn't it do what you need?