Delay non bloccante in un led rgb

Salve sto scrivendo questo codice .. funziona quasi .. ovvero che il led rgb si accende dopo 1 secondo ma a caso invece di seguire il mio codice.
Vi posto il codice:

#include <Arduino.h>
#include <Wire.h>

unsigned long RED,GREEN,BLUE;
int STATO_RED,STATO_GREEN,STATO_BLUE = 0;

#define PIN_LED_RED 5
#define PIN_LED_GREEN 6
#define PIN_LED_BLUE 7

void setup() {
  pinMode(PIN_LED_RED, OUTPUT);
  pinMode(PIN_LED_GREEN, OUTPUT);
  pinMode(PIN_LED_BLUE, OUTPUT);
  Serial.begin(9600);
  RED = millis();
  GREEN = millis();
  BLUE = millis();
}

void loop() {
    if ((millis() - RED) > 2000) {
      STATO_RED = !STATO_RED;
      colora(255,0,0);
      Serial.println("RED");
      RED = millis();
    }
    if ((millis() - GREEN) > 2000) {
      STATO_GREEN = !STATO_GREEN;
      colora(0,255,0);
      Serial.println("GREEN");
      GREEN = millis();
    }

    if ((millis() - BLUE) > 2000) {
      Serial.println("BLUE");
      STATO_BLUE = !STATO_BLUE;
      colora(0,0,255);
      BLUE = millis();
    }
}

void colora(int R, int G, int B)
{
  analogWrite(PIN_LED_RED, R);
  analogWrite(PIN_LED_GREEN, G);
  analogWrite(PIN_LED_BLUE, B);
}
  

avete ide come mai invece di venire prima RED, GREEN, BLUE .. mi fa l'accensione diversamente dal loop?

avete idea cosa può essere ?
Questo lo scritto io.. e non so se è giusto usare cosi.

Grazie mille e buona giornata.

problema risolto .. ho sbagliato i pin ..

#define PIN_LED_RED 5
#define PIN_LED_GREEN 7
#define PIN_LED_BLUE 6

l'unico che è la seriale.. che non stampa bene.. ovvero mi stampa cosi:
RED
dopo 1 secondo
GREEN
BLUE
etc..

per far venire che mi viene scritto cosi:
RED - 1 secondo
GREEN - 1 secondo
BLUE 1 - secondo

cosa devo fare?
grazie.

Ma non c'è motivo per cui debba venire prima uno o l'altro.
La funzione loop partendo dall'inizio fino alla fine impegna la CPU per meno di 1 millesimo di secondo. Qualunque condizione (una delle tre) può essere vera. Ad esempio se inserisci un delay nel loop a secondo del valore di delay si accenderà ad esempio il rosso.

Si, non vedo nulla di sbagliato. Però desideri un comportamento ma scrivi codice
che si comporta diversamente.

PS: Ma chissà perché non hai preso la buona abitudine di riservare il maiuscolo per le costanti, eppure gli esempio ci sono in giro. :roll_eyes:

Ciao.

Leggi millis() all'inizio della loop()
E usa il valore letto invece che rileggerlo tutte le volte, è quello il problema

Per prima cosa ti consiglierei di NON usare le maiuscole per le variabili in quanto per convenzione (quindi non è una regola imposta dal compilatore...) i nomi tutti in maiuscolo indicano delle costanti o delle macro. Per dire, vanne bene i tuoi "#define" per i pin (tra l'altro anche io uso un prefisso "PIN_" o "P_" per evidenziare i valori dei pin...), ma le variabili no, mettile in minuscolo con eventualmente le iniziali in maiuscolo.
Poi, altro consiglio (che puoi accettare o meno) se le tre "unsigned long" servono per memorizzare un valore di millis() io in genere metto come prefisso "tmr" ossia "timer", anche in questo caso per ricordarmi a cosa servono.
Poi se le tre variabili stato (che chiamerei "statoRed", "statoGreen" e "statoBlue" per quanto detto prima) contengono solo valori vero/falso, perché "int" e non usare più esplicitamente "bool"?

Per quanto riguarda il tuo problema, vorrei provare a fartici arrivare da solo: prova a spiegare meglio lo scopo delle tre variabili RED,GREEN,BLUE. Cosa contengono? Le inizializzi con millis() ossia col valore attuale dei millisecondi dalla partenza di Arduino, ci siamo? Ma poi come le usi?
Ossia spiega questa "if" cosa dovrebbe fare:

if ((millis() - RED) > 2000) {

OGNI volta che invochi millis() ti viene dato il valore attuale.
Tra un if e l'altro hai già valori diversi ed anche tra il test if e l'assegnazione se entri nell'if
Ovvero diverso è se fai la lettura di millis una sola volta:

void loop() {
  unsigned long currmill=millis();
  if ((currmill - RED) > 2000) 
  { ...
    RED = currmill;
  }
  if ((currmill - GREEN) > 2000) 
  { ...

Vero ma non è quello il problema, anche perché il confronto lo fa se maggiore di 2000, e farlo un paio di millisecondi in ritardo non causa il problema descritto.
Vorrei attendere che l'OP ragioni sul suo codice, in base agli "indizi" che gli ho dato, per trovare l'inghippo...:wink:

Lascia stare ciò che dice Docdoc

non ha verificato ed ha preso un abbaglio

io ho verificato ed in effetti il programma si comporta come descrivi
la ragione è la legger differenza tra i differenti valor di millis() dalle differenti chiamate
e siccome la loop è velocissima anche un millisecondo fa la differenza

devi, come ti è già stato detto, usare tempi univoci, salvando il tempo "standard" una volta e usandolo per tutte le operazioni simili

ecco il programma (copia del tuo) che fa giusto

/*
   Una nuova idea DDD
   Del Dinamico Duo

   Sentitevi liberi di copiare
   Sentitevi liberi di trarre ispirazione
   Sentitevi liberi di dare un cenno di ringraziamento


*/

#include <Arduino.h>
#include <Wire.h>

unsigned long RED, GREEN, BLUE;
int STATO_RED, STATO_GREEN, STATO_BLUE = 0;

#define PIN_LED_RED 5
#define PIN_LED_GREEN 6
#define PIN_LED_BLUE 7

void setup()
{
   pinMode(PIN_LED_RED, OUTPUT);
   pinMode(PIN_LED_GREEN, OUTPUT);
   pinMode(PIN_LED_BLUE, OUTPUT);
   Serial.begin(9600);
   unsigned long int m = millis();
   RED = m;
   GREEN = m;
   BLUE = m;
}

void loop()
{
   unsigned long int m = millis();

   if ((m - RED) > 2000)
   {
      STATO_RED = !STATO_RED;
      colora(255, 0, 0);
      Serial.println("RED");
      RED = m;
   }

   if ((m - GREEN) > 2000)
   {
      STATO_GREEN = !STATO_GREEN;
      colora(0, 255, 0);
      Serial.println("GREEN");
      GREEN = m;
   }

   if ((m - BLUE) > 2000)
   {
      Serial.println("BLUE");
      STATO_BLUE = !STATO_BLUE;
      colora(0, 0, 255);
      BLUE = m;
   }
}

void colora(int R, int G, int B)
{
   analogWrite(PIN_LED_RED, R);
   analogWrite(PIN_LED_GREEN, G);
   analogWrite(PIN_LED_BLUE, B);
}

Perdonami, nonostante il tuo alias molto "asimoviano" (che apprezzo), mi interesserebbe capire dove sia secondo te il mio abbaglio. Provo a spiegarti.
Lasciamo stare il discorso della leggerissima possibile differenza tra i tre e prendiamo il tuo codice, ok?

Nella setup() imposti le tre variabili (timer) con lo stesso identico valore di millis() giusto?
Quindi nel loop() verifica se la differenza tra i tre timer ed il millis() corrente sia maggiore di 2000 ossia 2 secondi. Ok?

Ma questo significa che tutte e tre le if() saranno sempre verificate contemporaneamente col risultato che verranno sempre eseguite tutte in sequenza, per cui la chiamata alla funzione "colora()" di fatto avrà come effetto solamente quella invocata per ultima, ossia ci sarà sempre e solo il blu acceso (gli altri due lo saranno per un millisecondo, quindi invisibili)!
Fai girare il TUO codice su Tinkercad e vedi che succede, se è come dico io o come di ci tu.

Tra l'altro l'OP chiedeva:

per far venire che mi viene scritto cosi:
RED - 1 secondo
GREEN - 1 secondo
BLUE 1 - secondo
cosa devo fare?

Quindi le accensioni vanno sfasate di 1 secondo, il che significa (ma questa cosa è quella sulla quale avrei voluto far ragionare l'OP ed arrivarci autonomamente) che nel setup() bisognerebbe forse quanto meno fare:

   RED = m;
   GREEN = m + 1000;
   BLUE = m + 2000;

PS: tra l'altro dirgli di ignorare anche tutti gli altri consigli che gli ho dato è ben poco utile all'OP.

Poiché il periodo è 2000ms per tutti e tre i LED, le tre accensioni dovrebbero avvenire contemporaneamente, ma la funzione colora() ne accende uno e spegne gli altri, quindi ogni due secondi vengono chiamate quasi contemporaneamente tre colora() che interferiscono l'una con l'altra e l'effetto finale è prodotto dall'ultima delle tre che viene chiamata. Quale sia l'ultima dipende sia dalla variazione di millis() tra un if e l'altro, sia da come viene compilato e ottimizzato il programma.

In poche parole, c'è un errore concettuale globale.

Torno in ferie.

Qualunque cosa dica docdoc non cambia due fatti incontrovertibili

1 il programma modificato da noi si comporta come richiesto (nel primo post) il che dimostra chi ha ragione e chi no
2 egli è nella nostra ignore list da un pezzo, pertanto può dire quel che vuole, ma non ci tange per nulla, abbiamo imparato la lezione e non ci faremo più bannare per le sue provocazioni

Appunto, carica il tuo codice su TinkerCad e vedi da te se funziona o se vedi solo il blu.

In ogni caso io avrei evitato tutte quelle palle di variabiline, ed implementato con una semplice macchina a stati finiti (questa, era una cosa alla quale avrei voluto far arrivare l'OP...):

#define S_RED 0
#define S_GREEN 1
#define S_BLUE 2
int Stato = -1;
unsigned long tmrSwitch;

#define PIN_LED_RED 5
#define PIN_LED_GREEN 6
#define PIN_LED_BLUE 7

void setup()
{
  pinMode(PIN_LED_RED, OUTPUT);
  pinMode(PIN_LED_GREEN, OUTPUT);
  pinMode(PIN_LED_BLUE, OUTPUT);
  Serial.begin(9600);
  tmrSwitch = 0;
  Stato = S_RED;
  Aggiorna();  
}

void loop()
{
  unsigned long int m = millis();
  if (m - tmrSwitch > 1000) {
    if (++Stato > S_BLUE) Stato = S_RED;
    tmrSwitch = m;
    Aggiorna();
  }
}

void Aggiorna() {
  switch (Stato) {
    case S_RED:    
      colora(255, 0, 0);
      Serial.println("RED");
      break;
    case S_GREEN:    
      colora(0, 255, 0);
      Serial.println("GREEN");
      break;
    case S_BLUE:
      colora(0, 0, 255);
      Serial.println("BLUE");
      break;
  }
}

void colora(int R, int G, int B)
{
   analogWrite(PIN_LED_RED, R);
   analogWrite(PIN_LED_GREEN, G);
   analogWrite(PIN_LED_BLUE, B);
}

Ah, e questa funziona.
Invece il tuo codice fa questo, ossia "RED" "GREEN" "BLUE" lo scrive di seguito, e si vede solo il blu:

Ultimo avverimento ...
... ho detto e ripetuto mille volte di limitarsi a discussioni tecniche, senza riferimenti a "ignore list", "plonk" ed altre baggianate del genere, parlando solo del codice e dell'hardware.

Come ho fatto in passato per altri utenti, il reiterarsi di questa cosa porterà alla sospensione dell'account!

Guglielmo

@docdoc docdoc non ne sarei sicurissimo.
Se partiamo con RED=0, GREEN=0, BLU=0 al primo if RED la millis potrebbe essere 2000, e quindi non scatta, al secondo if GREEN potrebbe millis essere arrivato a 2001 e quindi scatta. Hai il rosso spento e il blu acceso.

Inoltre come dice @Datman non avevo visto che quando accende un led spegne gli altri due (non capisco la logica)

ok, grazie mille ora me lo studio e poi ti faccio sapere.. il tuo funziona come vorrei fare io.
ti ringrazio molto.. ora mi metto ad studiarmelo e poi ti faccio sapere.
grazie e buona giornata.

Ahh, @gigetto1982 ma volevi accendere i tre led in sequenza a 2 secondi l'uno dall'altro !!
Sorry, mica avevo capito. Avevi 3 temporizzatori diversi, sembrava tu volessi fare un'altra cosa. ^-^

Quel codice per 2 secondi non fa nulla (perché l'intervallo è stato impostato a 2000 nonostante l'OP avesse detto di voler distanziare di 1 secondo, ma tralasciamo) ma subito dopo soddisfa tutte e tre le if() per cui la prima accende rosso, poi la seconda lo spegne ed accende il verde e infine l'ultima il blu. E quindi alla fine del primo ciclo avremo solo il led blu acceso, gli altri due sono stati accesi per un paio di millisecondi per cui risultano di fatto sempre spenti. D'altronde se su seriale ogni 2 secondi viene scritto:

RED
GREEN
BLUE

tutti e tre di seguito, ne è la prova. Per distanziarli di 1 secondo bisognerebbe impostare il relativo timer (le variabili RED, GREEN, BLUE che sono di fatto questo) con tre valori distanziati di 1 secondo uno dall'altro.
La versione dell'OP ha i colori "mischiati" perché, come si diceva, se legge millis() più volte può avere valori leggermente diversi per cui la sequenza non è quella giusta, ma, come dicevo e come cercavo di far arrivare autonomamente l'OP, il problema più importante non era quello della lettura di millis() bensì il modo in cui gestiva le variabili-timer. Oltre ai vari consigli "stilistici" che provavo a dargli.
Ma dato che l'OP voleva avere i colori in sequenza distanti 1 secondo, si fa prima con una variabile di stato che indica quale colore è acceso in quel momento, e ciclare tra le tre (come ho fatto nel mio ultimo codice di esempio, che ho anche provato).

F.De Gregori: E non c'è niente da capire. :smiley:

Il codice postato qui:

una volta incollato su wokwi:nano in 4 secondi di simulazione stampa questa sequenza:

RED
GREEN
BLUE
GREEN
BLUE
RED

Sembra una roulett russa che gira alla velocità di clock della CPU. Infatti basta aggiungere nel setup:

 delayMicroseconds(2);

e sempre in 4 secondi di simulazione stampa questa sequenza:

BLUE
RED
GREEN
GREEN
BLUE
RED

Cioè la sequenza dipende dal codice stesso che è variabile mentre il clock influisce ma è costante (quasi molto costante).

PS: ma poi che senso ha temporizzare 3 timer se il tempo è sempre 2s, di if temporizzata ne scrivo una sola.
PS1: non ho collegato alcun led

Stesso risultato diciamo casuale lo ottengo se una delle if temporizzate impegna la CPU per qualche us in più rispetto alle altre; tipo un paio di NOP.

Ciao.

1 Like

si giusto.. scusate se non mi sono fatto capire subito.
ti ringrazio anche a te e buona giornata .. in tanto sto convertendo il codice con i nomi giusti e non con lettere MAIUSCOLE etc..

vi ringrazio molto e buone vacanze a tutti.

1 Like

Ma figurati, nessun problema. A volte non è facile capire quello che un utente chiede (e non è sempre facile spiegarsi) :smiley: