/*
Wokwi | questions
Maquina expendedora
IanVsGaming - Thursday, February 12, 2026 10:20 AM
Project Link: https://wokwi.com/projects/455667190298274817?gh=1
*/
#include <LiquidCrystal.h>
#include <ESP32Servo.h>
const int NUM_LEDS = 5;
const int NUM_BTNS = 6;
const int LED_PINS[] = {21, 18, 17, 4, 13};
const int BTN_PINS[] = {22, 19, 5, 16, 15, 23};
const int SERVO_PIN = 12;
// Se definen los estados de la FSM
enum states {
REPOSO, //Sucede cuando la máquina no ha empezado a trabajar
BIENVENIDA, //Da la bienvenida al usuario
DINERO, //El usuario "ingresa dinero" presionando un botón, la máquina solo permite Q10.00
SELECCION, //El usuario escoge la bebida
DISPENSANDO, //Se dispensa la bebida y se simula con el servo
DISPENSADO, //La bebida ha sido dispensada
VUELTO, //El lcd manda un mensaje con el vuelto correspondiente, todas las bebidas valen Q5.00
DESPEDIDA //Se despide del usuario y le agradece por su compra
};
//Registra que bebida ha sido seleccionada y el tiempo que es dispensada
states currentState = REPOSO;
// global variables
bool ledState[NUM_LEDS];
bool servoMove = false;
int state = 0;
int oldState = -1; // always different on startup
int btnState[NUM_BTNS];
int oldBtnState[NUM_BTNS];
int selectedDrink = 0; //selección
unsigned long dispenseTime = 0; //tiempo
LiquidCrystal lcd(14, 27, 26, 25, 33, 32);
Servo servoMotor;
int checkButtons() {
int btnNumber = 0;
for (int i = 0; i < NUM_BTNS; i++) {
// check each button
btnState[i] = digitalRead(BTN_PINS[i]);
if (btnState[i] != oldBtnState[i]) { // if it changed
oldBtnState[i] = btnState[i]; // remember state for next time
btnNumber = i + 1;
//Serial.print("Button ");
//Serial.print(btnNumber);
if (btnState[i] == LOW) { // was just pressed
//Serial.println(" pressed.");
} else {
btnNumber = -1; // was just released
//Serial.println(" released.");
}
delay(20); // debounce
}
}
return btnNumber;
}
void showSplash() {
lcd.clear();
lcd.setCursor(4, 0);
lcd.print("Maquina");
lcd.setCursor(0, 1);
lcd.print("Expendedora V1.0");
delay(2000);
lcd.clear();
}
void setup() {
Serial.begin(9600);
lcd.begin(16, 2);
for (int i = 0; i < NUM_LEDS; i++) {
pinMode(LED_PINS[i], OUTPUT);
}
for (int i = 0; i < NUM_BTNS; i++) {
pinMode(BTN_PINS[i], INPUT_PULLUP);
}
servoMotor.attach(SERVO_PIN);
servoMotor.write(90);
showSplash();
}
void loop() {
int btnNumber = checkButtons();
if (btnNumber) {
if (btnNumber == 1) {
Serial.println("Button 1");
ledState[0] = !ledState[0];
} else if (btnNumber == 2) {
Serial.println("Button 2");
ledState[1] = !ledState[1];
} else if (btnNumber == 3) {
Serial.println("Button 3");
ledState[2] = !ledState[2];
} else if (btnNumber == 4) {
Serial.println("Button 4");
ledState[3] = !ledState[3];
} else if (btnNumber == 5) {
Serial.println("Button 5");
ledState[4] = !ledState[4];
} else if (btnNumber == 6) {
Serial.println("Button 6");
state++;
if (state > 7) state = 0;
servoMove = !servoMove;
servoMotor.write(servoMove ? 180 : 0);
}
for (int i = 0; i < NUM_LEDS; i++) {
digitalWrite(LED_PINS[i], ledState[i]);
}
}
if (state != oldState) {
oldState = state;
Serial.print("State: ");
Serial.println(state);
//Se programa la máquina de estados finitos (Máquina Expendedora de Bebidas)
switch (state) {
case REPOSO:
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Espere por favor");
delay(2000);
state = BIENVENIDA;
break;
case BIENVENIDA:
lcd.clear();
lcd.setCursor(2, 0);
lcd.print("Bienvenido!");
delay(2000);
state = DINERO;
break;
case DINERO:
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Ingrese dinero:");
break;
case SELECCION:
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("Por favor");
lcd.setCursor(3, 1);
lcd.print("seleccione");
break;
case DISPENSANDO:
lcd.clear();
lcd.setCursor(2, 0);
lcd.print("Dispensacion");
break;
case DISPENSADO:
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("Repartido");
break;
case VUELTO:
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("Mostrar costo");
break;
case DESPEDIDA:
lcd.clear();
lcd.setCursor(4, 0);
lcd.print("Gracias!");
break;
default:
lcd.clear();
lcd.setCursor(2, 0);
lcd.print("Error 99");
Serial.println("Error!");
}
}
}