#include <AccelStepper.h>
#include <EEPROM.h>
#include <LiquidCrystal.h>
const int rs = 25, en = 26, d4 = 27, d5 = 14, d6 = 12, d7 = 13;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
const int stepPin = 17;
const int dirPin = 16;
AccelStepper stepper(AccelStepper::DRIVER, stepPin, dirPin);
const int btnOrario = 18;
const int btnAntiorario = 19;
const int btnSalva = 21;
const int btnVaiA = 22;
const float stepPerMM = 100.0;
const int stepIncrement = 100; // Incremento/decremento per i movimenti manuali
const int maxPosizioni = 10;
long posizioni[maxPosizioni]; // Array per memorizzare le posizioni
int posSalvate = 0; // Numero effettivo di posizioni salvate
int indiceCorrente = 0; // Indice della *prossima* posizione nel ciclo "Vai"
int indiceVisualizzato = 0; // Indice della posizione *attualmente* mostrata all'utente
long posizioneAttuale = 0; // Posizione attuale del motore (in steps)
long offsetPosizione = 3000; // Offset iniziale o posizione di riferimento
const int eepromStart = 0; // Indirizzo di partenza in EEPROM per i dati
const unsigned long interval = 75; // Intervallo per i movimenti manuali
unsigned long lastMoveTime = 0;
long targetPosition = 0; // Posizione target per lo stepper
unsigned long lastUpdateDisplay; // Ultimo aggiornamento del display
unsigned long salvaPressStart = 0;
bool salvaAttivo = false; // Flag per il long press del tasto Salva
void setup() {
Serial.begin(9600);
lcd.begin(16, 4);
lcd.print("Sistema pronto");
delay(1000);
stepper.setMaxSpeed(2500); // Velocità massima del motore
stepper.setAcceleration(1000); // Accelerazione del motore
// Configurazione dei pin dei pulsanti con pull-up interni
pinMode(btnOrario, INPUT_PULLUP);
pinMode(btnAntiorario, INPUT_PULLUP);
pinMode(btnSalva, INPUT_PULLUP);
pinMode(btnVaiA, INPUT_PULLUP);
// Carica il numero di posizioni salvate dalla EEPROM
EEPROM.get(eepromStart, posSalvate);
// Validazione: se il valore è fuori range, azzera
if (posSalvate < 0 || posSalvate > maxPosizioni) {
posSalvate = 0;
}
// Carica le posizioni effettive dalla EEPROM
for (int i = 0; i < posSalvate; i++) {
// Le posizioni sono salvate dopo il numero di posizioni (sizeof(int))
EEPROM.get(eepromStart + sizeof(int) + (i * sizeof(long)), posizioni[i]);
}
// Inizializza la posizione attuale e il target
if (posSalvate == 0) {
posizioneAttuale = offsetPosizione;
posizioni[0] = offsetPosizione; // Per visualizzazione iniziale
} else {
posizioneAttuale = posizioni[0];
}
stepper.setCurrentPosition(posizioneAttuale);
targetPosition = posizioneAttuale;
indiceCorrente = 0; // La prossima piega da richiamare sarà la prima
indiceVisualizzato = 0; // Il display mostrerà la prima piega
lcd.clear();
updateDisplay(); // Aggiorna il display con lo stato iniziale
}
void loop() {
stepper.run();
bool orarioPressed = digitalRead(btnOrario) == LOW;
bool antiorarioPressed = digitalRead(btnAntiorario) == LOW;
bool salvaPressed = digitalRead(btnSalva) == LOW;
bool vaiPressed = digitalRead(btnVaiA) == LOW;
static bool salvaPrev = false;
static bool vaiPrev = false;
static bool salvato = false;
unsigned long currentMillis = millis();
// --- Reset della lista se Salva + Vai sono premuti insieme ---
if (salvaPressed && vaiPressed) {
resetListaEEPROM();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("EEPROM RESET!");
delay(1000);
updateDisplay();
return;
}
// --- Movimento manuale con pulsanti Orario e Antiorario ---
if (orarioPressed && currentMillis - lastMoveTime >= interval) {
targetPosition -= stepIncrement;
lastMoveTime = currentMillis;
// Quando si muove manualmente, la posizione attuale è la posizione visualizzata
indiceVisualizzato = -1; // Flag per indicare che non si è su una piega salvata
// o aggiorna indiceVisualizzato alla piega salvata più vicina
// ma per ora, -1 indica "non una piega salvata"
updateDisplay(); // Aggiorna immediatamente il display sulla posizione manuale
}
if (antiorarioPressed && currentMillis - lastMoveTime >= interval) {
targetPosition += stepIncrement;
lastMoveTime = currentMillis;
indiceVisualizzato = -1; // Flag per indicare che non si è su una piega salvata
updateDisplay(); // Aggiorna immediatamente il display sulla posizione manuale
}
// Aggiornamento display quando lo stepper non è in movimento e dopo un certo tempo
// (utile per visualizzare la posizione finale dopo un moveTo, o per movimenti manuali)
if (currentMillis - lastUpdateDisplay >= 500 && !stepper.isRunning()) {
lastUpdateDisplay = currentMillis;
// Se indiceVisualizzato è -1 (movimento manuale), assicurati che la posizione sia mostrata
if(indiceVisualizzato == -1) {
// Puoi trovare la piega più vicina se vuoi, altrimenti mostra solo la posizione
// Per semplicità, qui mostriamo solo la posizione
// Se si è fermato su una piega, si potrebbe cercare quale è.
}
posizioneAttuale = stepper.currentPosition();
updateDisplay(); // Ricarica il display per mostrare la posizione attuale
}
stepper.moveTo(targetPosition);
// --- Gestione del pulsante Salva (long press per salvare) ---
if (salvaPressed && !vaiPressed) {
if (!salvaPrev) {
salvaPressStart = currentMillis;
salvaAttivo = false;
salvato = false;
} else if (!salvaAttivo && (currentMillis - salvaPressStart >= 1000)) {
salvaAttivo = true;
if (posSalvate < maxPosizioni) {
posizioni[posSalvate] = stepper.currentPosition();
posSalvate++;
EEPROM.put(eepromStart, posSalvate);
for (int i = 0; i < posSalvate; i++) {
EEPROM.put(eepromStart + sizeof(int) + (i * sizeof(long)), posizioni[i]);
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Salvato piega:");
lcd.print(posSalvate);
lcd.setCursor(0, 1);
lcd.print(stepper.currentPosition() / stepPerMM, 2);
lcd.print(" mm");
delay(500);
salvato = true;
// Dopo il salvataggio, l'indice visualizzato è l'ultima piega salvata
indiceVisualizzato = posSalvate - 1; // Mostra l'ultima piega salvata
indiceCorrente = 0; // Il prossimo "Vai" partirà dalla prima piega
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("LISTA PIENA!");
delay(1000);
}
} else if (!salvato) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("SALVATAGGIO!");
lcd.setCursor(0, 1);
lcd.print((currentMillis - salvaPressStart) / 1000.0, 1);
lcd.print(" sec");
}
}
salvaPrev = salvaPressed;
// --- Gestione del pulsante Vai (scorre le posizioni salvate) ---
if (vaiPressed && !vaiPrev && !salvaPressed && posSalvate > 0 && !stepper.isRunning()) {
// Assicurati che indiceCorrente sia valido prima di usarlo
if (indiceCorrente >= posSalvate) {
indiceCorrente = 0; // Torna alla prima posizione se l'indice è fuori range
}
// Aggiorna l'indice che verrà visualizzato con la posizione a cui stiamo andando
indiceVisualizzato = indiceCorrente;
targetPosition = posizioni[indiceCorrente];
stepper.moveTo(targetPosition);
// Aggiorna il display SUBITO per mostrare la piega che sta per essere raggiunta
updateDisplay();
// Prepara indiceCorrente per la *prossima* pressione del pulsante "Vai"
indiceCorrente = (indiceCorrente + 1) % posSalvate;
delay(300);
}
vaiPrev = vaiPressed;
}
// --- Funzioni Ausiliarie ---
void updateDisplay() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Piega N:");
if (posSalvate == 0) {
lcd.print("0 di 0");
} else {
// Se indiceVisualizzato è -1 (movimento manuale o non su una piega salvata), non mostrare indice
if (indiceVisualizzato == -1) {
lcd.print("<---->"); // O un altro messaggio che indichi che non è una piega numerata
} else {
lcd.print(indiceVisualizzato + 1); // Usa indiceVisualizzato per la stampa
lcd.print(" di ");
lcd.print(posSalvate);
}
}
lcd.setCursor(0, 1);
lcd.print("Pos: ");
lcd.print(stepper.currentPosition() / stepPerMM, 2);
lcd.print(" mm");
}
void resetListaEEPROM() {
posSalvate = 0;
indiceCorrente = 0;
indiceVisualizzato = 0; // Reset anche qui
for (int i = 0; i < maxPosizioni; i++) {
posizioni[i] = 0;
}
EEPROM.put(eepromStart, posSalvate);
}