Consiglio su gestione dati letti da fotocella

Sto utilizzando una fotocella per realizzare una lampada crepuscolare a LED ed utilizzo la funzione map() per spalmare il valore analogico su un canale PWM in uscita che ho collegato ad un op-amp con guadagno 2 per gestire un dimmer.

Il tutto funziona molto bene e sono soddisfatto; l'unica pecca è che se in condizioni di oscurità (luce molto bassa) accendo, all'improvviso, una luce molto forte, i valori delle fotocella oscillano e fanno dei "salti" provocando una sorta di lampeggio della lampada che tenta di inseguire i cambiamenti di luce repentina.

Ad esempio, quando il valore della luminosità varia all'improvviso, i valori del PWM cambiano bruscamente per poi assestarsi dopo un certo periodo:

12
12
12
34
32
20
33
34

Mi dareste dei consigli su come controllare quando i valori analogici letti variano bruscamente?
Vorrei riuscire a rilevare i cambiamenti bruschi ed a settare il pwm in maniera opportuna ed in modo graduale.

Il codice che uso adesso è molto banale:

loop(){
//...
if (digitalRead(crepuscolare) == LOW && digitalRead(motion) == HIGH){
   
 digitalWrite(led5, LOW);
 digitalWrite(led7, HIGH); 
   
 Serial.println("Motion ON");
 
 int pirVal = digitalRead(pirPin);

 if(pirVal == LOW){ //was motion detected
  
    Serial.println("Motion Detected");
    for ( int i = 0; i < 20; i++){  // 20 secondi
    photocellReading = analogRead(photocellPin);  
    Serial.println(i);
    Serial.print("Analog reading = ");
    Serial.println(photocellReading);     
    
    LEDbrightness = map(photocellReading, 0, 1023, 255, 0);
    bright = LEDbrightness;
    Serial.println(bright);
    analogWrite(LEDpin, bright); 
 
    delay(1000);
    if ( digitalRead(pirPin) == LOW ){
    Serial.println("Reset, continua da zero!");  
    i = 0;
    }
    else if ( (digitalRead(crepuscolare) == HIGH && digitalRead(motion) == HIGH) || (digitalRead(crepuscolare) == HIGH && digitalRead(motion) == LOW) || (digitalRead(crepuscolare) == LOW && digitalRead(motion) == LOW) ) {
    i = 1001;    
    }
    }
 }
 
 else if(pirVal == HIGH){ 
 Serial.println("No Motion!");
 analogWrite(LEDpin, 0); 
 delay(1);
  }
  
 }
//..
}

Uhm.. potresti fare più letture e farti poi la media. Oppure fare una lettura e vedere lo scarto da quella precedente: se è superiore ad un certo valore, potresti prendere dei provvedimenti (inserire una correzione, scartare la lettura, ecc...).

Sono ignorante quindi magari sbaglio, potrebbe essere la fotocellula che sballa l'out per qualche ms perchè arriva luce di colpo, potresti mettere un condensatore (da non so quanto) per levellare gli sbalzi improvvisi, credo :cold_sweat:

Un condensatore? mmh.. si potrebbe provare, ma da quanto e dove dovrei metterlo? in serie alla fotocella o in parallelo? :cold_sweat:

L'idea di fare la media è buona, dici di usare un vettore e calcolare la media su dieci letture?

Non sono un matematico per cui non so che tipo di media può servirti. Inizia con la classica media aritmetica e vedi se può risolvere. Fai passare qualche ms tra una lettura e l'altra, per evitare di campionare più volte la stessa lettura.

Ma che fotocellula stai usando? Potresti provare con una fotoresistenza, che ha un tempo di risposta altino ed una linearità nei valori.

Uso questa qui: Mini Photocell - SEN-09088 - SparkFun Electronics

Non ne ho trovate altre :frowning:

Opterei anche io per un condensatore,per quanto riguarda il suo collegamento invece va in questo caso in parallelo ma come hai collegato la fotoresistenza all'ingresso arduino? In condizione di buio ti da 10k mentre di luce ti da 1k, io collegherei la fotor tra positivo ed in arduino,una R di 10k tra in di arduino e gnd ed in parallelo a questa un condensatore elettrolitico di pochi uF (2,2-4,7),il problema che ti rimane però è che la lettura che otterrai non sarà da 0 a 1023 ma da circa 512(buio) a circa 930(luce).Sono conti che ho ottenuto dal valore che assume il "partitore resistivo" in funzione della condizione di luce. Se con una capacità così piccola non risolvi il problema devi aumentarla,l'inconveniente che potrebbe darti è che ritardando la condizione di luce fino ad avere una lettura stabile ritarderai anche la condizione di buio,se questo non ti porta fastidio io proverei così.

Ogni quanto viene letto la fotoresistenze?
Come frequenza basa 2-3 volte al secondo. Poi fai una media dei ultimi 10-20 valori.

Ciao Uwe

Si, i collegamenti sono come quelli che hai detto tu, cioè con la resistenza di 10K, ma senza condensatore perchè non lo avevo considerato.

Leggo il valore con un delay(1) quindi è molto veloce anche se il tutto è all'interno di cicli if() che ad ogni loop valutano i valori di due variabili.

Quindi il consiglio è di mettere un condensatore in parallelo al resistore? E in alternativa considerare la media?

Il fatto del ritardo non so quanto potrebbe causarmi fastidi perchè dipende sempre dal valore di quest'ultimo, se è molto alto, potrebbe essere noioso.

e tu non usare un delay()

usi la funzione millis(), la controlli e cosi il programma scorre normalmente senza pause

In realtà potrei anche toglierlo del tutto il delay() o no?

Come la userestiu tu la funzione millis() ?
Leggeresti ogni x secondi?

all'inizio definisci due variabili

#define interval 1000 // ritardo che si vuole (in millisecondi)
long previousMills = 0;

poi nel loop inserisci

if ((millis() - previousMills) > interval ){
previousMills = millis();
// qui inserisci la lettura al sensore

}

// fine controllo tempo trascorso