//https://forum.arduino.cc/t/why-did-not-recognize-inserted-coin-value/1300588
#include "TM1637.h" //https://github.com/Seeed-Studio/Seeed_Grove_4Digital_Display_g/blob/master/TM1637.h
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// Define the connections to the Grove 4-digit display
#define CLK 3 // Clock pin to D3
#define DIO 4 // Data pin to D4
// Create instances of the displays
TM1637 display(CLK, DIO);
LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C address 0x27 is common
// Pin connected to the coin acceptor signal
const int coinPin = 2;
volatile int coinCount = 0;
volatile bool coinInsertedFlag = false;
bool timerStarted = false;
unsigned long startTime = 0;
const int requiredCoins = 25;
const int countdownDuration = 180; // 5 minutes in seconds
// Relay pins
const int relay1Pin = 8;
const int relay2Pin = 6;
const int relay3Pin = 7;
// Button pin
const int buttonPin = 5;
bool buttonPressed = false;
// Buzzer pin
const int buzzerPin = 11;
// Beep settings
const int beepDuration = 500; // Duration of each beep in milliseconds
const int beepDelay = 500; // Delay between beeps in milliseconds
// Debounce variables for coin acceptor
unsigned long lastPulseTime = 0;
const unsigned long debounceDelay = 50; // 50 ms debounce delay
const unsigned long pulseTimeout = 100; // 100 ms pulse validation window
// Relay states for avoiding unnecessary LCD updates
int lastRelayState = 0; // 0 = None, 1 = Relay1, 2 = Relay2, 3 = Relay3
// State variables for pulse validation
bool firstPulseDetected = false;
// Interrupt service routine for coin detection with debounce and pulse validation
bool coinFlag = false;
unsigned long currentTime = 0;
//----------------------------------------------------------------
void coinInserted() {
coinFlag = true;
// digitalWrite(13, !digitalRead(13));
digitalWrite(13, HIGH);
}
//----------------------------------------------------------------
void coinDetec() {
digitalWrite(13, LOW);
detachInterrupt(digitalPinToInterrupt(coinPin));
currentTime = millis();
// Check for debounce
if (currentTime - lastPulseTime < debounceDelay) {
Serial.println("y");
return; // Ignore if within debounce time
}
if()
coinCount++; // Valid coin insertion detected
coinInsertedFlag = true;
}
//----------------------------------------------------------------
void setup() {
Serial.begin(115200);
// Initialize the Grove 4-digit display
display.init();
display.set(7); // Set the brightness (0-7, 7 is the max)
// Initialize the I2C LCD
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Insert Coins: ");
lcd.setCursor(0, 1);
lcd.print("0 / 40");
// Set up coin acceptor input pin
pinMode(coinPin, INPUT_PULLUP);
// Set up relay pins
pinMode(relay1Pin, OUTPUT);
pinMode(relay2Pin, OUTPUT);
pinMode(relay3Pin, OUTPUT);
// Set up button pin
pinMode(buttonPin, INPUT);
// Set up buzzer pin
pinMode(buzzerPin, OUTPUT);
// Ensure all relays are off initially (HIGH for negative logic)
digitalWrite(relay1Pin, HIGH);
digitalWrite(relay2Pin, HIGH);
digitalWrite(relay3Pin, HIGH);
// Attach interrupt to the coinPin
attachInterrupt(digitalPinToInterrupt(coinPin), coinInserted, FALLING);
}
//----------------------------------------------------------------
void beepTone(int frequency) {
tone(buzzerPin, frequency); // Start the beep
delay(beepDuration); // Duration of the beep
noTone(buzzerPin); // Stop the beep
delay(beepDelay); // Delay between beeps
}
//----------------------------------------------------------------
void loop() {
if (coinFlag == true) {
coinDetec();
coinFlag = false;
}
if (coinInsertedFlag && !timerStarted) {
// Display the coin count on the 7-segment display
display.display(0, coinCount / 10); // Tens place
display.display(1, coinCount % 10); // Ones place
// Update the LCD with the current coin count
lcd.setCursor(0, 1);
lcd.print(coinCount);
lcd.print(" / 40 ");
if (coinCount >= requiredCoins && !timerStarted) {
lcd.setCursor(0, 0);
lcd.print("Press button to");
lcd.setCursor(0, 1);
lcd.print("start timer ");
}
// Reset the flag after updating the display
coinInsertedFlag = false;
while(digitalRead(coinPin) == LOW){}
attachInterrupt(digitalPinToInterrupt(coinPin), coinInserted, FALLING);
}
if (!timerStarted) {
// Read the button state
int buttonState = digitalRead(buttonPin);
delay(10); // Add a small delay for button debouncing
// Check if the required number of coins has been inserted
if (coinCount >= requiredCoins && buttonState == LOW) {
buttonPressed = true;
timerStarted = true;
startTime = millis(); // Record the start time
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Timer Started!");
}
} else {
// Calculate the time remaining for the countdown
int elapsedSeconds = (millis() - startTime) / 1000;
int remainingSeconds = countdownDuration - elapsedSeconds;
int currentRelayState = 0; // Variable to track current relay state
// Relay control and buzzer beeping based on elapsed time (negative logic)
if ((elapsedSeconds >= 1) && (elapsedSeconds < 90)) {
// First 90 seconds: Relay 1 on, others off, buzzer tone 1
digitalWrite(relay1Pin, LOW);
digitalWrite(relay2Pin, LOW);
digitalWrite(relay3Pin, HIGH);
beepTone(1000); // Beep tone of 1000 Hz
currentRelayState = 1; // Relay 1 is active
} else if ((elapsedSeconds > 90) && (elapsedSeconds < 100)) {
// Between 90 and 100 seconds: Relay 2 on, others off, buzzer tone 2
digitalWrite(relay1Pin, LOW);
digitalWrite(relay2Pin, HIGH);
digitalWrite(relay3Pin, LOW);
beepTone(1500); // Beep tone of 1500 Hz
currentRelayState = 2; // Relay 2 is active
} else if (elapsedSeconds > 100) {
// After 100 seconds: Relay 3 on, others off, buzzer tone 3
digitalWrite(relay1Pin, LOW);
digitalWrite(relay2Pin, HIGH);
digitalWrite(relay3Pin, HIGH);
beepTone(2000); // Beep tone of 2000 Hz
currentRelayState = 3; // Relay 3 is active
}
// Update the LCD only if the relay state has changed
if (currentRelayState != lastRelayState) {
lcd.clear(); // Clear LCD screen only when state changes
if (currentRelayState == 1) {
lcd.setCursor(0, 0);
lcd.print("Please Wait");
lcd.setCursor(0, 1);
lcd.print("Warming up");
// Serial.println("UV ONLY");
} else if (currentRelayState == 2) {
lcd.setCursor(0, 0);
lcd.print("Disinfecting Now!");
// Serial.println("UV and HEATER");
} else if (currentRelayState == 3) {
lcd.setCursor(0, 0);
lcd.print("Disinfecting Now!");
// Serial.println("UV ONLY");
}
// Update the last relay state
lastRelayState = currentRelayState;
}
// If the countdown is still running
if (remainingSeconds > 0) {
// Display the remaining time in MM:SS format
int minutes = remainingSeconds / 60;
int seconds = remainingSeconds % 60;
display.display(0, minutes / 10); // Tens place of minutes
display.display(1, minutes % 10); // Ones place of minutes
display.display(2, seconds / 10); // Tens place of seconds
display.display(3, seconds % 10); // Ones place of seconds
display.point(true); // Show the colon points
} else {
// Countdown has ended
display.clearDisplay();
timerStarted = false;
buttonPressed = false;
coinCount = 0; // Reset for the next round
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Insert Coins: ");
// Turn off all relays at the end (HIGH for negative logic)
digitalWrite(relay1Pin, HIGH);
digitalWrite(relay2Pin, HIGH);
digitalWrite(relay3Pin, HIGH);
}
}
}