Creare "sottoloop" indipendenti

Ciao a tutti,

se per esempio devo fare lampeggiare alternativamente 2 LED il programma qui sotto esegue l'operazione senza problemi:

const int led1 = 8;
const int led2 = 9;

void setup () {
	pinMode(led8, OUTPUT);
	pinMode(led2, OUTPUT);
}

void loop () {
	digitalWrite(led1, HIGH);
	delay(300);
	digitalWrite(led1, LOW);
	delay(300);
	digitalWrite(led2, HIGH);
	delay(300);
	digitalWrite(led2, LOW);
	delay(300);
}

Ma se voglio aggiungere un terzo LED che lampeggia molto più lentamente questa pausa interferisce con i led1 e led2:

const int led1 = 8;
const int led2 = 9;

const int led3 = 10;

void setup () {
	pinMode(led8, OUTPUT);
	pinMode(led2, OUTPUT);

	pinMode(led3, OUTPUT);
}



void loop () {
	digitalWrite(led1, HIGH);
	delay(300);
	digitalWrite(led1, LOW);
	delay(300);
	digitalWrite(led2, HIGH);
	delay(300);
	digitalWrite(led2, LOW);
	delay(300);
	
	digitalWrite(led3, LOW);
	delay(5000);
	digitalWrite(led3, HIGH);
	delay(5000);

}

C'è un modo per creare una specie di "sottoloop" indipendente? Non ci arrivo..

Non servono 2 loop().
Serve gestire il tempo in modo non bloccante.
Prova a guardare l'esempio dell'ide "blink without delay" e vedi come usano millis() per far lampeggiare un led.

1 Like

Dimentica la funzione delay() ... come ti hanno già detto, devi studiarti come si usa la funzione millis(), prima QUI, poi QUI e QUI e QUI e tutti gli articoli che sono in QUESTA pagina ... vedrai che poi ti sarà tutto più chiaro :wink:

Guglielmo

1 Like

Fantastico grazie mille!

Sono un po' in difficoltà, ho letto diversi tutorial pratici e replicando un esercizio di esempio come questo:

unsigned long t1, dt1;
unsigned long t2, dt2;

int tled1 = 600;
int tled2 = 150;

int st1 = LOW;
int st2 = LOW;

void setup() {
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
}

void loop() {
  dt1 = millis() - t1;
  if (dt1 > tled1) {
    st1 = !st1;
    digitalWrite(12, st1);
    t1 = millis();
  }

  dt2 = millis() - t2;
  if (dt2 > tled2) {
    st2 = !st2;
    digitalWrite(13, st2);
    t2 = millis();
  }
}

quello che ottengo è il funzionamento di 2 LED con frequenza di lampeggio indipendente.

Tutto benissimo ma se il tempo di tled1 è di 600ms questo tempo è uguale sia per il tempo di accensione che di spegnimento e io vorrei poter avere il controllo sia del tempo di accensione che di spegnimento.
Se aggiungo un ritardo di 1 secondo, esempio delay(1000); ovviamente cade lo scopo di usare la funzione millis()

Quello che mi è venuto in mente è di creare una variabile, esempio tled1pause = 2000; e inserirla a fine conteggio del LED t1, allo scopo di creare un ritardo di 2 scondi sempre senza interferire col LED t2, ma ovviamente sto pasticciando e non funziona.

Molto probabilmente mi sono incartato.. non riesco a capire come fare

Avrai letto anche i tutorials, ma mi sembra che non hai però ben appreso come usare millis(), difatti, il IF che usi NON è quello che è nei tutorial e così non va molto bene ... :roll_eyes:

if ( millis() - tempoPrecedente > tempoDaAttendere ) {
   ...
   ... // qui quello che si deve fare
   ...
   tempoPrecedente = millis();
}

Questa è la forma corretta del IF per usare millis() ...

Guglielmo

Ancora, per capire ancora meglio millis() prova a leggere anche QUI e QUI :wink:

Guglielmo

Il valore di tled1 lo puoi modificare dentro la if, tipo così:

dt1 = millis() - t1;
  if (dt1 > tled1) {
    if (st1) {
        tled1 = 900;
    } else {
        tled1 = 600;
    }
    st1 = !st1;
    digitalWrite(12, st1);
    t1 = millis();
  }

Ciao.

1 Like

... che è ancora una "forma" che spreca variabili e NON è quella sempre consigliata ed ottimizzata del IF per millis() ... :grin:

Guglielmo

Perché? Quale variabile?

dt1 è nello stack e lo sarebbe comunque poiché il risultato di questo calcolo ( millis() - tempoPrecedente) in qualche posto il compilatore deve metterlo.

Ciao.

Ciao, tu hai usato un cliclo nidificato per modificare, e aggiungerle nel ciclo, le variabili tled1 e tled2. Ho provato a replicare il tuo codice:

unsigned long t1, dt1;
unsigned long t2, dt2;

int tled1 = 600;
int tled2 = 350;

int st1 = LOW;
int st2 = LOW;

void setup() {
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
}

void loop() {

// LED 1
dt1 = millis() - t1;
  
  if (dt1 > tled1) {
    if (st1) {
        tled1 = 800; //OFF
    } else {
        tled1 = 100; //ON
    }
    
    st1 = !st1;
    digitalWrite(12, st1);
    t1 = millis();
  }
  

// LED 2
  dt2 = millis() - t2;
  
  if (dt2 > tled2) {
    if (st2) {
        tled2 = 1000; //OFF
    } else {
        tled2 = 100; //ON
    }
    
    st2 = !st2;
    digitalWrite(13, st2);
    t2 = millis();
  }
  
}

così funziona esattamente come avevo bisogno, cioè ho il pieno controllo sul tempo di spegnimento e di accensione, grazie!

@gpb01 praticamente quali problemi potrei avere? Se si tratta di solo di una forma di approccio non proprio corretta, per il mio caso l'importante è che funziona e così funziona benissimo. In questo esempio ci sono 2 LED, il mio progetto ne prevede 6, non è un progetto complesso.

mmm...direi che ho aggiunto una condizione if...else per modificare il valore di tled1. Ok la nidificazione delle if...else, ma non corretto il ciclo, i cicli sono while, do while e for.

In verità un ciclo esiste ed è la funzione loop() che inizia, termina e ricomincia all'infinito.

Le variabili st1 ed st2 le dovresti dichiarare di tipo bool o boolean, cioè cosi:

bool st1 = LOW;

Il tipo di dato int su AVR8 bit è grande 2 byte, su ESP32 e in genere su ARM int è grande 32 bit. Oltre che uno spreco di memoria è fuorviante per il programmatore che legge il codice e cerca di capirlo.

Ok, tranne queste e altre piccole imprecisione, hai subito capito come usare millis(). Se ti va di vedere cosa si può fare con millis di più complesso clicca qui.

Ciao.

Ciao, ho modificato le variabili dichiarandole di tipo boolean come hai suggerito tu.

Ho letto l'articolo è parecchio interesante ma è un po' fuori dalla mia portata, il mio esperimento con millis() si basa su diversi tutorial che ho seguito e alterato, devo approfondire molto di più.

Tutte quelle che ha dichiarato "globali" (e NON locali, quindi NON vanno nello stack), almeno secondo il codice pubblicato. E' comunque poi un inutile spreco di righe e cattiva leggibilità.

Guglielmo

Vero vedo sono tutte dichiarate globali e quindi allocate staticamente.
Forse inizia a diventare confuso quando ci saranno 6 x 6 = 36 variabili per i sei led. Si avrebbe minore confusione impiegano una struct con le 6 variabili per led e delle funzioni.

Ciao.

Ok, ora mi trovo in una condizione molto simile alla metafora dell'orizzonte che si allontana di un passo se faccio un passo avanti.
In questo contesto per ogni passo avanti devo farne uno indietro e ricominciare... chissà se ne uscirò vivo :sweat_smile: :joy:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.