Effetto alba e tramonto plafoniera Led 24v

Buonasera ragazzi, sto facendo una plafoniera per un acquario, mi servirebbe dimmerare le varie luci per creare effetti tipi alba e tramonto....
stavo provando a scrivere uno sketch non bloccante, ma mi sono un attimo bloccato. io :rofl:.....
vi posto l'esempio...

//-------led------
int ledrosso = 2;
int ledverde = 3;
int ledblu = 4;
int ledbianchi = 7;
int rele24v = 22;
int rele12v = 24;
int relegrow = 26;
//----------------
int ritardo = 10;
int ValorePWM = 0;
//------ora----------
#include "RTClib.h"
RTC_DS3231 rtc;
int timeOn= 11*60 + 41;
int timeOff= 18*60 + 50;


//--------lcd--------
#include <LiquidCrystal.h>
const int rs = 28, en = 6, d4 = 30, d5 = 5, d6 = 32, d7 = 8;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
//------time----------
int i = 0;
//----------------
int statoEffetti = 0;
int incrementoRosso = 0;
unsigned long timePrevRed = 0;
int FadeRed = 200;
int MaxIncrosso = 225;
int MinIncrosso = 0;

void setup() {
  pinMode(ledrosso, OUTPUT);
  pinMode(ledverde, OUTPUT);
  pinMode(ledblu, OUTPUT);
  pinMode(ledbianchi, OUTPUT);
  pinMode(rele24v, OUTPUT);
  pinMode(rele12v, OUTPUT);
  pinMode(relegrow, OUTPUT);
  //------------------------
  digitalWrite(rele24v,HIGH);
  digitalWrite(rele12v,HIGH);
  digitalWrite(relegrow,HIGH);
  //------------------------
  rtc.begin();
  lcd.begin(16,2);

  Serial.begin(9600);
  
  }

void loop() {
  ora_lcd();
  
  DateTime tempo = rtc.now();
  int oraAdesso = tempo.hour()*60 + tempo.minute();

  if(statoEffetti == 0){ 
    if (oraAdesso == timeOn){
      statoEffetti = 1;
      }
      if (statoEffetti == 1){
        controllo_luci();
        statoEffetti = 0;        
        }
   }
}

e questa poi e la scheda controllo luci....

void controllo_luci(){
  if(millis() - timePrevRed >= FadeRed){
    incrementoRosso++;
    digitalWrite(rele12v,LOW);
    digitalWrite(ledrosso, incrementoRosso);
    if(incrementoRosso > MaxIncrosso){
      statoEffetti = 2;
    }
    timePrevRed = millis ();
  }
  if(statoEffetti == 2){
    //led verdi
    }
}
  

non riesco a capire come poter creare un effetto dove per esempio parte la luce rossa poi ad esempio a meta del "fade" di quella rossa si accende il verde per far diventare la luce più gialla e poi si accende piano piano quella bianca per diventare sempre più intensa e far scemare quelle RGB....

È come stai giustamente tentando di fare con una variabile stato per controllare il flusso di esecuzione, ma questa variabile va controllata sempre:

SE stato x E timeout:
faccio un passo

Ma nel code principale o nella scheda luci?

In teoria la sequenza deve partire ad un ora x quindi non mi basta controllarla solo una volta l’ora per poi ricontrollarla quando devo far partire la sequenza inversa per lo spegnimento??

È una questione di design, che nel codice riportato non comprendo. Secondo me è meglio partire da un diagramma degli stati, eventi attesi in ogni stato, e azioni da eseguire in risposta agli eventi. Se usare un solo grosso diagramma, o vari diagrammi ciascuno con la propria variabile di stato personale, è di nuovo una scelta di design. In sostanza prima la logica di funzionamento ben precisa (in questa fase, se avviene questo, faccio questo) e poi la traduzione in istruzioni.

Il problema che non sono ferratissimo sulla programmazione nel senso che non sono capace a scriverlo e vado in confusione facilmente se cambio qualcosa ahahah riesci a farmi un esempio di quello che mi stai dicendo?

Per capire: tu vuoi far partire la sequenza a un'ora x e farla arrivare, diciamo, a uno stato stabile (ad es. giorno). Ad un'ora y deve partire la sequenza inversa che farà ritornare il tutto a un altro stato stabile (ad es notte).

Se è questo che vuoi fare comincia a specificare i tempi e le intensità dei vari colori in un diagramma temporale che poi potrà essere modificato in funzione della rapidità e delle varie colorazioni che si devono avvicendare. Ti premetto che non sarà semplice perché a livelli uguali di intensità nei tre colori fondamentali non corrisponde una uguale percezione da parte dell'occhio umano che è sensibile in maniera differente ai vari colori. Prova a googlare "diagramma percezione colori" per qualche informazione in più.

Ciao,
P.

E proprio questo che non so fare… nel senso come devo scrivere il codice per far fare quello alle luci ?? Nel senso come faccio a dirgli parti con il rosso poi mischiacinil verde quando il rosso è a metà

Grazie ora me lo guardò subito

sostanzialemente non mi è chiaro come creare uno sketch non bloccante.... quello che ho provato a fare l'ho copiato da qualche parte ma non riesco a capirlo.....anche perché non trovo delle reference buone

cancello tutto??? qualcuno di buon cuore che abbia voglia di aiutarmi?? :rofl:

Nel loop() del programma devi controllare se è scattata l'ora x oppure l'ora y.
Se è scattata l'ora x con la funzione millis() controlli ogni 100ms (ad esempio) il livello dei colori RGB fino al limite che vuoi raggiungere e lo mantieni fino all'ora y. A quel punto, sempre con la funzione millis(), controlli la variazione inversa fino al nuovo punto che vuoi raggiungere.

Per questo ti dicevo di preparare uno schema temporale con i livelli dei vari valori di ciascun colore. Un esempio può essere:

Tempo  x--------30s--------60s--------90s- - -
Rosso  0--------127--------255--------255- - -
verde  0---------0---------127--------255- - -
Blu    0---------0---------127--------255- - -

Tempo  y--------30s--------60s--------90s- - -
Rosso  255------255--------127---------0-- - -
verde  255------127---------0----------0-- - -
Blu    255------127---------0----------0-- - -

Questo è solo un esempio. Da qui si parte per implementare il programma. Un esempio può essere questo:

METTI ora_x a false
METTI ora_y a false
METTI rosso a0
METTI verde a 0
METTI blu a 0

loop()
LEGGI ora
SE è scattata l'ora x
  METTI ora_x a true
  METTI ora_y a false
SE è scattata l'ora y
  METTI ora_y a true
  METTI ora_x a false
SE ora_x true
  SE sono passati 100ms
    Aggiorna valori RGB
    SE si è raggiunto uno stato stabile
      METTI ora_x a false
SE ora_y true
  SE sono passati 100ms
    Aggiorna valori RGB
    SE si è raggiunto uno stato stabile
      METTI ora_y a false

Ciao,
P.

Tanto per capire, partiamo dall'inizio. Parliamo di dimmerare con analogWrite()??

Se si cosa centra questa porzione di codice:

incrementoRosso++;
    digitalWrite(rele12v,LOW);
    digitalWrite(ledrosso, incrementoRosso);  // analogWrite? penso di si.

Seconda cosa, lo sketch non bloccante, giusto basta trovare il modo di non usare delay, for, while o altri cicli dentro al loop. Usi millis() per temporizzare l'incremento di un contatore che sarà il valore del PWM di un colore, quando il valore di questo contatore >= soglia abiliti un porzione di codice e così via.

PS: so perfettamente che non è così semplice scrivere uno sketch non bloccante, specie se si è presa l'abitudine di usare delay.

Ciao.

Oltre all'esempio "BlinkWithoutDelay" che ti fa vedere come funziona millis(), un esempio di programma semplice semplice può essere questo:

unsigned long tNow;
setup() {
  tNow = millis();
}

loop() {
  if (millis() - tNow >= 100) {
    tNow = millis();
    //QUI METTI LE AZIONI DA FARE OGNI 100ms
  }
  //QUI IL PROGRAMMA EVOLVE IN MANIERA NON BLOCCANTE
}

Ciao,
P.

Per questo dicevo che prima ci si deve chiarire passo passo la logica che si vuole seguire, e solo poi tradurla in istruzioni. Lo pseudocodice/procedura del post #10 è ottimo. Vengono usate due variabili di stato 'ora_x' e 'ora_y' per abilitare o disabilitare il funzionamento delle parti successive del programma. E come vedi le parti sono scritte nella forma forma: if stato -> if evento -> azione. In questo caso gli eventi sono le condizioni che si vogliono controllare, timeout ecc. Quando si riesce ad esprimere tutta la logica sotto in questa forma si è ottenuta una procedura non bloccante, e se funziona su carta in pseudocodice, funzionerà anche tradotta in codice (salvo errori di "traduzione" che però non sono di logica).

Mi diceva papà che esiste una discussione che spiega bene questa cosa di alba e tramonto, e si trova facilmente perché è in sticker...

ok, ora mi è chiaro come strutturare il programma in base ad orari e come teoricamente usare millis() (dico teoricamente perché non sono a casa e non riesco a provarlo dal vivo però dai non sembra cosi complicato spiegato bene).
Comunque la parte che mi manca e proprio la parte di codice inerente ai valori RGB.....domani mentre sono di rientro a casa butto giu uno schema tipo quello che mi hai proposto tu.....che mi piace molto come logica. poi lo posto cosi abbiamo le idee più chiare.....

allora si effettivamente digitalWrite() avrebbe dovuto essere analogWrite() :sweat_smile: ma come dicevo prima non sono a casa e non potendo provare è stato un errore di distrazione..... invece la parte di incrementoRosso++ teoricamente nella mia testa avrebbe dovuto incremntare il valore RGB Rosso di un punto ogni tot.

lascia perdere :rofl: poi una volta capito il meccanismo è una cavolata, spero adesso di averlo capito ahahah

ecco qua spiegami questo,

allora praticamente tNow è uguale a millis(),
poi diciamo che :

se millis() - tNow (che sarebbe uguale a 0) è maggiore o uguale a 100 entri nella condizione, e poi prima di uscire dalla condizione riassegni tNow al valore aggiornato di millis()????

provo a scriverne una?

anche perche fosse per le luci anche fosse bloccante non sarebbe un grosso problema, ma visto che ci devo integrare anche dei sensori di galleggiamento....per azionare una pompa per il rabbocco, il codice deve poter leggere cambio di stato del sensore in ogni momento.....(MA ANDIAMO PER GRADI :rofl: UNA COSA ALLA VOLTA)

dove??

millis() è un contatore che parte da 0 al momento dell'accensione di Arduino e viene incrementato ogni millisecondo in maniera assolutamente autonoma da qualunque istruzione si stia eseguendo in quel momento. L'istruzione tNow = millis(); mette in tNow il valore che ha millis() IN QUEL MOMENTO che non sarà zero perché Arduino è partito PRIMA di eseguire quella istruzione. Se vuoi puoi far stampare il valore di millis() con l'istruzione Serial.println(millis()); per vedere quamto è IN QUELL'ISTANTE, ma toglila nella versione definitiva.

Fatto questo ( tNOW = millis(); ) entri in loop() e millis() si incrementa da solo ogni millisecondo. La differenza (millis() - tNow) assumeerà valori sempre crescenti via via che verrà ricalcolata ad ogni passaggio, perché millis() si incrementerà, mentre tNow resterà al valore inizialmente 'congelato' con l'istruzione tNow = millis();.

Quando la differenza (millis() - tNow) assumerà un valore uguale o appena superiore a 100 significa che sono trascorsi 100ms da tNow = millis(). È il momento di eseguire le azioni che devono essere eseguite ogni 100 ms, ma bisogna anche ricordarsi di 'ricaricare' tNow al valore che avrà millis() IN QUEL MOMENTO, che differirà presumibilmente di poco più di 100 dal valore del tNow precedente.

Spero di essere stato chiaro, ma se hai altri dubbi chiedi e cercheremo di chiarirteli.

Ciao,
P.

allora ho fatto una tabella con all'incirca i valori che potrebbero servirmi.... (bisogna poi vedere come rendono perché magari sono sballati pero come diceva @Claudio_FF almeno abbiamo un idea inziale...


ora visto questo vi allego anche lo schetch come lo strutturato almeno mi dite se va bene oppure no.... dopo di che devo capire come gestire i vari comandi alle luci....

//-------led------
int ledrosso = 2;
int ledverde = 3;
int ledblu = 4;
int ledbianchi = 7;
int rele24v = 22;
int rele12v = 24;
int relegrow = 26;
//----------------
int ValorePWM = 0;
//------pulsanti------
int pulsante1 = 0;
int pulsante2 = 0;
int pulsante3 = 0;
int pulsante4 = 0;
//------ora----------
#include "RTClib.h"
RTC_DS3231 rtc;

int hOn = 0;
int mOn = 0;
int hOff = 0;
int mOff = 0;

//--------lcd--------
#include <LiquidCrystal.h>
const int rs = 28, en = 6, d4 = 30, d5 = 5, d6 = 32, d7 = 8;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
//----------------
int statoEffetti = 0;
int tNow = 0;

void setup() {
  pinMode(ledrosso, OUTPUT);
  pinMode(ledverde, OUTPUT);
  pinMode(ledblu, OUTPUT);
  pinMode(ledbianchi, OUTPUT);
  pinMode(rele24v, OUTPUT);
  pinMode(rele12v, OUTPUT);
  pinMode(relegrow, OUTPUT);
  //------------------------
  digitalWrite(rele24v,HIGH);
  digitalWrite(rele12v,HIGH);
  digitalWrite(relegrow,HIGH);
  //------------------------
  pinMode(pulsante1, INPUT);
  pinMode(pulsante2, INPUT);
  pinMode(pulsante3, INPUT);
  pinMode(pulsante4, INPUT);
  //------------------------
  rtc.begin();
  lcd.begin(16,2);

  tNow = millis();
  
  }

void loop() {
  ora_lcd();
  int timeOn= hOn*60 + mOn; // ORA ACCENSIONE
  int timeOff= hOff*60 + mOff; //ORA SPEGNIMENTO
  
  DateTime tempo = rtc.now();
  int oraAdesso = tempo.hour()*60 + tempo.minute();

  if(statoEffetti == 0){ 
    if (oraAdesso > timeOn){
      statoEffetti = 1;
      }
      if (statoEffetti == 1){
        controllo_luci();
        statoEffetti = 0;        
        }
   }
}

poi la pagina gestione luci...

void controllo_luci(){
  if (millis() - tNow >= 100) {
    tNow = millis();
    //QUI METTI LE AZIONI DA FARE OGNI 100ms
  }

}
  

ora se ho capito bene @pgiagno all'interno del:
if(millis()-tNow >= 100){
tNow = millis();
//qui devo mettere tutti i controlli delle varie luci vero???
}

poi altra cosa che non capisco del comando millis() ho cercato un po di informazioni per capirci di più, ma dice che dopo una 50ntina di giorni incomincia a sballare il conteggio di millis, e vero?? come si può risolvere??

le 4 variabili pulsanti mi serviranno per modificare i vari parametri, magari ora accensione e spegnimento, e non saprei come fare ma magari anche le varie colorazioni(ma forse e meglio non complicarsi la vita)....per ora diciamo che serviranno per modificare l'ora di accensione e spegnimento.(

P.S. una cosa alla volta però :grin:

????? idee e consigli su come poter unire tutta la colorazione dei Led?? come da questo schema???

La funzione millis() serve a scandire il passaggio del tempo. Il tuo diagramma temporale prevede cambiamenti di illuminazione al minimo ogni 5 minuti, quindi è inutile l'istruzione
if (millis() - tNow >= 100)
perché non devi cambiare illuminazione ogni 100ms bensì al più ogni 5 min. Quindi l'istruzione diventa

  if (millis() - tNow >= 300000) {	//300000 sono i millisecondi in 5 minuti
    tNow = millis();
    //QUI METTI LE AZIONI DA FARE OGNI 5 minuti
  }

Devi avere un contatore

  int azione;

che avrai inizializzato a 0 e che incrementerai ogni volta che esci da controllo_luci().

Ho corretto e integrato il tuo programma. Questo è SOLO UN ESEMPIO di come si potrebbe implementare la funzione. Ci saranno errori (non l'ho testato).

//-------led------
int ledrosso = 2;
int ledverde = 3;
int ledblu = 4;
int ledbianchi = 7;
int rele24v = 22;
int rele12v = 24;
int relegrow = 26;
//----------------
int ValorePWM = 0;
//------pulsanti------
int pulsante1 = 0;
int pulsante2 = 0;
int pulsante3 = 0;
int pulsante4 = 0;
//------ora----------
#include "RTClib.h"
RTC_DS3231 rtc;

int hOn = 0;
int mOn = 0;
int hOff = 0;
int mOff = 0;

//--------lcd--------
#include <LiquidCrystal.h>
const int rs = 28, en = 6, d4 = 30, d5 = 5, d6 = 32, d7 = 8;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
//----------------
int statoEffetti = 0;
//TUTTE LE VARIABILI CHE AVRANNO A CHE FARE CON millis() DEVONO ESSERE DEFINITE COME unsigned long
//int tNow = 0;
unsigned long tNow;

//AGGIUNGEREI QUESTA VARIABILE PER LA GESTIONE DEL TEMPONELLA FUNZIONE controllo_luci()
int azione = 0;

void setup() {
  pinMode(ledrosso, OUTPUT);
  pinMode(ledverde, OUTPUT);
  pinMode(ledblu, OUTPUT);
  pinMode(ledbianchi, OUTPUT);
  pinMode(rele24v, OUTPUT);
  pinMode(rele12v, OUTPUT);
  pinMode(relegrow, OUTPUT);
  //------------------------
  digitalWrite(rele24v,HIGH);
  digitalWrite(rele12v,HIGH);
  digitalWrite(relegrow,HIGH);
  //------------------------
//PER UNA BUONA GESTIONE DEI PULSANTI CONVIENE CHE CHIUDANO VERSO GND E CHE I PIN DEI PULSANTI VENGANO DEFINITI COME INPUT_PULLUP
//  pinMode(pulsante1, INPUT);
//  pinMode(pulsante2, INPUT);
//  pinMode(pulsante3, INPUT);
//  pinMode(pulsante4, INPUT);
  pinMode(pulsante1, INPUT_PULLUP);
  pinMode(pulsante2, INPUT_PULLUP);
  pinMode(pulsante3, INPUT_PULLUP);
  pinMode(pulsante4, INPUT_PULLUP);

  //------------------------
  rtc.begin();
  lcd.begin(16,2);

  tNow = millis();
  
  }

void loop() {
  ora_lcd();
  int timeOn= hOn*60 + mOn; // ORA ACCENSIONE
  int timeOff= hOff*60 + mOff; //ORA SPEGNIMENTO
  
  DateTime tempo = rtc.now();
  int oraAdesso = tempo.hour()*60 + tempo.minute();

/*CAMBIEREI QUESTE ISTRUZIONI
  if(statoEffetti == 0){
    if (oraAdesso > timeOn){
      statoEffetti = 1;
      }
      if (statoEffetti == 1){
        controllo_luci();
        statoEffetti = 0;        
        }
   }
*/
//IN QUESO MODO
  if (oraAdesso >= timeOn && oraAdesso <= timeOff) {
    controllo_luci();
  }
  else {
    azione = 0;
  }
//QUI GESTIONE PULSANTI
}
void controllo_luci() {
/*===========================================
La funzione millis() serve a scandire il passaggio del tempo. Il tuo diagramma temporale prevede cambiamenti di illuminazione al minimo ogni 5 minuti, quindi è inutile l'istruzione
  if (millis() - tNow >= 100)
perché non devi cambiare illuminazione ogni 100ms bensì al più ogni 5 min. Quindi l'istruzione diventa
  if (millis() - tNow >= 300000) {	//300000 sono i millisecondi in 5 minuti
    tNow = millis();
    //QUI METTI LE AZIONI DA FARE OGNI 5 minuti
  }
===========================================*/
  if (millis() - tNow >= 300000) {	//300000 sono i millisecondi in 5 minuti
    tNow = millis();
    switch (azione) {
    case (1):   //sono passati 5 minuti dall'ora X
//    ROSSO = 100
//    VERDE = 0
//    BLU = 0
      break;
    case (2):   //sono passati 10 minuti dall'ora X
//    ROSSO = 127
//    VERDE = 50
//    BLU = 0
      break;
    case (3):   //sono passati 15 minuti dall'ora X
//    ROSSO = 255
//    VERDE = 165
//    BLU = 0
      greak;
    case (4):   //sono passati 20 minuti dall'ora X
//    ROSSO = 255
//    VERDE = 255
//    BLU = 0
      break;
    case (6):   //sono passati 30 minuti dall'ora X
//    ROSSO = 0
//    VERDE = 0
//    BLU = 0
//    BIANCO = 255
      break;
    case (96):  //sono passate 8 ore dall'ora X
//    BIANCO = 100
      break;
    case (97):  //sono passate 8 ore e 5 minuti dall'ora X
//    ROSSO = 255
//    VERDE = 255
//    BLU = 0
//    BIANCO = 0
      break;
//...e così via. Fino a
    case (108):   //sono passate 9 0re dall'ora X
//    ROSSO = 0
//    VERDE = 0
//    BLU = 0
//    BIANCO = 0
      break;
      //METTERE QUI FLAG FINITO
    default:
      break;
    }  //FINE switch... case
    azione = azione + 1;
  }  //FINE if (millis...
}  //FINE funzione controllo_luci()

La funzione NON È BLOCCANTE, quindi puoi mettere la gestione pulsanti, o altre istruzioni nel loop().

Ciao,
P.