Arduino utilizzato come timer luci... 24 ore

Ciao, non riesco a capire come programmare semplicemente un contatore che mi accenda tramite pin digitale e relay una luce per tot ore al giorno.
tipo setto il tempo a 7 ore
premo un pulsante per far partire il tempo
il pin va in HIGH per le ore richieste e poi in LOW per le restanti ore del giorno..

praticamente un temporizzatore senza usare un modulo che gestisce orario

l'effetto sarebbe 7 ore di luce ---> (24-7) 17 ore di buio

Poi magari dovrei poter impostare la variabile ORE_DI_LUCE con un potenziometro che mi fa range 0-24

ho provato in vari modi.. ma non riesco a fare cicli di 24 ore..

Probabilmente ti è utile QUESTA libreria :wink:

Guglielmo

O anche con millis()...
Secondi in un'ora = 3600
Millisecondi in un'ora = 3600 * 1000 = 3600000
e poi il classico
if (millis() - iniziomillis >= intervallomillis) buio else luce.

@ paulus1969 : quella ti va bene se ON -> OFF sono nello stesso giorno ... malauguratamente devi accendere una luce ... diciamo alle 17:00 e spegnere alle 05:00 (... che so io, immagina un'insegna luminosa) ... la cosa non è più così facile :wink:

Guglielmo

Dalla sua richiesta, leggo:

premo un pulsante per far partire il tempo

quindi gli serve solo un conteggio delle ore trascorse da quando lo ha premuto.

Vuole anche mettere un potenziometro per regolare la durata, si fa un bel map (potenziometro, 0, 1023, 1, 24), magari con un piccolo display (certo sarebbe più carino mettere un encoder ottico rotativo e regolare con la precisione del minuto) e se ne è uscito.

una cosa del genere? oppure ci sono modi piu semplici?

int SEC;
int MIN;
int TEMPO=2;
int RELAY=13;

void setup() {

  Serial.begin(9600);

  pinMode(13, OUTPUT);
  pinMode(2, INPUT);
  
}


void loop() {
  

  Serial.print(MIN);
  Serial.print(":");
  Serial.println(SEC);
  
  delay(1000);   
  SEC=SEC++;
  int START = digitalRead (2);
    Serial.println("");
  Serial.print(START);
      Serial.println("_pulsante start 24ore");
    Serial.print(TEMPO);     
    Serial.println("_valore temporizzato in minuti");
        Serial.print(RELAY);     
    Serial.println("_uscita relay");

  
  if (START==1){
      SEC=0;
      MIN=0;
  }
  
  if (SEC==60){
  SEC=0;
  MIN=MIN++;
  }
  
  if (MIN==4){ //1440 minuti = 24 ore
  SEC=0;
  MIN=0;
  }
  
  if (TEMPO>MIN){
    
  digitalWrite (RELAY, HIGH);
    }
   else {
   digitalWrite (RELAY, LOW);
    }
  
 
 
}

Forse modi più complicati :wink:
Di che precisione hai bisogno? Se imposto 6 ore devono essere 6 ore esatte o ti va bene anche uno scarto? Sappi che l'Arduino non è molto preciso a tenere il tempo, colpa del risonatore ceramico usato come fonte di clock (si parla anche di minuti/ora). La lib swRTC che Guglielmo ti citava introduce anche una piccola correzione dello scarto temporale fra orario misurato ed orario reale ma non può neanch'essa fare miracoli. Per precisioni maggiori ti serve un piccolo RTC, ossia un chippino esterno che funziona come orologio hardware.

non mi serve una gran precisione... di che scarto parliamo nell'arco di una giornata?
quanto incide la complessità del programma sul delay?

Come detto, minuti/ora. Cioè qualche minuto all'ora.

Non ho capito la tua seconda frase, usando un RTC esterno non usi delay, ma fai una lettura del tempo dal chip. Sicuramente è un sistema più complesso di quello che hai fatto tu ora.

no.. scusa mi sono spiegato male...
non volevo usare RTC esterno perchè non mi serve precisione... (se sballa di 15 minuti al giorno piu' andare bene...) anche se posso aggiustarlo diminuendo o aumentando i minuti totali giornalieri.. o no... 1445 - 1435

intendevo chiedere se un utilizzo (come codice come messo in post precedente) in un programma un po piu complesso causa ritardi del delay (dei cicli) cioè aumenta il delay...1000

Il problema è che tu aspetti 1000 ms poi esegui altri compiti. Finché sono poche cose il loro impatto è minimo, se ne devi eseguire di più la cosa può diventare misurabile su lunghi intervalli.

Per evitare questo, devi misurare il tempo usando millis. Guarda l'esempio BlinkWithoutDelay e magari leggi anche questo mio articolo.

leo72:
Il problema è che tu aspetti 1000 ms poi esegui altri compiti. Finché sono poche cose il loro impatto è minimo, se ne devi eseguire di più la cosa può diventare misurabile su lunghi intervalli.

Per evitare questo, devi misurare il tempo usando millis. Guarda l'esempio BlinkWithoutDelay e magari leggi anche questo mio articolo.

interessante... ma mi si sta incriccando il cervello per cercare di capire come trasformare il codice scritto prima usando millis


quando premo pulsante mi segno i millis su una variabile (posso segnarlo in minuti?)

lasciando stare la sintassi...

int TIME=currentMillis/60000 // leggere direttamente in minuti
int POTENZ=analogread*0.71 //per rapportare la lettura massima 1023 a 1440 minuti = 24 ore
poi..

if TIME +POTENZ > TIME
led HIGH
else LOW

... giusto?

Creati una funzione che richiami dal loop principale. In quella funzione controlli se l’intervallo di tempo fra il precedente valore di millis e l’attuale è superiore a 1000, quindi è passato 1 secondo. Se sì, aggiorni a cascata le variabili di secondi/minuti/ore.

ho provato a trasformare tutto utilizzando i millis.... così ma non funziona... quando il pulsante (2) torna in LOW non mi riparte la conta dei minuti ma mi divide i millis passati per 60000 e il timer ritorna alla lettura reale e non si azzera...

devo dirgli che TIMEMIN si incrementa di +uno ogni 60000 millis e non di trasformare i millis in minuti.. come faccio?

allego codice...

long TIME;   //non mi gestisce una giornata di 24 ore? 60000x60x24= 86'400'000
            // devo usare float? 
int TIMEMIN;
int POTE_ANALOG;
int ON;
int ONORA;
int START;



void setup() {

   pinMode(13, OUTPUT);
  Serial.begin(9600);  
}

void loop()
{
 
TIME = millis();
TIMEMIN = (TIME / 60000); // trasformo in minuti
POTE_ANALOG = analogRead (A1); // leggo potenziomentro
ON = (POTE_ANALOG / 0.71); // Trasformo lettura potenziometro in MINUTI/GIORNO
ONORA = (ON / 60); // Trasformo ON in ORE - solo per mio controllo
START = digitalRead (2); // polsante di inizio timer


//istruzoni

if (ON > TIMEMIN) {
  digitalWrite (13, HIGH);
}
else {
   digitalWrite (13, LOW);
}

if (START == 1) {
  TIMEMIN = 0;
}


// monitor seriale
Serial.print("Minuti: ");
Serial.println(TIMEMIN);
Serial.print("Millis: ");
Serial.println(TIME);
Serial.print("Potenziometro: ");
Serial.println(POTE_ANALOG);
Serial.print("Tempo ON in minuti: ");
Serial.println(ON);
Serial.print("Tempo ON in ore: ");
Serial.println(ONORA);

Serial.println("");
delay (1000);
  }

leo72:
In quella funzione controlli se l'intervallo di tempo fra il precedente valore di millis e l'attuale è superiore a 1000

si ma come ? come faccio a paragonare dei millis passati con quelli attuali?
se attribuisco i millis a una variabile questa mi si incrementa a ogni ciclo macchina... ammetto la mia ignoranza ... :~

Credo di aver risolto... alle volte è la strada piu' semplice quella giusta... ho messo una variabile dove trasferire la lettura dei millis al premere del pulsante e poi dico di accendere per il tempo letto prima + il tempo selezionato con il potenziometro..... ora l'unico dubbio è che la variabili "LONG" non mi può contenere 86'400'000 millisecondi che sono i millisecondi di 24 ore...

allego codice.

long TIME;   //non mi gestisce una giornata di 24 ore? 60000x60x24= 86'400'000
            // devo usare float? 
int TIMEMIN; // inizializzo variabile tempo trasformata in minuti
int POTE_ANALOG; // inizializzo variabile valore potenziometro da 0 a 1024
int ON; //Inizializzo variabile tempo in minuti di illuminazione trasformando da scala 0-1024 a scala 0-1440 che sono i minuti in 24 ore
int ONORA; // inizializzo variabile tempo accensione trasformato in ore  solo per mia visione
int START; // inizializzo variabile pulsante partenza conteggio
int LETTURATIMEMIN; // inizializzo una variabile dove mettere la lettura timemin quando premo pulsante
int TMON; // sommo la lettura timemin quando premo pulsante ai minuti di accensione previsti

int PINRELAY=13; //pin relay
int PINPOTENZ=A1; //pin potenziometro tempo
int PINPULS=2; //pin pulsante


void setup() {

   pinMode(PINRELAY, OUTPUT);
  Serial.begin(9600);  
}

void loop()
{
 
TIME = millis();
TIMEMIN = (TIME / 60000); // trasformo in minuti
POTE_ANALOG = analogRead (PINPOTENZ); // leggo potenziomentro
ON = (POTE_ANALOG / 0.71); // Trasformo lettura potenziometro in MINUTI/GIORNO
ONORA = (ON / 60); // Trasformo ON in ORE - solo per mio controllo
START = digitalRead (PINPULS); // polsante di inizio timer
TMON = ( LETTURATIMEMIN + ON);


//istruzoni

if (TMON>TIMEMIN) {
  digitalWrite (13, HIGH);
}
else {
   digitalWrite (13, LOW);
}

if (START == 1) {
  LETTURATIMEMIN = TIMEMIN;
}


// monitor seriale
Serial.print("Minuti: ");
Serial.println(TIMEMIN);
Serial.print("Millis: ");
Serial.println(TIME);
Serial.print("Potenziometro: ");
Serial.println(POTE_ANALOG);
Serial.print("Tempo ON in minuti: ");
Serial.println(ON);
Serial.print("Tempo ON in ore: ");
Serial.println(ONORA);
Serial.print("LETTURA TIMEMIN: ");
Serial.println(LETTURATIMEMIN);
Serial.print("LETTURA TMON: ");
Serial.println(TMON);

Serial.println("");
delay (1000);
  }

MI sa che sbagli calcoli, una variabile a 32 bit può contenere valori molto superiori a 86400000 :stuck_out_tongue:
Se prendiamo un signed long, i valori gestibili vanno da -2147483648 a +2147483647. Se prendiamo un unsigned long andiamo da 0 a 4294967295.

Siccome millis dà un unsigned long, DEVI usare un unsigned long per memorizzare il suo valore, quindi non long TIME ma unsigned long TIME. :wink:

ok perfetto.... avevo un manuale ma non parlava di unsigned long e signed long ... solo di long... :~

no ok… posso usare “unsigned long” che arriva fino a … +2’147’483’647

ora pero’ devo inserire i giorni che passano osseno mi parte solo la prima volta e non tutti i giorni…

aggiungo 1 variabile giorni da sommare al tempo di accensione… NO!!!

------ DEVO RITORNARE AL DELAY… O CAMBIARE STRATEGIA… -------
MI SONO APPENA ACCORTO CHE PRIMA O POI I MILLIS SI AZZERERANNO… ed è un casino… devo cambiare approcio.

vabbè comunque ho imparato qualcosa :smiley:

ora provo ad utilizzare questa libreria… http://www.leonardomiliani.com/2011/swrtc-un-orologio-in-tempo-reale-via-software/#wpfb-file-23

CASPA:
------ DEVO RITORNARE AL DELAY... O CAMBIARE STRATEGIA.... -------
MI SONO APPENA ACCORTO CHE PRIMA O POI I MILLIS SI AZZERERANNO... ed è un casino.... devo cambiare approcio.

No, non serve, basta scegliere il GIUSTO approccio ... guarda QUI

Guglielmo