accensione ogni 5 minuti con millis

buongiorno a tutti,
sto provando a usare millis ha qualche problema.
vorrei che il mio codice preveda l'attivazione di un relè per 10 secondi ogni 5 minuti.
purtroppo con il mio codice riesco a farlo ogni 20 secondi, non oltre.
il mio codice:

unsigned long tempo;                // memorizza il tempo da quando Arduino è stato avviato
  unsigned long ciclo_time = 0;   // memorizza il tempo alla fine di ogni ciclo
  int tempo_high=10000;     // tempo in millisecondi in cui il rele deve rimanere acceso
  int tempo_low=20000;     // tempo in millisecondi in cui il rele deve rimanere spento



void setup()  
pinMode(relay, OUTPUT);

void loop()
 { 
   tempo=millis();
   if(tempo>ciclo_time+tempo_low)   // se tempo è maggiore di (ciclo_time+tempo_low) accendi il rele
  {
    digitalWrite(relay, HIGH);

  }
   if(tempo>ciclo_time+(tempo_low+tempo_high))    // se tempo è maggiore di (ciclo_time+(tempo_low+tempo_high)) spegni il role
  {
     digitalWrite(rele, LOW);

    lampeggio_time=millis();            // finito il ciclo la variabile ciclo_time viene aggiornata con i millis() attuali
  }

se incremento il valore di tempo_low per arrivare ai 5 minuti non si attiva il reale.
ho letto diversi post e i diversi articoli che consigliate ma non riesco a venirne fuori.
dove sbaglio?

Secondo me ti converrebbe gestire tutto con una "macchina a stati finiti" che semplificandola al massimo puoi vedere come uno switch o una serie di if/else tipo:

if(StatoAttuale==STO_ASPETTANDO_CHE_PASSINO_5_MINUTI)
{
  if(millis()-tempoPrecedente>tempo_low)
  { 
     digitalWrite(relay, HIGH);
     tempoPrecedente = millis();
     StatoAttuale = RELAY_ATTIVO_ASPETTO_10_SECONDI;
  }
}
else
{
  if(StatoAttuale==RELAY_ATTIVO_ASPETTO_10_SECONDI)
  {
    if(millis()-tempoPrecedente>tempo_high)
    {
      digitalWrite(relay, LOW);
      tempoPrecedente = millis();
      StatoAttuale = STO_ASPETTANDO_CHE_PASSINO_5_MINUTI;
    }
  }
}

C'è modo di scriverlo più sintetico... si, così è dì'immediata comprensione (almeno spero) a te ottimizzarlo.
Alcuni errori che noto nel programma:

  1. Non è il programma che stai usando perché ci sono errori, quando posti posta tutto aiuti ad aiutarti
  2. la variabile tempo è superflua
  3. Il test di millis() così come l'hai scritto soffre del buffer overflow sotto ti metto alcuni link utili
  4. lampeggio_time nonm è definita
  5. il setup non ha le graffe d'apertura e chiusura
  6. tempo_low è int se devi superare i 32767 millisecondi (e 5 minuti li superano) non può essere definita int

per capire le basi con cui si usa millis() consiglio prima la lettura di QUESTO post esplicativo, dopo di che lo studio di come si usa la funzione millis(), prima QUI, poi QUI e QUI e QUI e tutti gli articoli che sono in QUESTA pagina ... alla fine il tutto dovrebbe essere più chiaro :slight_smile:

grazie, quegli articoli li avevo già letti tutti.
ti allego tutto il mio codice:

#include <DS3231.h>
  #include <LiquidCrystal_I2C.h>
  #include <Wire.h>
  #include <Time.h>
  #include <TimeLib.h>
  #include <DHT.h>
  #include "DHT.h"
  #define DHTPIN 6 // 6 è il pin di Arduino a cui collego il sensore di temperatura
  #define DHTTYPE DHT22 // dht22 è il tipo di sensore che uso
  DHT dht(DHTPIN, DHTTYPE);
  
  #define Isteresi 3
  #define TempImpostata 22
  LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display
  DS3231  rtc(SDA, SCL);

  // Init a Time-data structure
  Time  ti;
  
  
unsigned long tempo;                // memorizza il tempo da quando Arduino è stato avviato
  unsigned long ciclo_time = 0;   // memorizza il tempo alla fine di ogni ciclo
  int tempo_high=10000;     // tempo in millisecondi in cui il rele deve rimanere acceso
  int tempo_low=20000;     // tempo in millisecondi in cui il rele deve rimanere spento


  int relay_luci = 3; // PIN DEL RELè LUCE
  int relayVentolaEntrata = 9;
  int relayVentolaUscita= 10;
  int relay_calore = 8; //calore
  //Setup light cycle for both bars
  const int OraAccensione = 6;     //Accensione luci alle 6:00:00
  const int OraSpegnimento = 21;    // Spegnimento luci alle 21:59:59

  
void setup() 
{
{
  
  
  rtc.begin();
  //The following lines can be uncommented to set the date and time
  //rtc.setDOW(THURSDAY);     
 //rtc.setTime(10,13,00);     
  //rtc.setDate(24, 1, 2019); 
  lcd.begin(16,2);
  lcd.backlight();
  
  pinMode(relay_luci, OUTPUT);
  digitalWrite(relay_luci,LOW);

  pinMode(relayVentolaEntrata, OUTPUT);
  digitalWrite(relayVentolaEntrata, LOW);

  pinMode(relayVentolaUscita, OUTPUT);
  digitalWrite(relayVentolaUscita, LOW);

  pinMode(relay_calore, OUTPUT);
  digitalWrite(relay_calore, LOW);

}
}


void loop() 
{{{ti = rtc.getTime();

    //Bar 1
  if (ti.hour >= OraAccensione && ti.hour < OraSpegnimento)
{
   
  digitalWrite(relay_luci, HIGH);
 float h = dht.readHumidity();
  float t = dht.readTemperature();
  
  lcd.setCursor(1, 0);
  lcd.print(rtc.getTimeStr()); 
  lcd.print(" "); 
  //lcd.print(rtc.getDateStr());  
  /*lcd.print(":");
  lcd.print(ti.min);
  lcd.print(":");
  lcd.print(ti.sec);
  */

 // posiziono il cursore alla colonna 5 e riga 0
  lcd.setCursor(0, 1);
  lcd.print("T:");
  lcd.setCursor(2, 1);    
  lcd.print(t);
  //lcd.setCursor(7, 1);
  //lcd.print("C");
  lcd.setCursor(8, 1);
  lcd.print("Hu:");
  lcd.setCursor(10, 1);
  lcd.print(h);
  lcd.setCursor(15, 1);
  lcd.print("%");

  if (t > TempImpostata)
{
  if (t > TempImpostata + Isteresi)
{
  digitalWrite(relay_calore, LOW);
  digitalWrite(relayVentolaEntrata, HIGH);
  digitalWrite(relayVentolaUscita, HIGH);
}
  else
{
  digitalWrite(relay_calore, LOW);
  digitalWrite(relayVentolaEntrata, LOW);
  digitalWrite(relayVentolaUscita, LOW);
}  
}
  else 
{
  if (t < TempImpostata - Isteresi)
{
  digitalWrite(relay_calore, HIGH);
  digitalWrite(relayVentolaEntrata, LOW);
  digitalWrite(relayVentolaUscita, LOW);
  
}  
}

 { 
   tempo=millis();                      //memorizza i millisecondi nella variabile tempo
   if(tempo>ciclo_time+tempo_low)   // se tempo è maggiore di (ciclo_time+tempo_low) accendi il rele
  {
    digitalWrite(relayVentolaEntrata, HIGH);
     digitalWrite(relayVentolaUscita, HIGH);

  }
   if(tempo>ciclo_time+(tempo_low+tempo_high))    // se tempo è maggiore di (ciclo_time+(tempo_low+tempo_high)) spegni il rele
  {
     digitalWrite(relayVentolaEntrata, LOW);
     digitalWrite(relayVentolaUscita, LOW);

    ciclo_time=millis();            // finito il ciclo la variabile ciclo_time viene aggiornata con i millis() attuali
  }

    


}}

  
  else if (ti.hour >= OraSpegnimento || ti.hour < OraAccensione)
{
  digitalWrite(relay_luci, LOW);
  digitalWrite(relay_calore, LOW);
  digitalWrite(relayVentolaEntrata, LOW);
  digitalWrite(relayVentolaUscita, LOW);
}
} 
}
}

Li avrai anche letti ma non li hai messi in pratica, inoltre il tuo programma èp infarcito di mille mila parentesi graffe aperte e chiuse senza motivo (ma che erano in saldo? :slight_smile: ) ad esempio già nel setup ne apri/chiudi due anziché 1 come dovrebbe essere e nel loop poi è un vero e proprio florilegio di parentesi graffe innutili.
Sicuramente è frutto di innumerevoli copiaincolla.
Per prima cosa prova a modficareil programma in modo da avere le sole graffe minime necessarie (una per if, una per le varie funzioni, ecc.) e poi metti in pratica quanto ti ho suggerito come modifica alla parte che regola la temporizzazione on/off del relay.

grazie, stasera darò una pulita alle graffe. Ho realizzato il codice a step e nell'assemblarlo ho portato dietro tutto.

Sto cercando di mettere in pratica quanto suggerito, stasera proverò questo codice:

unsigned long accensione;     // variabile usata per contare i millisecondi trascorsi dall'accensione di Arduino
unsigned long tempoventole = 0;        // variabile usata per stabilire quando dovrà accendersi il primo led

void setup() {
 
pinMode(11,OUTPUT);
pinMode(12,OUTPUT);
digitalWrite(11,LOW);
digitalWrite(12,LOW);
}
 
void loop() {
 
accensione = millis();                   // memorizzo millis() nella variabile accensione
if(accensione >= 10000)                 // Dopo 10 secondi la variabile accensione viene azzerata
{
accensione = 0;
accensione = millis();
}
 
// le ventole vengono accese dopo 5 minuti dall'avvio di arduino e spente dopo 1 minuto
 
if(accensione > tempoventole + 300000) // 5 minuti
{
digitalWrite(11,HIGH);
digitalWrite(12,HIGH);
tempoventole = millis();
}
 
if(accensione > tempoventole + 60000)
{
digitalWrite(11,LOW);
digitalWrite(12,LOW);
 
}
 

}

è corretto ragionare in questa maniera?

grazie ancora

Bene la pulizia del codice, male male male la logica.
Il primo if non serve assolutamente a nulla, ad ogni ciclo di loop assegna alla variabile accensuione il valore di millis() dopo dieci secondi non fai altro che azzerarla e assegnare nuovamente il valore di millis().
Poi aspetti 5 minuti (a prescindere dal primo if che come detto non serve e non fa nulla di utile) perché tempoventole vale zero. Dopo 5 minuti accendi e da questo momento crolla tutto perché tempoventole varrà sempre millis() e il minuto non passerà più essendo che anche accensione vale millis(), pochi milliseocndi di differenza ma mai dieci secondi.
Inoltre non c'è traccia della macchina a stati finiti e tu ne hai bisogno. Detto che non capisco se dopo sei minuti spegni arduino e poi lo riaccendi (e non ne capisco il motivo) o se semplicemente avvii tutto e devi fare un solo ciclo di un minuto dopo 5 minuti e poi nientaltro e allora perchè mettere in piedi una MCU quando con un cavolo di relé temporizzato puoi fare la medesima cosa?
Detto ciò devi riveder il modo di ragionare partendo da una base di una macchina a stati finiti che nel tuo caso sono due:

  1. primo_avvio: Attendo 5 minuti senza fare nient'altro, trascorsi 5 minuti passo allo stato accensione
  2. accensione: Attendo 1 minuto e poi spengo tutto
    Non capendo i 10 secondi iniziali li hoomessi, se devi aspettare 5 minuti + 10 secondi non ti serve un altro stato se invece nei primi 10 secondi devi fare qualcosa allora diventano tre stati:
  3. primo_avvio: faccio qualcosa, trascorsi 10 secondi cambio e vado in attesa_accensione
  4. attesa_accensione: aspetto 5 minuti e poi accedo e vado nello stato accensione
  5. accensione: attendo un minuto e spengo tutto

niente, non mi entra in testa sta macchina a stati finiti; deve ripetersi in continuo, le ventole devono accendersi e spegnersi mentre tutto il resto del codice procederà (accensione luci, accensione calore, etc).
grazie della pazienza, proverò a ragionare come suggerisci.

Guarda credo che anche millis() non ti sia proprio chiaro o comunque è gestito non nel miglior modo possibile ti consiglio di guardare QUI, poi QUI e QUI.
Poi mi fermerei un attimo e ripartirei facendo un semplice compito ovvero accendere le ventole per 1 minuto a seguito della pressione di un pulsante, ovvero premi il pulsante le ventole si accendono per un minuto e poi si spengono, alla successiva pressione si riaccendono per un minuto e così via. Se premi il pulsante con ventole accese prima che sia trascorso il minuto non devi considerare la pressione del pulsante (ovvero non si deve estendere il tempo d'accensione).
Quando questo funziona allora potrai estendere con le altre gestioni (attesa di 5 minuti dopo l'evento)

gli articoli sono gli stessi che mi hai consigliato ieri, li ho già letti, li rileggerò e farò delle prove per capire meglio millis e macchina a stati finiti. farò anche il test con ventola e pulsante.
purtroppo però al momento non posso fermarmi a fare i compiti, ho un progetto in piedi e devo riuscire a far partire quelle ventole ogni 5 minuti; ogni giorno che passa rischio di buttare tutto ciò che ruota intorno a questo progetto.
grazie ancora per il supporto ed i consigli.

aquilacieca:
purtroppo però al momento non posso fermarmi a fare i compiti, ho un progetto in piedi e devo riuscire a far partire quelle ventole ogni 5 minuti; ogni giorno che passa rischio di buttare tutto ciò che ruota intorno a questo progetto.
grazie ancora per il supporto ed i consigli.

Scusa se sembro brutale ma allora se non hai tempo di imparare per fare ciò che devi piglia un relé temporizzato e con arduino lo alimenti quando vuoi che tra 5 mintui le ventole si accendano per un minuto e fine, qundo avrai modo ti metterai ad imparare ciò che serve e realizzerai il tutto con Arduino, daltronte se hai una scadenza non vedo come altro puoi porre rimedio se non affidando la realizazione a qualcuno che sia in condizioen di farlo nei tempi richiesti

fabpolli:
Scusa se sembro brutale ma allora se non hai tempo di imparare per fare ciò che devi piglia un relé temporizzato e con arduino lo alimenti quando vuoi che tra 5 mintui le ventole si accendano per un minuto e fine, qundo avrai modo ti metterai ad imparare ciò che serve e realizzerai il tutto con Arduino, daltronte se hai una scadenza non vedo come altro puoi porre rimedio se non affidando la realizazione a qualcuno che sia in condizioen di farlo nei tempi richiesti

Cosi farò visto che credevo fosse più semplice da mettere in pratica.

grazie ancora e buona giornata.

Io farei così (ho aggiustato qualche cosa da quando l'ho pubblicato):

#define PAUSA 300000 // 5min *60s/min *1000ms/s
#define DURATA 10000 // 10s *1000ms/s
#define RELE 5 // Pin a cui è collegato il relè

unsigned long t1=0;
byte on=0; // bool occuperebbe comunque 1 byte.

void setup()
{pinMode(RELE, OUTPUT);}

void loop()
{
if(millis()-t1>PAUSA && on==0)
  {on=1; digitalWrite(RELE, HIGH);} // Se è trascorsa la pausa, accende
if(millis()-t1>PAUSA+DURATA)
  {on=0; t1=millis(); digitalWrite(RELE, LOW);} // Se è trascorsa anche la durata, spegne e azzera.
}

Datman:

...

{on=0; t1=0; digitalWrite(RELE, LOW);}
}

mi sfugge qualcosa o t1 non dovrebbe diventare di volta in volta t1 = t1 + durata + pausa :confused:

Grazie per avermi fatto notare l'errore.
In realtà dovevo "azzerare" allo scadere della DURATA ponendo t1=millis(). Adesso ho corretto.

Datman:
Grazie per avermi fatto notare l'errore.
In realtà dovevo "azzerare" allo scadere della DURATA ponendo t1=millis(). Adesso ho corretto.

Il sistema suggerito da -zef- è più preciso per tempi esattamente periodici, ma in questo caso credo che la precisione non conti.

grazie a tutti per il supporto.
ho caricato il codice gentilmente postato, per accorciare l'attesa ho messo come pausa 30 secondi e come durata 10 secondi.
purtroppo dopo 30 secondi il reale scatta per un istante piccolissimo poi non si riattiva più. non accade più nulla. il codice inserito è identico in tutto e per tutto a quello postato da voi.

io lo ho provato, e funziona benissimo, OK al primo tentativo
è quindi evidente che hai sbagliato qualcosa..........,
ricontrolla il programma
oppure prova senza rele', usando il pin 13
se così va prova a vedere che tipo di "difesa" hai contro i disturbi del relè

Confermo. Ho provato anch'io sul 13 e funziona.
Mi sa che quando scatta il relè si pianta il processore...

Risolto, avevo un if dopo basato sulle temperature che "annullava" il relè della ventola.
Grazie ancora per l'aiuto

Prego! :slight_smile:

Ciao