[RISOLTO] millis su fade led rgb

Ciao a tutti, io ho questo codice:

for( int i = 0 ; i < 255 ; i += 1 ){
       analogWrite( G, 0 + i );
       analogWrite( R, 255 - i );
       delay(tempo);
    }
    for( int i = 0 ; i < 255 ; i += 1 ){
      analogWrite( B, 0 + i );
      analogWrite( G, 255 - i );
      delay(tempo);
    } 
    for( int i = 0 ; i < 255 ; i += 1 ){
      analogWrite( R, 0 + i );
      analogWrite( B, 255 - i );
      delay(tempo);
      }

che mi permette di effettuare un fade incrociato di un led rgb. Il mio problema è che devo sostituire il delay con un millis perchè non posso far fermare il programma. Nonostante ho provato ad inserire il millis mi vengono fuori risultati compleatmente differenti da quelli sperati. Ecco una delle tante prove (che però non va bene):

for( int i = 0 ; i < 255 ; i += 1 ){
      zero = millis();
       if(millis() - zero < tempo){
       analogWrite( G, 0 + i );
       analogWrite( R, 255 - i );
       //delay(tempo);
      }
      else{
        zero = millis();
      }
    }
    for( int i = 0 ; i < 255 ; i += 1 ){
      int zero1 = millis();
      if(millis() - zero1 > tempo){
      analogWrite( B, 0 + i );
      analogWrite( G, 255 - i );
      zero1 = millis();
      //delay(tempo);
      }
      else{
        zero1 = millis();
      }
    } 
    for( int i = 0 ; i < 255 ; i += 1 ){
      int zero2 = millis();
      if(millis() - zero2 > tempo){
      analogWrite( R, 0 + i );
      analogWrite( B, 255 - i );
      zero2 = millis();
      //delay(tempo);
      }
      else{
        zero2 = millis();
      }
    }

Qualcuno può darmi una mano?

Grazie Leo

Ormai si vive di rendita :slight_smile:

Millis:

Fade:

Teoria completa:

Grazie Claudio_FF per avermi linkato quei qost che mi hanno chiarito meglio l'utilizzo del millis(). Ho notato però che in quei post, alla funzione millis viene affiancata la funzione switch, ho l'impressione che non è ciò che serve a me, o sbaglio?

Leo

LeoTer01: in quei post, alla funzione millis viene affiancata la funzione switch, ho l'impressione che non è ciò che serve a me, o sbaglio?

Switch è solo una forma contratta di if/else if/else if/... quindi si può benissimo non usarla, basta che la sequenza logica delle operazioni svolte sia la stessa.

Dopo tante prove sono riuscito a scrivere un codice che, secondo me è il più corretto, però continua a non funzionare. Il led rimane acceso rosso e controllando da seriale i valori di fadeR, fadeG, fadeB non cambiano ma rimangono quelli di partenza, ovvero rispettivamente 255, 0, 0. Qualcuno sa dirmi dove sto sbagliando? (Ricordo che il mio intento è quello di creare una dissolvenza incrociata dei tre colori di un led rgb, senza l'uso del delay) Ecco il codice:

int R = 5;
int G = 6;
int B = 3;
int fadeR = 255;
int fadeG = 0;
int fadeB = 0;
long zero = 0;
long tempo;
void setup(){
pinMode(R, OUTPUT);
  pinMode(G, OUTPUT);
  pinMode(B, OUTPUT);
}
void loop(){
    analogRead(A5);
    pR = map(analogRead(A5), 0, 1023, 1, 20);
    tempo = pR;
    if(millis() - zero > tempo){
      if(fadeR >= 0 && fadeG <= 255){
        fadeR--;
        fadeG++;
        analogWrite(R, fadeR);
        analogWrite(G, fadeG);
        zero = millis(); 
      }
      if(fadeG >= 0 && fadeB <= 255){
        fadeG--;
        fadeB++;
        analogWrite(G, fadeG);
        analogWrite(B, fadeB);
        zero = millis(); 
      }
      if(fadeB >= 0 && fadeR <= 255){
        fadeB--;
        fadeR++;
        analogWrite(B, fadeB);
        analogWrite(R, fadeR);
        zero = millis(); 
      }
    }
delay(10);
}

Grazie Leo

Consideri che millis() è in millisecondi, vero?

la variabile tempo quando la inizializzi? Poi tutte le variabili legate a millis devono essere unsigned long e non solamente long Più precisamente tempo può essere long basta che il valore che vuoi controllare stia nei limiti del long, ma zero deve essere unsigned long

Datman: Consideri che millis() è in millisecondi, vero?

Esatto.

fabpolli: Poi tutte le variabili legate a millis devono essere unsigned long e non solamente long Più precisamente tempo può essere long basta che il valore che vuoi controllare stia nei limiti del long, ma zero deve essere unsigned long

Provveduto a modificare da long a unsigned long entrambe, potresti spiegarmi il motivo di ciò, perchè altre parti del programma (che ho omesso) funzionavano lo stesso anche con long, grazie.

fabpolli: la variabile tempo quando la inizializzi?

In che senso "inizializzi" ?

Leo

ciao io inizializzo millis() cosi':

unsigned long previousMillis1 = 0; //will store last time LED was updated
unsigned long interval1 = 10000;  //tempo aggiornamento 10 secondi

poi nel loop () ho cosi:

if (millis() - previousMillis1 > interval1) {
    previousMillis1 = millis();
}

in questo modo se sono passati 10 secondi continua il codice dopo if senno continua il loop()

ciao

LeoTer01: Esatto.

Provveduto a modificare da long a unsigned long entrambe, potresti spiegarmi il motivo di ciò, perchè altre parti del programma (che ho omesso) funzionavano lo stesso anche con long, grazie.

In che senso "inizializzi" ?

Leo

Quello è un errore mio non avevo notato la riga

tempo = pR;

che valorizza la variabile. Funzionavano con long per pura fortuna :) A parte gli scherzi le variabili long ti fanno funzionare il tutto finché millis() non restituisce un valore superiore al limite di long quindi per per esempio facendo prove riprogrammi/resetti arduino spesso tutto sembra funzionare, quando invece arduino resta acceco per più di 2,147,483,647 mS allora assegnano un valore troppo grande per il logn questo assumerà un valore negativo (Es. un mS dopo il limite indicato una variabile long varrà -2,147,483,648) e si incasina il tutto. Non è però detto che in questo caso specifico sia quello a creare l'anomalia di funzionamento

Nello specifico ti consiglio di "rivedere" la richista di @Datman perché hai risposto di si ma mi sa che la tua map "sbugiarda" :) la tua affermazione

fabpolli: che valorizza la variabile. Funzionavano con long per pura fortuna :) A parte gli scherzi le variabili long ti fanno funzionare il tutto finché millis() non restituisce un valore superiore al limite di long quindi per per esempio facendo prove riprogrammi/resetti arduino spesso tutto sembra funzionare, quando invece arduino resta acceco per più di 2,147,483,647 mS allora assegnano un valore troppo grande per il logn questo assumerà un valore negativo (Es. un mS dopo il limite indicato una variabile long varrà -2,147,483,648) e si incasina il tutto. Non è però detto che in questo caso specifico sia quello a creare l'anomalia di funzionamento

Capito grazie, però non era quello il problema :(

fabpolli: Nello specifico ti consiglio di "rivedere" la richista di @Datman perché hai risposto di si ma mi sa che la tua map "sbugiarda" :) la tua affermazione

E come faccio a saperlo? Io credevo che fosse in millisecondi. Il map ce l'ho messo perchè volevo che girando il potenziometro "pR" mi cambiasse il valore di "tempo" quindi la velocità della dissolvenza.

Leo

LeoTer01: E come faccio a saperlo? Io credevo che fosse in millisecondi. Il map ce l'ho messo perchè volevo che girando il potenziometro "pR" mi cambiasse il valore di "tempo" quindi la velocità della dissolvenza.

Leo

Guarda bene i valori che usi. Il valore minimo e massimo che ti ritorna la map qual'è?

Da serial monitor leggendo "pR" leggo valori da 1 a 20 in base a com'è posizionato il potenziometro.

Leo

ok e ti sembrano tanti 20 millisecondi? :)

Considerando che la persistenza retinica si aggira attorno a 18/20 mS ::)

effettivamente hai ragione però utilizzando il delay ero costretto a mettere valori del genere altrimenti andava lentissima :D Però mettendo valori che vanno da 200 a 500 non cambia nulla: sempre acceso su rosso.

Leo

LeoTer01:
Però mettendo valori che vanno da 200 a 500 non cambia nulla: sempre acceso su rosso

Nel loop ci sono tre if eseguiti uno dopo l’altro che alla fine lasciano i valori invariati… in un if vengono incrementati e in un if successivo decrementati, risultato finale valore uguale all’inizio.

Eh, probabilmente è per quello che non funziona ma non so proprio come risolvere il problema....ho provato di tutto ma non sono ancora riuscito a farlo funzionare. :sob: Qualcuno mi potrebbe dare qualche linea guida, qualche aiuto su come fare?

P.S. Spero abbiate capito cosa voglio fare, in caso contrario cercherò di spiegarmi meglio!

Grazie Leo

Prova facendo diversamente: prendi un valore che varia ciclicamente, ad esempio il resto di millis() diviso 2000, e ne ricavi i valori per R, G e B sfasandoli tra loro: G=R+667; B=G+667. Naturalmente devi mettere degli if che azzerino al superamento del massimo: if(G>2000) G-=2000.

Tempo fa feci qualcosa del genere con un led RGB, ma usai dei delay perché non c'era altro nel programma. Mi resi conto, però, che per fare sfumi uniformi era necessaria una tabella con valori trovati sperimentalmente e, comunque, i 255 valori del pwm producevano visibili salti ai livelli di luminosità più bassi.

LeoTer01, il tuo codice iniziale con i cicli for() aveva il problema che usava i delay(), che tu non vuoi usare!

La tua alternativa con millis() non è una naturale evoluzione del codice con for().

Nel codice con for(), eseguo prima il primo for, poi il secondo for, poi il terzo for.

Per farlo con millis() a mio avviso dovresti usare una macchina a stati finiti, una variabile che assume tre valori, e tre if(), se stato=1 eseguo il primo decremento, poi stato passa a 2 ed eseguo il secondo decremento.

Esempio:

int R = 5;
int G = 6;
int B = 3;
int fadeR = 255;
int fadeG = 0;
int fadeB = 0;
unsigned long zero = 0;
unsigned long tempo=200;
byte stato=0; // A seconda del valore di stato esegue una cosa o un altra


void setup(){
pinMode(R, OUTPUT);
  pinMode(G, OUTPUT);
  pinMode(B, OUTPUT);
}
void loop(){
    analogRead(A5);
    pR = map(analogRead(A5), 0, 1023, 1, 20);
    tempo = pR;
    if(millis() - zero > tempo){

      if(stato==0){
     
        fadeR--;
        fadeG++;
        analogWrite(R, fadeR);
        analogWrite(G, fadeG);
        if(fadeR==0)
            stato=1; // Quando il colore rosso è zero passa allo stato successivo
        
      }else if(stato==1){
   
      
        fadeG--;
        fadeB++;
        analogWrite(G, fadeG);
        analogWrite(B, fadeB);
        if(fadeG==0)
            stato=2; // Quando il colore verde è zero passo allo stato successivo 2
        
      }else if(stato==2){
      
        fadeB--;
        fadeR++;
        analogWrite(B, fadeB);
        analogWrite(R, fadeR);
        if(fadeB==0)
             stato=0; // Quando l'ultimo stato è stato eseguito rincomincia tornando allo stato zero
         
      }
      zero = millis(); // Questo deve avvenire ogni step di tempo
    }
delay(10);
}

PER capire meglio leggi cosa sia una macchina a stati finiti in maniera da capire meglio, di imparare cose che ti possono tornare utili in altre occasioni :)