#include <Servo.h>
#include <Arduino.h>
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>
Servo brand0Servo;
const int brand0ButtonPin = 4;
const int coinPin = 2;
const int ledPin = 6; // Red LED
const int insufficientLedPin = 7; // Green LED
const int irSensorPin = 8;
const int buzzerPin = 10; // Pin for the buzzer
volatile int impulsCount = 0;
float totalAmount = 0.0;
float coinValue;
const char *brand0Name = "Cigar";
const int brand0Price = 8;
const int coinPulses[] = {1, 2, 5, 10};
const float coinValues[] = {1.0, 2.0, 5.0, 10.0};
LiquidCrystal_I2C lcd(0x27, 16, 2);
unsigned long previousMillis = 0;
const unsigned long interval = 3000;
int messageState = 0;
bool transactionActive = false;
bool outOfStockDisplayed = false;
bool messageUpdated = false; // Flag to track message updates
unsigned long ledBlinkMillis = 0;
bool ledState = false; // For blinking LED
float lookup(int pulses) {
for (int i = 0; i < sizeof(coinPulses) / sizeof(coinPulses[0]); i++) {
if (pulses == coinPulses[i]) {
return coinValues[i];
}
}
return -1;
}
void setup() {
pinMode(brand0ButtonPin, INPUT_PULLUP);
pinMode(coinPin, INPUT);
pinMode(ledPin, OUTPUT);
pinMode(insufficientLedPin, OUTPUT);
pinMode(irSensorPin, INPUT);
pinMode(buzzerPin, OUTPUT); // Set buzzer pin as output
attachInterrupt(digitalPinToInterrupt(coinPin), coinInterrupt, FALLING);
brand0Servo.attach(9);
brand0Servo.write(60);
lcd.init();
lcd.clear();
lcd.backlight();
Serial.begin(9600);
checkStockOnBoot(); // Check stock on boot and handle initial state
}
void coinInterrupt() {
impulsCount++;
}
void checkStockOnBoot() {
if (digitalRead(irSensorPin) == LOW) { // Stock available
resetDisplay();
outOfStockDisplayed = false;
messageUpdated = false; // Allow message toggling
} else { // Stock out
handleOutOfStock(); // Handle out-of-stock state
}
}
void handleOutOfStock() {
lcd.clear();
lcd.setCursor(4, 0);
lcd.print("OUT OF");
lcd.setCursor(5, 1);
lcd.print("STOCK");
totalAmount = 0.0;
outOfStockDisplayed = true;
beepOutOfStock(); // Beep for out of stock
}
void monitorStock() {
if (digitalRead(irSensorPin) == LOW) { // Stock available
if (outOfStockDisplayed) {
resetDisplay(); // Reset display if stock is replenished
outOfStockDisplayed = false;
}
} else { // Stock out
if (!outOfStockDisplayed) {
handleOutOfStock(); // Handle out-of-stock state
}
}
}
bool checkStockBeforeDispense() {
if (digitalRead(irSensorPin) == LOW) { // Stock available
outOfStockDisplayed = false;
return true;
} else { // Stock out
if (!outOfStockDisplayed) {
handleOutOfStock();
}
return false;
}
}
void loop() {
unsigned long currentMillis = millis();
// Continuously monitor stock availability
monitorStock();
// Handle LED blinking when stock is out
if (outOfStockDisplayed) {
if (currentMillis - ledBlinkMillis >= 200) { // Toggle LED every 500ms
ledBlinkMillis = currentMillis;
ledState = !ledState;
if (ledState) {
digitalWrite(ledPin, HIGH); // Turn on red LED
digitalWrite(insufficientLedPin, LOW); // Turn off green LED
} else {
digitalWrite(ledPin, LOW); // Turn off red LED
digitalWrite(insufficientLedPin, HIGH); // Turn on green LED
}
}
} else {
// Reset the LED to the balance state after transaction
if (totalAmount <= 7) {
digitalWrite(ledPin, HIGH); // Red LED on
digitalWrite(insufficientLedPin, LOW); // Green LED off
} else {
digitalWrite(ledPin, LOW); // Red LED off
digitalWrite(insufficientLedPin, HIGH); // Green LED on
}
}
// Only update the message after the interval has passed and the message has not been updated
if (!transactionActive && currentMillis - previousMillis >= interval && !messageUpdated) {
previousMillis = currentMillis;
messageState = (messageState + 1) % 2;
messageUpdated = true; // Set flag to indicate the message has been updated
resetDisplay();
}
if (impulsCount > 0) {
coinValue = lookup(impulsCount);
if (coinValue > 0) {
totalAmount += coinValue;
transactionActive = true;
beepCoinInserted(); // Beep when a coin is inserted
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" YOUR BALANCE");
lcd.setCursor(0, 1);
lcd.print(" Php ");
lcd.print(totalAmount, 2);
impulsCount = 0;
}
// LED Behavior: Turn on red if insufficient funds, green if sufficient funds
if (totalAmount >= brand0Price) {
digitalWrite(ledPin, LOW); // Turn off red LED
digitalWrite(insufficientLedPin, HIGH); // Turn on green LED
} else {
digitalWrite(ledPin, HIGH); // Turn on red LED
digitalWrite(insufficientLedPin, LOW); // Turn off green LED
}
if (digitalRead(brand0ButtonPin) == LOW) {
if (totalAmount == 0) {
displayMessage("Insert Coin", 2000);
beepInsufficientFunds(); // Beep if insufficient funds
} else if (totalAmount < brand0Price) {
displayMessage("Add More Coins", 2000);
beepInsufficientFunds(); // Beep if insufficient funds
} else if (outOfStockDisplayed) {
// If stock is out and button is pressed, show "COME BACK LATER"
displayMessage(" COME BACK", 1000);
displayMessage(" LATER", 1000);
}
}
if (digitalRead(brand0ButtonPin) == LOW && totalAmount >= brand0Price && !outOfStockDisplayed) {
dispenseCigar(brand0Servo, brand0Name, brand0Price);
beepSufficientFunds(); // Beep when the item is dispensed
}
// Reset messageUpdated flag after user interaction to allow toggling
if (digitalRead(brand0ButtonPin) == LOW || impulsCount > 0) {
messageUpdated = false; // Allow message to toggle again after user action
}
}
void displayMessage(const char *message, int duration) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(message);
delay(duration);
resetDisplay();
}
void beepCoinInserted() {
tone(buzzerPin, 4000, 200); // Short beep when a coin is inserted
}
void beepSufficientFunds() {
tone(buzzerPin, 3000, 2000); // Long beep if funds are sufficient
}
void beepInsufficientFunds() {
for (int i = 0; i < 3; i++) {
tone(buzzerPin, 3000, 200); // Beep 3 times if insufficient funds
delay(200);
}
}
void beepOutOfStock() {
for (int i = 0; i < 50; i++) {
tone(buzzerPin, 5000, 150); // Beep 10 times if out of stock
delay(150);
}
}
void resetDisplay() {
if (messageState == 0) {
lcd.clear(); // Clear display only if necessary
lcd.setCursor(0, 0);
lcd.print(" EXACT AMOUNT");
lcd.setCursor(0, 1);
lcd.print(" ONLY!");
} else {
lcd.clear(); // Clear display only if necessary
lcd.setCursor(0, 0);
lcd.print(" CIGAR VENDO");
lcd.setCursor(0, 1);
lcd.print(" NO MINORS!");
}
}
void dispenseCigar(Servo &servo, const char *brandName, int price) {
int cigars = totalAmount / price;
for (int i = cigars; i > 0; i--) {
if (!checkStockBeforeDispense()) { // Check stock before dispensing
return;
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Dispensing ");
lcd.setCursor(0, 1);
lcd.print(String(brandName) + " " + String(i));
servo.write(0);
delay(300);
servo.write(30);
delay(300);
servo.write(0);
delay(300);
servo.write(30);
delay(300);
servo.write(0);
delay(300);
servo.write(30);
delay(300);
servo.write(60);
delay(300);
}
totalAmount = 0.0;
transactionActive = false;
digitalWrite(ledPin, LOW);
digitalWrite(insufficientLedPin, LOW);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" THANK YOU!");
delay(2000);
resetDisplay();
}
not really into electronics, please bear with my diagram