Accensione e spegnimento temporizzato led

Ciao a tutti!

Sto cercando di far funzionare un programma relativamente semplice:

  1. legge il valore della fotoresistenza
  2. se inferiore a 512 accende il led per 10 secondi e poi lo spegne per 20 secondi
  3. se superiore a 512 lo spegne per 20 secondi

Sto continuando a provare da diversi giorni, ormai non so più che pesci pigliare.
Questo è il codice che ho attualmente:

#define LED 6
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7,3,POSITIVE);
unsigned long TempTime=0;
unsigned long LedTime=0;
unsigned long LedCycle=0;
int ValTemp;
int ValTempMin=1023;
int Counter=0;
int Temp=0;

void setup() {
  pinMode(LED,OUTPUT); //indica output
  delay(3000); //attendi 3 secondi
}

void loop() {
  unsigned long Check1=millis();
  if(Check1-TempTime>=5000){
    TempTime=Check1; //controlla la fotoresistenza ogni 5 secondi
    ValTemp=analogRead(A0); //leggi il valore di temperatura
    ValTempMin=min(ValTemp,ValTempMin); //confronta i valori e trova il minore
    lcd.setCursor(2,0); //setta il cursore in posizione
    lcd.print(ValTemp); //scrivi il valore rilevato
    lcd.setCursor(11,0); //setta il cursore in posizione
    lcd.print(ValTempMin); //scrivi il valore minimo
  }
  unsigned long Check2=millis();
  if(Check2-LedCycle>=20000){
    LedCycle=Check2; //controlla il led ogni 20 secondi
    Temp=analogRead(A0); //leggi il valore di temperatura
    Startup(); //esegui void
  }
}

void Startup() {
  if(Temp<512){
    On(); //esegui void
  }
  else{
    Off(); //esegui void
  }
}

void On() {
  LedTime=millis(); //inizia il conteggio
  if(millis()-LedTime<10000){
    digitalWrite(LED,HIGH); //accendi l'output
    Counter++; //aumenta di 1
    lcd.setCursor(14,1); //setta il cursore in posizione
    lcd.print(Counter); //scrivi il valore
  }
  else{
    digitalWrite(LED,LOW); //spegni l'output
  }
}

void Off() {
  LedTime=millis(); //inizia il conteggio
  if(millis()-LedTime<20000){
    digitalWrite(LED,LOW); //spegni l'output
    }
}

Quando esegue il void On() è come se non capisse che deve spegnere il led dopo 10 secondi, rimane acceso.

Qualche suggerimento?

SI, uno solo: riparti da capo quando un progetto non va si fa prima a ripaertire che perdere tempo a salvarlo
inoltre mi sembra che hai messo troppi punti dove controlli troppi tempi
semplificati, non gestire lo LCD per adesso
e chiarisci cosa significa:

  1. se superiore a 512 lo spegne per 20 secondi

e lo tiene acceso per quanto? oppure vuoi dire che per 20 secondi, a led spento NON legge la fotocellula?

Standardoil:
SI, uno solo: riparti da capo quando un progetto non va si fa prima a ripaertire che perdere tempo a salvarlo
inoltre mi sembra che hai messo troppi punti dove controlli troppi tempi
semplificati, non gestire lo LCD per adesso
e chiarisci cosa significa:

  1. se superiore a 512 lo spegne per 20 secondi

e lo tiene acceso per quanto? oppure vuoi dire che per 20 secondi, a led spento NON legge la fotocellula?

Si, volevo far aggiornare la Temp ogni 5 secondi e scrivere il valore sull'lcd.

Nell 3) intendevo che il led rimane spento per 20 secondi, terminati questi il programma rilegge la fotocellula e ricomincia il ciclo.

OK, per il momento non guarderei troppo per il sottile, la lettura ogni 5 secondi dopo
io farei un ciclo semplice
primo spengo (che male non fa mai)
poi un semplice test, analogread < di soglia
se si accendi e carica un timer a 10 secondi
se no carica un timer a 20 secondi
come prima cosa puoi provare con dei delay, per poi passare a millis

#define LED 6
int Temp = 0;

void setup() {
  digitalWrite(LED,LOW);
  delay(1000);
}

void loop() {
  Temp=analogRead(A0);
  if(Temp<512){
    digitalWrite(LED,HIGH);
    delay(10000);
  }
  else{
    digitalWrite(LED,LOW);
    delay(20000);
  }
}

E fino a qui tutto ok. Adesso provo con i millis.

Vai…

domanda strana: funziona? Non vedo a pinMode per settare il pin del led ad output.
Comunque se stai usando una Arduino Uno (più comune) e non usi quel pin per altro, puoi usare come pin led il 13, sul quale è già collegato un led

#define LED 6
int Temp=0;
unsigned long Shutdown=0;
unsigned long OnTimer=0;


void setup() {
  Serial.begin(9600);
  pinMode(LED,OUTPUT);
  delay(1000);
}

void loop() {
  digitalWrite(LED,LOW);
  Temp=analogRead(A0);  //leggi il valore analogico
  Shutdown=millis()+20000;  //inizia il conteggio
  if(Temp<512){   //se il valore è inferiore a 512
    digitalWrite(LED,HIGH);  //accendi il led
    OnTimer=millis()+10000;  //inizia il conteggio
    if(OnTimer<millis()&&Shutdown<millis()){  //10 secondi dopo l'accensione e fino a 20 secondi
      digitalWrite(LED,LOW);  //spegni il led
    }
    Temp=1023;  //resetta il valore analogico al massimo
    OnTimer=millis()+10000;  //resetta il conteggio
    Shutdown=millis()+20000;  //resetta il conteggio
  }
  else{  //se il valore è superiore a 512
    digitalWrite(LED,LOW);  //spegni il led
    Serial.println("off");  //scrivi off
    if(Shutdown<millis()){  //se sono trascorsi più di 20 secondi
      Shutdown=millis()+20000;  //resetta il conteggio
    }
  }
}

Immagino sia una cosa del genere, però mi sfugge qualcosa…

Silente:
domanda strana: funziona? Non vedo a pinMode per settare il pin del led ad output.
Comunque se stai usando una Arduino Uno (più comune) e non usi quel pin per altro, puoi usare come pin led il 13, sul quale è già collegato un led

Si funziona senza specificare il pinMode, forse grazie al #define LED 6(?)

gagliardo:
Si funziona senza specificare il pinMode, forse grazie al #define LED 6(?)

No, funziona per pura fortuna, la define semplicemente dice al compilatore di mettre 6 ogni volta che trova la scritta LED, in realtà il pinMode c'è ma è sul pin errato, per modificare il programma in modo che sia corretto basta modificare

pinMode(7,OUTPUT);

in

pinMode(LED,OUTPUT);

Si avevo fatto un po di confusione, lo ho sistemato.

Comunque quando rileva un valore >512 il led si spegne. Quando rileva un valore <512 il led rimane acceso.

Praticamente non conteggia il tempo trascorso.

avanti un passo.
Provo a ragionare liberamente, cme se fossi io da solo a riflettere sul problema
risscrivendo le tue specifiche (sempre pensare a cmabiate l'ordine dei fattori, il risultato non cambia, la complessità forse sì)
dicevo riscrivo le tue specifiche: se c'è luce accendo per 10 secondi, poi spengo per venti
se invece non c'è luce aspetto 20 secondi per provare di nuovo
ancora: provo, aspetto 20 secondi, provo di nuovo, aspetto 20 secondi, provo di nuovo, aspetto20 etc etc, ma se quando provo trovo luce accendo e aspetto 10 secondi
proviamo a scriverlo, sempre in italiano, ma un po' formale, quasi come un programma

ciclo ripetuto sempre:
    Vedo se c'è luce
    Se c'è:
         Accendo il led
         aspetto 10 secondi
         Spengo il led
    Altrimenti 
         Aspetto 20 secondi
    Ripeto il ciclo

il problema sono le attese, senza delay, usando millis. per il momento ignoriamo il problema dello owerflow di millis, facciamo finta che non ci sia
ri-scriviamo di nuovo le specifiche: se ho il led accceso sto aspettando 10 secondi, invece se ho il led spento ne sto aspettando 20
il testo può essere una cosa del tipo:

se millis> target
dove target è il tempo che devo aspettare
se il led è acceso
lo spengo
adesso devo aspettare 20 secondi
target = millis+20000
altrimenti
provo la luminosità
se OK
accendo il led
adesso devo aspettare solo 10 secondi
altrimenti
non accendo il led
e aspetto 20 secondi
fine del ciclo

Sono sicuro che non è difficile tradurlo in una loop funzionante
poi s pensa al display con misure ogni 5 secondi
e poi si pensa allo overflow della millis

Standardoil:
... per il momento ignoriamo il problema dello owerflow di millis ...

Se il confronto è scritto come si deve, lo puoi sempre ignorare, anzi, è cosa da non prendere nemmeno in considerazione.

Guglielmo

secondo te quindi al momento si può mettere al fuoco anche questa bistecca?

HUUU a proposito
scegli se leggi una luminosità o una temperatura, e metti consistenti nomi di variabili e commenti, prima regola del buon programmatore secondo Nelson (che sono io):

Non generare confusione e butta via la spazzatura

Standardoil:
secondo te quindi al momento si può mettere al fuoco anche questa bistecca?

Secondo me, se uno NON solleva proprio l'"inesistente" problema e mette direttamente il giusto IF ... in generale, l'utente si incasina di meno :wink:

Guglielmo

Vero, ma io lo IF non lo ho messo, me ne guardo bene
ho già fatto una volta l'errore di scrivere il programma per uno OP, e mi ha cazziato nvece di ringraziarmi
adesso il programma se lo scrivono gli OP, e le IF le fanno loro.........

Standardoil:
... ho già fatto una volta l'errore di scrivere il programma per uno OP, e mi ha cazziato nvece di ringraziarmi
adesso il programma se lo scrivono gli OP, e le IF le fanno loro ...

Ahahahahahahahah ... :smiley:

Guglielmo

Diavolo, avevo scritto

if(LED==HIGH){…

e non funzionava… stavo provando da 2 ore :sweat_smile:

Ho sistemato e provato, così funziona perfettamente! Grazie!! PS pensavo che programmare un timer fosse molto più complicato di target=millis()+timer, mi hai aperto un mondo :grinning:

Ho letto qualcosa sull’overflow e per il momento ho capito che devo usare unsigned long, approfondirò con calma. Domani provo ad aggiungere le rilevazioni ogni 5 secondi!

#define LED 7
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7,3,POSITIVE);
int Lum;  //valore analogico fotoresistenza
unsigned long int target=0;  //timer
byte LedState=LOW;  //stato led spento

void loop() {
  if(millis()>target){  //se tempo trascorso è maggiore del timer
    if(LedState==HIGH){  //se lo stato del led è acceso
      LedState=LOW;  //cambia lo stato del led in spento
      digitalWrite(LED,LedState);  //spegni il led
      Serial.println("cool");  //scrivi cool
      target=millis()+20000;  //imposta il timer di 20 secondi
    }
    else{  //se lo stato del led è spento
      Lum=analogRead(A0);  //rileva il valore analogico
      if(Lum>=512){  //se è uguale o superiore a 512
        LedState=LOW;  //cambia lo stato del led in spento
        digitalWrite(LED,LedState);  //spegni il led
        Serial.println("off");  //scrivi off
        target=millis()+20000;  //imposta il timer di 20 secondi
      }
      else{  //se è inferiore a 512
        LedState=HIGH;  //cambia lo stato del led in acceso
        digitalWrite(LED,HIGH);  //accendi il led
        Serial.println("on");  //scrivi on
        target=millis()+10000;  //imposta il timer di 10 secondi
        Lum=1023;  //resetta il valore analogico al massimo
      }
    }
  }
}

gagliardo:
Ho letto qualcosa sull'overflow e per il momento ho capito che devo usare unsigned long, approfondirò con calma.

Ti basta studiare prima QUI, poi QUI ed infine leggi anche QUI e QUI ... vedrai che ti sarà tutto più chiaro :wink:

Guglielmo

Aggiunte anche le rilevazioni luminosità ogni 5 secondi:

unsigned long LumTimer=5000;  //intervallo tra misurazioni di luminosità
unsigned long prevLum=0;  //variabile usata per memorizzare il momento dell'ultima rilevazione
...
if(millis()-prevLum>=LumTimer){
    prevLum=millis();  //esegui ogni 5 secondi
    Lum=analogRead(A0);  //rileva il valore analogico
    minLum=min(Lum,minLum);  //confronta i valori e trova i minore

Da quel che ho capito sull'overflow, la soluzione qui sopra è già ok e fa il rollover da sola.
Quello che bisogna modificare è questo IF:

if(millis()>target){
    ...

Che si potrebbe mettere così immagino:

unsigned long target;
...
if((long)(millis()-target)>=0){

Adesso sarebbe da modificare il registro come scritto QUI per verificare che funzioni