#include <avr/io.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
LiquidCrystal_I2C lcd(0x27, 20, 04);
//pins config
#define COIN_SENSOR_PIN 2 // Coin sensor input (interrupt-capable pin)
#define BILL_ACCEPTOR_PIN 3 // Bill acceptor input (interrupt-capable pin)
#define buttonPin1 4
#define buttonPin2 5
#define buttonPin3 6
#define buttonPin4 7
#define relayPin1 8
#define relayPin2 9
#define relayPin3 10
#define relayPin4 11
#define Led1 A0
#define Led2 A1
#define Led3 A2
#define Led4 A3
#define buzzer 13
//variables
volatile int credit = 0;
int ON = 255;
int OFF = 0;
int time_left1, time_left2, time_left3, time_left4;
int credit_need[] = {10, 30, 40, 20}; //in coint
int credit_time[] = {40, 40, 40, 40}; //in seconds
int minutes ;
int seconds ;
//debounce millis
bool done_buz = true;
bool buttonState1 = true;
bool buttonState2 = true;
bool buttonState3 = true;
bool buttonState4 = true;
bool lastButtonState1 = true;
bool lastButtonState2 = true;
bool lastButtonState3 = true;
bool lastButtonState4 = true;
bool reading1, reading2, reading3, reading4;
bool run1 = false;
bool run2 = false;
bool run3 = false;
bool run4 = false;
unsigned long lastDebounceTime1 = 0;
unsigned long lastDebounceTime2 = 0;
unsigned long lastDebounceTime3 = 0;
unsigned long lastDebounceTime4 = 0;
unsigned long debounceDelay = 20;
//counter millis
unsigned long previousMillis = 0;
const long interval = 1000;
unsigned long toneDuration = 500; // Time in milliseconds for each half of the tone (on and off)
unsigned long previousMillis_tone = 0; // Variable to store the last time the tone state was changed
bool toneState = false; // Variable to store the current state of the tone
void print_lcd(int x, int y, int mint, int sec, String words);
void setting_lcd(int x, int y, int data, String words, String words1);
/////////////////////////////////////////////
uint32_t ChipID = 4294967295; /// DEVICE ID MUST be UNIQUE every board
////////////////////////////////////////////
//get ChipID must be unique
uint32_t CHIPID() {
uint32_t chipId = 0;
for (int i = 0; i < 4; i++) {
chipId |= (uint32_t)(eeprom_read_byte((uint8_t*)(0x0E + i)) << (i * 8));
}
if (chipId != ChipID) {
lcd.setCursor(0, 0);
lcd.print("NOT VALID DEVICE ID");
lcd.setCursor(0, 1);
lcd.print("CODE has a copyright");
lcd.setCursor(0, 2);
lcd.print("contact manufacturer");
lcd.setCursor(0, 3);
lcd.print("for code detail !!!");
while (1) {
if (Serial.available() > 0) {
String req = Serial.readString();
req.trim();
Serial.print("Unique ID : ");
if (req == "request ID") {
Serial.println(chipId);
}
}
}
} else {
lcd.setCursor(5, 0);
lcd.print("Like Us On ");
lcd.setCursor(6, 1);
lcd.print("Facebook");
lcd.setCursor(1, 2);
lcd.print("AB AGVM 4in1 Timer");
}
delay(2000);
}
void setup() {
Serial.begin(115200);
lcd.init();
lcd.backlight();
CHIPID();
lcd.setCursor(2, 3);
lcd.print("!! Thank You !!");
delay(2000);
lcd.clear();
pinMode(COIN_SENSOR_PIN, INPUT);
pinMode(buttonPin1, INPUT_PULLUP);
pinMode(buttonPin2, INPUT_PULLUP);
pinMode(buttonPin3, INPUT_PULLUP);
pinMode(buttonPin4, INPUT_PULLUP);
pinMode(relayPin1, OUTPUT);
pinMode(relayPin2, OUTPUT);
pinMode(relayPin3, OUTPUT);
pinMode(relayPin4, OUTPUT);
pinMode(Led1, OUTPUT);
pinMode(Led2, OUTPUT);
pinMode(Led3, OUTPUT);
pinMode(Led4, OUTPUT);
pinMode(buzzer, OUTPUT);
pinMode(BILL_ACCEPTOR_PIN, INPUT_PULLUP); // Bill acceptor input (interrupt-capable pin)
//interrupt call
attachInterrupt(digitalPinToInterrupt(COIN_SENSOR_PIN), coinInterrupt, RISING);
attachInterrupt(digitalPinToInterrupt(BILL_ACCEPTOR_PIN),billInterupt, FALLING);
int v = EEPROM.read(1);
Serial.println(v);
// if (v != 255) {
Serial.println("get eeprom value");
EEPROM.get(1, credit_need[0]);
delay(10);
EEPROM.get(20, credit_need[1]);
delay(10);
EEPROM.get(40, credit_need[2]);
delay(10);
EEPROM.get(60, credit_need[3]);
delay(10);
EEPROM.get(80, credit_time[0]);
delay(10);
EEPROM.get(100, credit_time[1]);
delay(10);
EEPROM.get(120, credit_time[2]);
delay(10);
EEPROM.get(140, credit_time[3]);
delay(10);
// }
//making sure relays are off on load
for (int i = 8; i <= 11; i++) {
digitalWrite(i, LOW);
delay(10);
}
tone(buzzer, 1000);
delay(50);
noTone(buzzer);
delay(50);
tone(buzzer, 1000);
delay(50);
noTone(buzzer);
delay(50);
tone(buzzer, 1000);
delay(50);
noTone(buzzer);
delay(50);
tone(buzzer, 1000);
delay(50);
noTone(buzzer);
lcd.clear();
sense_click();
if (!reading4) {
setting();
}
}
void loop() {
clicks();
countdown();
//led ON or OFF
analogWrite(Led1, (credit >= credit_need[0]) ? ON : OFF);
analogWrite(Led2, (credit >= credit_need[1]) ? ON : OFF);
analogWrite(Led3, (credit >= credit_need[2]) ? ON : OFF);
analogWrite(Led4, (credit >= credit_need[3]) ? ON : OFF);
lcd.setCursor(0, 0);
lcd.print("Credit Amount: ");
lcd.print(credit);
lcd.print(" ");
}
//interrupt call
void addcoin() {
credit ++;
}
void sense_click() {
reading1 = digitalRead(buttonPin1);
reading2 = digitalRead(buttonPin2);
reading3 = digitalRead(buttonPin3);
reading4 = digitalRead(buttonPin4);
}
void clicks() {
sense_click();
if (reading1 != lastButtonState1) {
lastDebounceTime1 = millis();
}
if (reading2 != lastButtonState2) {
lastDebounceTime2 = millis();
}
if (reading3 != lastButtonState3) {
lastDebounceTime3 = millis();
}
if (reading4 != lastButtonState4) {
lastDebounceTime4 = millis();
}
//button 1 debounce
if ((millis() - lastDebounceTime1) > debounceDelay
&& credit >= credit_need[0]/* && !run1*/) {
if (reading1 != buttonState1) {
buttonState1 = reading1;
if (buttonState1 == LOW) {
//Serial.println("Button 1 pressed!");
// Do any additional actions here
credit -= credit_need[0];
time_left1 == 0 ? +1 : +0; //offset in 1st run
time_left1 += credit_time[0];
run1 = true;
digitalWrite(relayPin1, LOW);
}
}
}
//button 2 debounce
if ((millis() - lastDebounceTime2) > debounceDelay
&& credit >= credit_need[1]/* && !run2*/) {
if (reading2 != buttonState2) {
buttonState2 = reading2;
if (buttonState2 == LOW) {
//Serial.println("Button 2 pressed!");
// Do any additional actions here
credit -= credit_need[1];
time_left2 == 0 ? +1 : +0;
time_left2 += credit_time[1];
run2 = true;
digitalWrite(relayPin2, LOW);
}
}
}
//button 3 debounce
if ((millis() - lastDebounceTime3) > debounceDelay
&& credit >= credit_need[2]/* && !run3*/) {
if (reading3 != buttonState3) {
buttonState3 = reading3;
if (buttonState3 == LOW) {
//Serial.println("Button 3 pressed!");
// Do any additional actions here
credit -= credit_need[2];
time_left3 == 0 ? +1 : +0;
time_left3 += credit_time[2];
run3 = true;
digitalWrite(relayPin3, LOW);
}
}
}
//button 4 debounce
if ((millis() - lastDebounceTime4) > debounceDelay
&& credit >= credit_need[3]/* && !run4*/) {
if (reading4 != buttonState4) {
buttonState4 = reading4;
if (buttonState4 == LOW) {
//Serial.println("Button 4 pressed!");
// Do any additional actions here
credit -= credit_need[3];
time_left4 == 0 ? +1 : +0;
time_left4 += credit_time[3];
run4 = true;
digitalWrite(relayPin4, LOW);
}
}
}
lastButtonState1 = reading1;
lastButtonState2 = reading2;
lastButtonState3 = reading3;
lastButtonState4 = reading4;
}
void countdown() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
run1 == true ? time_left1 -- : time_left1 = time_left1 ;
run2 == true ? time_left2 -- : time_left2 = time_left2 ;
run3 == true ? time_left3 -- : time_left3 = time_left3 ;
run4 == true ? time_left4 -- : time_left4 = time_left4 ;
}
minutes = time_left1 / 60;
seconds = time_left1 % 60;
print_lcd(0, 2, minutes, seconds, "B1: ");
if (minutes == 0 && seconds == 0) {
run1 = false;
time_left1 = 0;
digitalWrite(relayPin1, HIGH);
}
minutes = time_left2 / 60;
seconds = time_left2 % 60;
print_lcd(0, 3, minutes, seconds, "B2: ");
if (minutes == 0 && seconds == 0) {
run2 = false;
time_left2 = 0;
digitalWrite(relayPin2, HIGH);
}
minutes = time_left3 / 60;
seconds = time_left3 % 60;
print_lcd(10, 2, minutes, seconds, "B3: ");
if (minutes == 0 && seconds == 0) {
run3 = false;
time_left3 = 0;
digitalWrite(relayPin3, HIGH);
}
minutes = time_left4 / 60;
seconds = time_left4 % 60;
print_lcd(10, 3, minutes, seconds, "B4: ");
if (minutes == 0 && seconds == 0) {
run4 = false;
time_left4 = 0;
digitalWrite(relayPin4, HIGH);
}
if ( time_left1 < 30 && time_left1 > 25
|| time_left1 < 6 && time_left1 > 1 ) {
Alarm(1000);
}
if ( time_left2 < 30 && time_left2 > 25
|| time_left2 < 6 && time_left2 > 1 ) {
Alarm(1500);
}
if ( time_left3 < 30 && time_left3 > 25
|| time_left3 < 6 && time_left3 > 1 ) {
Alarm(2000);
}
if ( time_left4 < 30 && time_left4 > 25
|| time_left4 < 6 && time_left4 > 1 ) {
Alarm(2500);
}
}
//function for time remain
void print_lcd(int x, int y, int mint, int sec, String words) {
lcd.setCursor(x, y);
lcd.print(words);
lcd.print(mint);
lcd.print(":");
lcd.print(sec);
lcd.print(" "); //eraser
}
void setting_lcd(int x, int y, int data, String words, String words1) {
lcd.setCursor(x, y);
lcd.print(words);
lcd.print(data);
if (data < 100 && data >= 10) {
lcd.print(" ");
}
if (data < 10) {
lcd.print(" ");
}
lcd.print(words1);
}
void setting() {
pass_code();
menus();
}
void pass_code() {
lcd.setCursor(0, 0);
lcd.print("Settings");
delay(3000);
int pass1 = 0;
int pass2 = 0;
int pass3 = 0;
lcd.clear();
while (1) {
sense_click();
if (reading1 != lastButtonState1) {
lastDebounceTime1 = millis();
}
if (reading2 != lastButtonState2) {
lastDebounceTime2 = millis();
}
if (reading3 != lastButtonState3) {
lastDebounceTime3 = millis();
}
if (reading4 != lastButtonState4) {
lastDebounceTime4 = millis();
}
//button 1 debounce
if ((millis() - lastDebounceTime1) > debounceDelay) {
if (reading1 != buttonState1) {
buttonState1 = reading1;
if (buttonState1 == LOW) {
Serial.print("pass 1 pressed! ");
// Do any additional actions here
pass1 = constrain(pass1 + 1, 0, 10);
pass1 = pass1 > 9 ? 0 : pass1 ;
Serial.println(pass1);
}
}
}
//button 2 debounce
if ((millis() - lastDebounceTime2) > debounceDelay) {
if (reading2 != buttonState2) {
buttonState2 = reading2;
if (buttonState2 == LOW) {
Serial.print("pass 2 pressed! ");
// Do any additional actions here
pass2 = constrain(pass2 + 1, 0, 10);
pass2 = pass2 > 9 ? 0 : pass2 ;
Serial.println(pass2);
}
}
}
//button 3 debounce
if ((millis() - lastDebounceTime3) > debounceDelay) {
if (reading3 != buttonState3) {
buttonState3 = reading3;
if (buttonState3 == LOW) {
Serial.print("pass 3 pressed! ");
// Do any additional actions here
pass3 = constrain(pass3 + 1, 0, 10);
pass3 = pass3 > 9 ? 0 : pass3 ;
Serial.println(pass3);
}
}
}
//button 4 debounce
if ((millis() - lastDebounceTime4) > debounceDelay) {
if (reading4 != buttonState4) {
buttonState4 = reading4;
if (buttonState4 == LOW) {
Serial.println("Enter pressed!");
// Do any additional actions here
if (pass1 == 2 && pass2 == 3 && pass3 == 4) {
lcd.setCursor(0, 3);
lcd.print("Passcode Match");
delay(2000);
lcd.clear();
break;
} else {
lcd.setCursor(0, 3);
lcd.print("Passcode Mismatch");
delay(2000);
for (int i = 0; i < 20; i++) {
lcd.setCursor(i, 3);
lcd.print(" ");
delay(1);
}
}
}
}
}
lastButtonState1 = reading1;
lastButtonState2 = reading2;
lastButtonState3 = reading3;
lastButtonState4 = reading4;
lcd.setCursor(0, 0);
lcd.print("Passcode");
lcd.setCursor(0, 2);
lcd.print(pass1);
lcd.print(" ");
lcd.print(pass2);
lcd.print(" ");
lcd.print(pass3);
}
}
void menus() {
lcd.setCursor(0, 0);
lcd.print("ongoing settings");
delay(2000);
lcd.clear();
int Switch = 0;
int index = 0;
bool clear = false;
while (1) {
sense_click();
//set index according to case number
index = Switch == 0 || Switch == 1 ? 0 : index;
index = Switch == 2 || Switch == 3 ? 1 : index;
index = Switch == 4 || Switch == 5 ? 2 : index;
index = Switch == 6 || Switch == 7 ? 3 : index;
//option to clear lcd when in exit option menu
clear = Switch != 8 ? false : true;
//Serial.println(index);
if (!reading1) {
Switch = constrain(Switch - 1, -1, 10);
Switch = Switch == -1 ? 8 : Switch;
delay(50);
}
if (!reading4) {
Switch = constrain(Switch + 1, 0, 10);
Switch = Switch > 9 ? 0 : Switch;
delay(50);
}
if (!reading2) {
//Serial.println(index);
if (Switch == 0 || Switch == 2 || Switch == 4 || Switch == 6) {
credit_need[index] = constrain(credit_need[index] + 1, 1, 999);
//Serial.println("credit_need");
} else {
credit_time[index] = constrain(credit_time[index] + 1, 1, 999);
// Serial.println("credit_time");
}
if (Switch == 8) {
lcd.clear();
break;
}
}
if (!reading3) {
//Serial.println(index);
if (Switch == 0 || Switch == 2 || Switch == 4 || Switch == 6) {
credit_need[index] = constrain(credit_need[index] - 1, 1, 999);
// Serial.println("credit_need");
} else {
credit_time[index] = constrain(credit_time[index] - 1, 1, 999);
//Serial.println("credit_time");
}
if (Switch == 8) {
lcd.clear();
break;
}
}
switch (Switch) {
//notice that other has 2 space and other only 1 in '" "' it is use to erase < arrows
case 0:
setting_lcd(0, 0, credit_need[0], "B1 C:", " <");
setting_lcd(0, 1, credit_time[0], "B1 T:", " ");
setting_lcd(0, 2, credit_need[1], "B2 C:", " ");
setting_lcd(0, 3, credit_time[1], "B2 T:", " ");
setting_lcd(10, 0, credit_need[2], "B3 C:", " ");
setting_lcd(10, 1, credit_time[2], "B3 T:", " ");
setting_lcd(10, 2, credit_need[3], "B4 C:", " ");
setting_lcd(10, 3, credit_time[3], "B4 T:", " ");
break;
case 1:
setting_lcd(0, 0, credit_need[0], "B1 C:", " ");
setting_lcd(0, 1, credit_time[0], "B1 T:", " <");
setting_lcd(0, 2, credit_need[1], "B2 C:", " ");
setting_lcd(0, 3, credit_time[1], "B2 T:", " ");
setting_lcd(10, 0, credit_need[2], "B3 C:", " ");
setting_lcd(10, 1, credit_time[2], "B3 T:", " ");
setting_lcd(10, 2, credit_need[3], "B4 C:", " ");
setting_lcd(10, 3, credit_time[3], "B4 T:", " ");
break;
case 2:
setting_lcd(0, 0, credit_need[0], "B1 C:", " ");
setting_lcd(0, 1, credit_time[0], "B1 T:", " ");
setting_lcd(0, 2, credit_need[1], "B2 C:", " <");
setting_lcd(0, 3, credit_time[1], "B2 T:", " ");
setting_lcd(10, 0, credit_need[2], "B3 C:", " ");
setting_lcd(10, 1, credit_time[2], "B3 T:", " ");
setting_lcd(10, 2, credit_need[3], "B4 C:", " ");
setting_lcd(10, 3, credit_time[3], "B4 T:", " ");
break;
case 3:
setting_lcd(0, 0, credit_need[0], "B1 C:", " ");
setting_lcd(0, 1, credit_time[0], "B1 T:", " ");
setting_lcd(0, 2, credit_need[1], "B2 C:", " ");
setting_lcd(0, 3, credit_time[1], "B2 T:", " <");
setting_lcd(10, 0, credit_need[2], "B3 C:", " ");
setting_lcd(10, 1, credit_time[2], "B3 T:", " ");
setting_lcd(10, 2, credit_need[3], "B4 C:", " ");
setting_lcd(10, 3, credit_time[3], "B4 T:", " ");
break;
case 4:
setting_lcd(0, 0, credit_need[0], "B1 C:", " ");
setting_lcd(0, 1, credit_time[0], "B1 T:", " ");
setting_lcd(0, 2, credit_need[1], "B2 C:", " ");
setting_lcd(0, 3, credit_time[1], "B2 T:", " ");
setting_lcd(10, 0, credit_need[2], "B3 C:", " <");
setting_lcd(10, 1, credit_time[2], "B3 T:", " ");
setting_lcd(10, 2, credit_need[3], "B4 C:", " ");
setting_lcd(10, 3, credit_time[3], "B4 T:", " ");
break;
case 5:
setting_lcd(0, 0, credit_need[0], "B1 C:", " ");
setting_lcd(0, 1, credit_time[0], "B1 T:", " ");
setting_lcd(0, 2, credit_need[1], "B2 C:", " ");
setting_lcd(0, 3, credit_time[1], "B2 T:", " ");
setting_lcd(10, 0, credit_need[2], "B3 C:", " ");
setting_lcd(10, 1, credit_time[2], "B3 T:", " <");
setting_lcd(10, 2, credit_need[3], "B4 C:", " ");
setting_lcd(10, 3, credit_time[3], "B4 T:", " ");
break;
case 6:
setting_lcd(0, 0, credit_need[0], "B1 C:", " ");
setting_lcd(0, 1, credit_time[0], "B1 T:", " ");
setting_lcd(0, 2, credit_need[1], "B2 C:", " ");
setting_lcd(0, 3, credit_time[1], "B2 T:", " ");
setting_lcd(10, 0, credit_need[2], "B3 C:", " ");
setting_lcd(10, 1, credit_time[2], "B3 T:", " ");
setting_lcd(10, 2, credit_need[3], "B4 C:", " <");
setting_lcd(10, 3, credit_time[3], "B4 T:", " ");
break;
case 7:
setting_lcd(0, 0, credit_need[0], "B1 C:", " ");
setting_lcd(0, 1, credit_time[0], "B1 T:", " ");
setting_lcd(0, 2, credit_need[1], "B2 C:", " ");
setting_lcd(0, 3, credit_time[1], "B2 T:", " ");
setting_lcd(10, 0, credit_need[2], "B3 C:", " ");
setting_lcd(10, 1, credit_time[2], "B3 T:", " ");
setting_lcd(10, 2, credit_need[3], "B4 C:", " ");
setting_lcd(10, 3, credit_time[3], "B4 T:", " <");
break;
case 8:
if (!clear) {
delay(100);
lcd.clear();
clear = true;
}
lcd.setCursor(0, 0);
lcd.print("Exit <");
break;
}
}
lcd.setCursor(0, 0);
lcd.print("Saving data !!!!!!!!");
EEPROM.put(1, credit_need[0]);
delay(10);
EEPROM.put(20, credit_need[1]);
delay(10);
EEPROM.put(40, credit_need[2]);
delay(10);
EEPROM.put(60, credit_need[3]);
delay(10);
EEPROM.put(80, credit_time[0]);
delay(10);
EEPROM.put(100, credit_time[1]);
delay(10);
EEPROM.put(120, credit_time[2]);
delay(10);
EEPROM.put(140, credit_time[3]);
delay(2000);
lcd.clear();
}
void Alarm(int pitch) {
unsigned long currentMillis = millis(); // Get the current time in milliseconds
// Check if it's time to change the tone state
if (currentMillis - previousMillis_tone >= toneDuration) {
previousMillis_tone = currentMillis; // Update the previous time
toneState = !toneState; // Toggle the tone state (on or off)
if (toneState) {
// Turn on the tone
tone(buzzer, pitch);
} else {
// Turn off the tone
noTone(buzzer);
}
}
}