Mettere in pausa un programma

Salve.
Avrei bisogno di aiuto per quanto riguarda un progettino.
Ho un motorino che gira per x secondi; in qualsiasi momento vorrei essere in grado di premere un pulsante per metterlo in pausa; ripremendo il pulsante voglio che riprenda a girare per il tempo rimanente. Ad esempio: imposto 5 secondi di rotazione, dopo due secondi premo pausa-> il motore si ferma; se ripremo quel pulsante deve fare altri 3 secondi di rotazione. Io pensavo di usare una funzione pausa() che conta il tempo trascorso in pausa e dopo sottrae a millis() il valore calcolato, ma il problema è proprio che non so se si possa fare una simile operazione (inteso sottrarre un valore a millis()). Qualcuno ha un'idea migliore della mia? Ne sarei grato

In generale fai prima a provarlo che a chiedere XD

In ogni caso io farei

un booleano che tiene in memoria se si è in pausa, col fronte di salita del pulsante inverti lo stato.
Calcoli il tempo impiegato nell’ultimo ciclo (che solitamente chiamo dt) usando una variabile statica e l’interrogazione a millis
Crei una seconda variabile che indica il tempo rimanente in rotazione: se > 0 e la pausa è disattiva fai girare il motore e sottrai al tempo dt; se <= 0 blocchi il motore

Ciao

Non puoi sottrarre il valore a millis, io farei così:
Parte il motorino memorizzo il valore di millis(), premo il pulsante prendo il valore attuale di millis() e calcolo quanto tempo ha girato e lo memorizzo.
Quando premi di nuovo il pulsante sottrai al tempo totale che il motorino dovrebbe girare (5 secondi secondo il tuo esempio) il tempo che hai memorizzato prima come differenza di millis, e come tempo di avvio il millis attuale.
Il controllo che dovresti aver implementato nella parte che gestisce la rotazione del motore farà il resto senza ulteriori modifiche.
Se così non è, o non è chiaro, posta il codice che usi che magari si riesce ad aiutarti meglio

Ecco il codice, non l'ho provato... Ma dovrebbe funzionare :slight_smile:

const byte pulsantePin = 13;
const byte motorePin = 2;
volatile bool staGirando = false;

const unsigned long tempoMassimo = 5000;
unsigned long tempoTrascorso = 5000;
volatile unsigned long ultimoTempo = 0;

void setup() {
 pinMode(motorePin, OUTPUT);
 pinMode(pulsantePin, INPUT_PULLUP);
 attachInterrupt(digitalPinToInterrupt(pulsantePin), premuto, FALLING);
}

void loop() {
  if(staGirando) {
    if((millis() - ultimoTempo) + tempoTrascorso > tempoMassimo) {
      digitalWrite(motorePin, LOW);
      staGirando = false;
    }
  }
}

void premuto() {
  if(staGirando) {
    digitalWrite(motorePin, LOW);
    tempoTrascorso += millis() - ultimoTempo; // memorizza tempo
  }
  else {
    digitalWrite(motorePin, HIGH);
    if(tempoTrascorso >= tempoMassimo) { // resetta
      tempoTrascorso = 0;
    }
    ultimoTempo = millis();
  }
  staGirando = !staGirando;
}

Mattia9914:
Ho un motorino che gira per x secondi; in qualsiasi momento vorrei essere in grado di premere un pulsante per metterlo in pausa; ripremendo il pulsante voglio che riprenda a girare per il tempo rimanente.

Secondo me il modo più semplice per risolvere questo problema (come tanti altri simili che richiedono un avanzamento a fasi/situazioni più o meno temporizzate), è ragionare a fasi/situazioni esprimendole bene in italiano. Quando la logica in italiano (espressa con i vincoli delle cose comprensibili dalla macchina) funziona, il resto e` mera traduzione sintattica. È semplice: in quali situazioni mi posso trovare? A quali eventi devo stare attento in ogni situazione? Che azioni devo compiere in risposta ad un evento? In quale nuova situazione posso eventualmente trovarmi? Come dice un altro utente del forum: così c'est plus facile:

SE situazione FERMO:
    SE clic:                           // primo avvio
        azzera totale tempo trascorso girando
        salva tempo inizio gira da millis
        situazione = GIRA

ALTRIMENTI SE situazione GIRA:
    parziale = millis() - inizio
    SE totale+parziale >= DURATA:      // timeout, si ferma
        fase = FERMO
    ALTRIMENTI SE clic:                // mette in pausa
        totale += parziale
        situazione = PAUSA

ALTRIMENTI SE situazione PAUSA:
    SE clic:                           // riparte da pausa
        salva tempo inizio gira da millis
        situazione = GIRA

Rimane solo da valorizzare la variabile 'clic' a true (per un ciclo di programma) nel momento in cui il pulsante viene premuto (basta confrontare se al ciclo precedente non era premuto), e da comandare l'uscita, anche questo semplice: uscita attiva solo se la situazione corrisponde a GIRA.

Naturalmente questa logica funziona solo se si lascia il loop libero di girare alla massima velocità, senza bloccarlo con istruzioni delay sparse in giro. Importante: Ogni tempo o ritardo o attesa si realizza NON con delay, ma permanendo in una situazione finché non avviene un evento che fa passare ad un'altra situazione.