// Version: 4.1
#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// Pines de conexión
#define STEP_PIN 20
#define DIR_PIN 21
#define INCREASE_PIN 5
#define PLAY_PIN 2
#define STOP_PIN 4
#define CABIN_BUTTON_START 12
#define CABIN_BUTTON_END 19
// Configuración del motor paso a paso
#define STEPS_PER_REV 200
#define CABIN_STEPS 25
#define TOTAL_STEPS 200
// Variables de estado
int currentSteps = 0; // Posición actual en pasos
int targetSteps = 0;
int selectedLoops = 0;
bool isRunning = false;
volatile bool stopRequested = false; // Volatile para usar con interrupciones
// Configuración del LCD
#define SDA_PIN 26
#define SCL_PIN 33
LiquidCrystal_I2C lcd(0x27, 16, 2); // Dirección I2C del LCD (0x27 es común)
// Funciones auxiliares
void IRAM_ATTR handleStop() {
stopRequested = true; // Interrupción para manejar el botón "Stop"
}
void setup() {
Serial.begin(115200);
// Configurar pines
pinMode(STEP_PIN, OUTPUT);
pinMode(DIR_PIN, OUTPUT);
pinMode(INCREASE_PIN, INPUT_PULLUP);
pinMode(PLAY_PIN, INPUT_PULLUP);
pinMode(STOP_PIN, INPUT_PULLUP);
for (int i = CABIN_BUTTON_START; i <= CABIN_BUTTON_END; i++) {
pinMode(i, INPUT_PULLUP);
}
// Configurar interrupción para el botón "Stop"
attachInterrupt(digitalPinToInterrupt(STOP_PIN), handleStop, FALLING);
// Inicializar LCD
Wire.begin(SDA_PIN, SCL_PIN);
lcd.init();
lcd.backlight();
lcd.setCursor((16 - 12) / 2, 0); // Centered "Ready for"
lcd.print("Ferris Wheel By Ferdinand");
lcd.setCursor((16 - 11) / 2, 1); // Centered "Ready for"
lcd.print("Insert Coin.");
// Mensaje inicial
Serial.println("Ferris Wheel By Ferdinand Insert Coin");
}
void loop() {
if (digitalRead(INCREASE_PIN) == LOW && !isRunning) {
increaseLoops();
delay(200); // Anti-rebote
}
if (digitalRead(PLAY_PIN) == LOW && !isRunning) {
playSequence();
delay(200); // Anti-rebote
}
for (int i = CABIN_BUTTON_START; i <= CABIN_BUTTON_END; i++) {
if (digitalRead(i) == LOW) {
int cabinNumber = i - CABIN_BUTTON_START + 1;
String cabinMessage = "Cabin #" + String(cabinNumber);
lcd.clear();
lcd.setCursor((16 - cabinMessage.length()) / 2, 0); // Centered cabin message
lcd.print(cabinMessage);
delay(2000); // Show message for 2 seconds
moveToCabin(cabinNumber);
delay(200); // Anti-rebote
}
}
if (stopRequested) {
emergencyStop();
}
}
void increaseLoops() {
selectedLoops++;
String message = "Loops: " + String(selectedLoops);
lcd.clear();
lcd.setCursor((16 - message.length()) / 2, 0);
lcd.print(message);
Serial.println(message);
}
void playSequence() {
if (selectedLoops == 0) {
lcd.clear();
lcd.setCursor((16 - 12) / 2, 0); // Centered "Please insert"
lcd.print("Please insert coin");
lcd.setCursor((16 - 4) / 2, 1); // Centered "coin"
lcd.print("coin");
Serial.println("Please insert coin");
return;
}
if (currentSteps != 0) {
lcd.clear();
lcd.setCursor((16 - 7) / 2, 0); // Centered "Cabin 1..."
lcd.print("Cabin 1...");
Serial.println("Returning to Cabin 1 before starting sequence...");
moveToCabin(1);
}
lcd.clear();
lcd.setCursor((16 - 9) / 2, 0); // Centered "Boarding..."
lcd.print("Boarding...");
Serial.println("Starting passenger boarding...");
stopRequested = false;
isRunning = true;
performBoardingSequence();
performLoops();
performUnboardingSequence();
if (currentSteps != 0) {
lcd.clear();
lcd.setCursor((16 - 7) / 2, 0); // Centered "Cabin 1..."
lcd.print("Cabin 1...");
Serial.println("Returning to Cabin 1 after sequence...");
moveToCabin(1);
}
isRunning = false;
selectedLoops = 0;
lcd.clear();
lcd.setCursor((16 - 10) / 2, 0); // Centered "Ready for"
lcd.print("Ready for");
lcd.setCursor((16 - 8) / 2, 1); // Centered "new game"
lcd.print("new game");
Serial.println("Ready for new game.");
}
void performBoardingSequence() {
for (int cabin = 1; cabin <= 8; cabin++) {
if (stopRequested) return;
moveToCabin(cabin);
lcd.clear();
lcd.setCursor((16 - 13) / 2, 0); // Centered "Boarding Cabin"
lcd.print("Boarding Cabin");
lcd.setCursor((16 - 1) / 2, 1); // Centered cabin number
lcd.print(cabin);
delay(5000);
}
}
void performLoops() {
int totalStepsToMove = selectedLoops * TOTAL_STEPS;
for (int i = 0; i < totalStepsToMove; i++) {
if (stopRequested) return;
if (i % TOTAL_STEPS == 0) {
String spinMessage = "Spinning: Loop " + String(i / TOTAL_STEPS + 1);
lcd.clear();
lcd.setCursor((16 - spinMessage.length()) / 2, 0);
lcd.print(spinMessage);
Serial.println(spinMessage);
}
stepMotor(true);
}
}
void performUnboardingSequence() {
for (int cabin = 1; cabin <= 8; cabin++) {
if (stopRequested) return;
moveToCabin(cabin);
lcd.clear();
lcd.setCursor((16 - 12) / 2, 0); // Centered "Unboarding"
lcd.print("Unboarding");
lcd.setCursor((16 - 6) / 2, 1); // Centered "Cabin "
lcd.print("Cabin ");
lcd.print(cabin);
delay(5000);
}
}
void moveToCabin(int cabin) {
if (stopRequested) {
Serial.println("Motor stopped");
return;
}
int target = (cabin - 1) * CABIN_STEPS;
int stepsToMove = calculateShortestPath(target);
moveSteps(stepsToMove);
currentSteps = (currentSteps + stepsToMove + TOTAL_STEPS) % TOTAL_STEPS;
}
int calculateShortestPath(int target) {
int distance = target - currentSteps;
if (distance > TOTAL_STEPS / 2) {
distance -= TOTAL_STEPS;
} else if (distance < -TOTAL_STEPS / 2) {
distance += TOTAL_STEPS;
}
return distance;
}
void moveSteps(int steps) {
bool direction = steps > 0;
digitalWrite(DIR_PIN, direction);
for (int i = 0; i < abs(steps); i++) {
if (stopRequested) {
lcd.clear();
lcd.setCursor((16 - 14) / 2, 0); // Centered "Emergency Stop"
lcd.print("Emergency Stop");
Serial.println("Emergency stop requested. Stopping motor.");
return;
}
stepMotor(direction);
}
}
void stepMotor(bool direction) {
digitalWrite(STEP_PIN, HIGH);
delayMicroseconds(500);
digitalWrite(STEP_PIN, LOW);
delayMicroseconds(500);
}
void emergencyStop() {
lcd.clear();
lcd.setCursor((16 - 14) / 2, 0); // Centered "Emergency Stop"
lcd.print("Emergency Stop");
Serial.println("Emergency stop activated. System halted.");
stopRequested = false;
isRunning = false;
selectedLoops = 0;
lcd.setCursor((16 - 51) / 2, 1); // Centered "Ready."
lcd.print("You can now move to a specific cabin or press Play.");
Serial.println("You can now move to a specific cabin or press Play.");
}