/* This is my 20 Tray FOOD VENDING MACHINE.
Item numbers are Item 01 to Item 20.
This code is made by myself with the help of research and study.
I don't have a YouTube channel.
Feel free to grab this code and use it as you want.
Thank you! */
#include <Keypad.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
Servo servos[20];
LiquidCrystal_I2C lcd(0x27, 16, 2);
#define relayCoin 2
#define coinSlot 10
#define LED 11
#define vending 12
#define buzz 13
const byte ROWS = 4; // Four rows
const byte COLS = 3; // Four columns
char keys[ROWS][COLS] = {
{'1', '2', '3'},
{'4', '5', '6'},
{'7', '8', '9'},
{'*', '0', '#'}
};
byte rowPins[ROWS] = {9, 8, 7, 6}; // Connect to R1, R2, R3, R4
byte colPins[COLS] = {5, 4, 3}; // Connect to C1, C2, C3
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
//Keypad and selection global variables
int itemValues[20] = {5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100};
int itemNumber;
char num1 = 0;
char num2 = 0;
byte inputState = 0; // 0: Waiting for first digit, 1: Waiting for second digit, 2: Displaying result
const char* messages[] = {
"You selected 01", "You selected 02", "You selected 03", "You selected 04",
"You selected 05", "You selected 06", "You selected 07", "You selected 08",
"You selected 09", "You selected 10", "You selected 11", "You selected 12",
"You selected 13", "You selected 14", "You selected 15", "You selected 16",
"You selected 17", "You selected 18", "You selected 19", "You selected 20" };
//Insert coins variables
int pulse;
int coinSlotStatus;
// State variables
enum State { KEYPAD, COINS };
State currentState = KEYPAD;
//vending variables
int vendingStatus;
int coinBalance;
int itemPrices[20] =
{ 5, 10, 15, 20, 25,
30, 35, 40, 45, 50,
55, 60, 65, 70, 75,
80, 85, 90, 95, 100};
bool allowInsertCoins = false; // Add this global flag
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
lcd.init();
lcd.backlight();
oneBEEP();
lcd.clear();
lcd.setCursor(0,0);
lcd.print("MY VENDO MACHINE");
lcd.setCursor(0,1);
lcd.print(" INITIALIZING");
delay(2000);
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" INPUT ITEM");
lcd.setCursor(0,1);
lcd.print(" NUMBER");
pinMode(relayCoin, OUTPUT);
pinMode(coinSlot, INPUT_PULLUP);
pinMode(LED, OUTPUT);
pinMode(vending, INPUT_PULLUP);
pinMode(buzz, OUTPUT);
digitalWrite(LED, HIGH);
for(int servoNum = 0; servoNum < 20; servoNum++){
servos[servoNum].attach(22+ servoNum);
}
}
void loop() {
typeKeypad();
if (currentState == COINS && allowInsertCoins) {
insertCoins();
vendingItem();
}
}
void typeKeypad(){
// put your main code here, to run repeatedly:
char digit = keypad.getKey();
if (inputState == 0) {
if (digit) {
kpadTone();
num1 = digit;
inputState = 1; // Switch to waiting for the second digit
delay(300);
}
} else if (inputState == 1) {
if (digit) {
kpadTone();
num2 = digit;
inputState = 2; // Both digits received, display the result
delay(300);
}
} else if (inputState == 2) {
int index = (num1 - '0') * 10 + (num2 - '0');
if (index >= 1 && index <= 20) {
digitalWrite(relayCoin, HIGH);
LEDindicator();
twoBEEP();
displayResult(messages[index - 1], itemValues[index - 1]);
allowInsertCoins = true;
}else{
errorTone();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("INVALID NUMBERS");
lcd.setCursor(0, 1);
lcd.print(" SELECT AGAIN");
delay(500);
lcd.clear();
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" INPUT ITEM");
lcd.setCursor(0,1);
lcd.print(" NUMBER");
}
inputState = 0;
}
// If a coin is inserted, change the state to COINS
if (digitalRead(coinSlot) == LOW) {
currentState = COINS;
}
}
void displayResult(const char* message, int amount) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(message);
lcd.setCursor(0, 1);
lcd.print("Amount: ");
lcd.setCursor(8, 1);
lcd.print(amount);
delay(1000);
lcd.setCursor(0, 0);
lcd.print(" [INSERT COINS]");
inputState = 0; // Reset the input state
}
void insertCoins(){
coinSlotStatus = digitalRead(coinSlot); // wait to insert coins.
delay(30);
if (coinSlotStatus == LOW) {
digitalWrite(LED, LOW);
pulse += 1;
char lcdBuffer[16];
sprintf(lcdBuffer, "CREDITS: P %d.00", pulse);
lcd.setCursor(0, 0);
lcd.print(lcdBuffer);
delay(30); // Set the coinsInserted flag to true
}
}
void vendingItem() {
vendingStatus = digitalRead(vending);
char itemNumber[2] = {num1, num2};
int itemIndex = atoi(itemNumber) - 1; // Convert num1 and num2 to an integer and subtract 1 to get the array index
if (vendingStatus == LOW && itemIndex >= 0 && itemIndex < 20) {
oneBEEP();
int itemPrice = itemPrices[itemIndex];
if (pulse >= itemPrice) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" VENDING YOUR");
lcd.setCursor(0, 1);
lcd.print(" ITEM");
servos[itemIndex].writeMicroseconds(2500);
delay(3000);
servos[itemIndex].writeMicroseconds(1500);
twoBEEP();
// Update the coin balance
coinBalance = pulse - itemPrice;
if (coinBalance > 0) {
char lcdBuffer[16];
sprintf(lcdBuffer, "CRED. BAL. P%d.00", coinBalance);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" ITEM VENDED");
lcd.setCursor(0, 1);
lcd.print(lcdBuffer);
delay(2000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" CREDIT BALANCE");
lcd.setCursor(0, 1);
lcd.print(" IS CHANGING");
delay(2000);
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" ITEM VENDED");
char lcdBuffer[16];
sprintf(lcdBuffer, "CRED. BAL. P0.00"); // Set balance to 0.00
lcd.setCursor(0, 1);
lcd.print(lcdBuffer);
delay(2000);
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" GET YOUR ITEM");
lcd.setCursor(0, 1);
lcd.print(" THANK YOU");
delay(2000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" INPUT ITEM");
lcd.setCursor(0, 1);
lcd.print(" NUMBER");
digitalWrite(relayCoin, LOW);
pulse = 0;
currentState = KEYPAD;
} else {
// Not enough credits, display an error message
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" INSUFFICIENT");
lcd.setCursor(0, 1);
lcd.print(" CREDITS");
delay(1000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" [INSERT MORE]");
lcd.setCursor(0, 1);
lcd.print(" [COINS]");
currentState = COINS;
}
}
}
void LEDindicator(){
digitalWrite(LED, LOW);
delay(150);
digitalWrite(LED, HIGH);
delay(150);
digitalWrite(LED, LOW);
delay(150);
digitalWrite(LED, HIGH);
}
void oneBEEP(){
tone(buzz, 2200);
delay(50);
noTone(buzz);
}
void twoBEEP(){
tone(buzz, 2200);
delay(25);
noTone(buzz);
delay(70);
tone(buzz, 2200);
delay(25);
noTone(buzz);
}
void kpadTone(){
tone(buzz, 697);
delay(50);
noTone(buzz);
}
void errorTone(){
tone(buzz, 440);
delay(50);
noTone(buzz);
}