martedì 25 giugno 2013

Luxmetro

Luxmetro con arduino

Con questo progetto descrivo un semplice Luxmetro  con una fotoresistenza.

Versione 2.2 del 19/06/2013 

 





Il materiale occorrente per questo progetto:

Arduino, una fotoresistenza, LCD, potenziometro 10k, 3 pulsanti, cavi per collegamento, resistenze ( vedi schema).







Attenzione!!

Utilizzo del LCD ACM1602B
Per utilizzare questo lcd seguite le indicazioni
di Mauro Alfieri  www.mauroalfieri.it
Ho collegato il mio lcd nel modo da lui suggerito ed ha funzionato subito


 Questi sono i collegamenti



Funzionamento:

All'accensione lo strumento mostra i Lux ambiente e questi cambiano continuamente al variare dell'illuminamento. 

Con la pressione del tasto HOLD si blocca la lettura ( per poterla annotare) per riprendere
premere nuovamente il tasto HOLD.

Con la pressione del tasto Min - Max si avvia la visualizzazione e conservazione
dei valori minimo e massimo funzione utile per ambienti illuminati con lampade diverse e non uniformemente disposte, e per controllare l'illuminamento per un determinato periodo di tempo.
Per uscire premere nuovamente il tasto Min-Max, per azzerare premere il tasto reset di arduino.

Tasto Lux / Fc si cambia unità di misura da Lux a FootCandele e viceversa.

Chi ha già scaricato la versione 1.7 oppure 1.8 può sostiture lo sketch senza dover fare cablaggi diversi, dovrà sostituire la R5 con un valore da 10k, oppure un valore scelto, inserendo tale valore nella variabile float R_nota.

Lo sketch contiene la gestione pulsanti descritta in dettaglio nel post  arduino partiamo da zero n3,

Note sulle formule utilizzate nello sketch.


 Vout = (Vin/1024.0 * valR);    // Si converte il valore in Volt

Nella variabile valR  troveremo un valore compreso fra 0 e 1023 che moltiplicheremo per i (5/1024) 4,8 mV, ottenendo così la tensione sul partitore, che cambia al variare della luce ricevuta.

  Ldr = ((R_nota * Vin/Vout )- R_nota);    // Si calcola la resistenza

Con questo passaggio calcoliamo il valore in ohm della fotoresistenza, vedi in dettaglio le spiegazioni sul post arduino-partiamo-da-zero-n6
La variabile R_nota contiene il valore ( 10k ) o meglio il valore misurato con precisione della R5.

 
  Lux = pow((Ldr/Ldr_1), (1.0/-Pend));   // si calcolano i Lux

Per questa formula devo ringraziare Marco Magagnin che sulla rivista Elettronica In ha pubblicato un articolo sulla espansione ADC per Raspberrypi  e descrive questa formula e molto altro.
Consiglio la lettura dell'articolo.
 Ecco alcuni elementi per chiarire la formula.
Nelle caratteristiche ( quasi introvabili) delle fotoresistenze il costruttore rilascia dati molto importanti, ci dovreste trovare anche il grafico che esprime l'andamento della resistenza in funzione dei Lux, ( io ero stato tratto in inganno da questo grafico) non avevo valutato il fatto che è espresso in scala logaritmica, quindi è si una retta ma "retta in forma logaritmica":

1)  logR = -a log IL + log R1

dove:
R=  resistenza del fotoresistore
 a=  pendenza della retta valore Gamma ( di solito compreso fra 0,6 e 0,8 ) questo è il valore della pendenza della retta
IL = Lux
R1 = resistenza del fotoresistore in condizioni di luce unitario ( nel mio caso 75K)

Dalla (1) si ricava Lux = pow((Ldr/Ldr_1), (1.0/-Pend));

qui sotto l'immagine della retta fornita dal produttore della LDR (tratta dall'articolo di Elettronica in)




Fatte le modifiche alla precedente versione ho riscontrato un buon funzionamento, anche se rimangono i limiti del Dac di arduino, inoltre non sono riuscito a ricavare il valore esatto della pendenza della mia fotoresistenza.

Quì sotto trovate lo sketch ampiamente commentato, spero vi possa chiarire tutti i passaggi.
Se avete domande scrivete pure, cercherò di rispondere a tutti.
Vi ringrazio fin d'ora per un vostro commento sul lavoro.

*****
/* Sergio & Adriano Prenleloup
      19/06/2013
*** Luxmetro ***  versione 2.2

Utilizzo del LCD ACM1602B
Per utilizzare questo lcd seguite le indicazioni
di Mauro Alfieri  www.mauroalfieri.it
Ho collegato il mio lcd nel modo da lui suggerito ed ha funzionato subito

************** Funzioni dei tasti  **************************

All'accensione mostra i Lux ambiente e questi variano se si sposta lo strumento.

Tasto OLD         si blocca la lettura ( per poterla registrare)
                  per riprendere premere nuovamente il tasto OLD

Tasto Min - max   si avvia la visualizzazione e conservazione
                  dei valori minimo e massimo utile per ambienti
                  illuminati con lampade diverse e non uniformemente
                  disposte per uscire premere nuovamente il tastp Min-max

Tasto Lux / Fc    si cambia unità di misura da Lux a FootCandele e viceversa.


*/
#include 
#include 
 
// initialize the library with
// the numbers of the interface pins

// Pin utilizzati
// pin 5 --- RS ( tipo di comando da inviare)
// pin 4 --- Enable
// pin 0,1,2,3 --- Dati si utilizzano 4 bit

LiquidCrystal lcd(5, 4, 3, 2, 1, 0);

//pulsanti
int Hold_Button = 6;  // pulsante old
int MinM_Button = 7; // pulsante min max
int Unit_Button = 8; // pulsante cambio unità

// fotoresistenza
int pinLdr = A0;

// *******************************************
//varabili globali e costanti

const int MODO_AMBIENTE = 0;  // costanti selezione
const int MODO_HOLD     = 1;  // modo di operativo
const int MODO_MINMAX   = 2;  // di funzionamento
boolean memorizzato;

float valoreMIN = 0;    // valori lux minimo e massimo
float valoreMAX = 0;

int valoreLdr = 0;   // usata per i valori ( 0-1023)
float calibVal = 1;      // calibrazione ( non usata nella 2.2) 

float COST_CD = 0.0929; //conversione da lettura  a footcandele
float COST_LUX = 1;    //conversione da lettura sensore a lux
float  valR = 0;      // valore lettura resistenza
 
float Vout = 0.0;    //Voltaggio uscita partitore
float Vin = 5.0;    // Vcc (5 Volts) voltaggio arduino
float R_nota = 9900.0;  // Valore misurato della resistenza nota (10Komm)
                           
float valore;            // valore lux                           
float Ldr = 0.0;         // Valore calcolato della resistenza Ldr.
float Ldr_1 = 75000.0;   // Valore ldr illuminamento unitario
float Pend  = 0.66;      // Valore gamma fotoresistenza
double Lux = 0.0;        // Lux calcolati
//**************************************************

//stato corrente dei bottoni
int stato_bottoni[3];
boolean stato_switch[3];

//stringhe per mostrare la descrizione della lettura mostrata
char* Descrive [] =
{"Lux ambiente","HOLD Lux","Lux-min  Lux-max", "Fc ambiente", "Fc HOLD", "Fc-min   Fc-max"};
 
// ***************************************************

void setup() 
{
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  
  // fotoresistenza
  pinMode( pinLdr, INPUT);
  
  // Pulsanti
  pinMode (Hold_Button, INPUT);
  pinMode (MinM_Button, INPUT);
  pinMode (Unit_Button, INPUT);
  
  stato_bottoni[0] = 0;
  stato_bottoni[1] = 0;
  stato_bottoni[2] = 0;
  
  valoreMIN = valoreMAX = LeggiSensore();
  memorizzato = false;
  valore = LeggiSensore();   
}    
 
// ********** lettura pulsanti & antirimbalzo **********************
void aggiornaStato(int bottone, int& statoBottoneVecchio, boolean& statoSwitch)
{
  //Si legge lo stato corrente del bottone (se premuto o no)
  int statoBottoneCorrente = digitalRead (bottone);
  
  //Se lo stato corrente del bottone è cambiato (diverso dal vecchio stato)
  //si deve gestire il nuovo stato
  if (statoBottoneCorrente != statoBottoneVecchio)
  {
      //se stiamo passando da rilasciato a premuto allora gestiamo la 
      //logica antirimbalzo e attiviamo/disattiviamo lo swith
     if (statoBottoneCorrente == HIGH)
     {
       delay(10);
       statoSwitch = !statoSwitch;
     }
     //il nuovo stato diventa lo stato corrente
     statoBottoneVecchio = statoBottoneCorrente;  
  }
}

// *************controllo modo funzionamento ******************
void controlla()
{
    aggiornaStato(Hold_Button, stato_bottoni[0], stato_switch[0]);
    aggiornaStato(MinM_Button, stato_bottoni[1], stato_switch[1]);
    aggiornaStato(Unit_Button, stato_bottoni[2], stato_switch[2]);
}

// *******************************
int modoOperativo()
{
  if (stato_switch[0] == 1)
    return MODO_HOLD;
  else if (stato_switch[1] == 1)
    return MODO_MINMAX;  
  return MODO_AMBIENTE;
}

// ****************************** 
// Lettura Ldr calcolo resistenza
// calcolo Lux
// ******************************
float LeggiSensore()
{
   valR = 0;
  // si leggono 5 valori dalla fotoresistenza
  for ( int i = 0; i<= 4; i++)
  {
    int valoreLdr = analogRead(pinLdr);
    delay ( 40 );
    
    valR = valR + valoreLdr;
  }
   // media dei valori letti 
   valR = valR/5;
   
  // calcoliamo il valore della resistenza LDR
  
  Vout = (Vin/1024.0 * valR);    // Si converte il valore in Volt
  Ldr = ((R_nota * Vin/Vout )- R_nota);    // Si calcola la resistenza 
  
  // si calcolano i Lux
  Lux = pow((Ldr/Ldr_1), (1.0/-Pend));
   
   
   return (Lux);
}

// *******************************
float ConvertiLux(float valore)
{
  return COST_LUX * valore;
}

// ********************************
float ConvertiCandele(float valore)
{
  return COST_CD * valore;
}

// *********************************
void visualizza(int idxMessaggio, float valore1, float valore2)
{   
   double valoreLCD1;
   double valoreLCD2;
   int decimali = 0;
   
   // se unità fotocandele converte e visualizza in foot candele
   if ( stato_switch[2] == 1)
   { 
     valoreLCD1 = ConvertiCandele(valore1);
     valoreLCD2 = ConvertiCandele(valore2);
     idxMessaggio = idxMessaggio + 3;
     decimali = 2;
   }
   else
   {
     valoreLCD1 = ConvertiLux(valore1);
     valoreLCD2 = ConvertiLux(valore2);
     decimali = 0;
   }
      
    // si scrivono i risultati 
   // con la descrizione lettura
   lcd.clear ();   
   lcd.print(Descrive[idxMessaggio]);
   lcd.setCursor(0, 1);
   lcd.print ( valoreLCD1, decimali );
   
   if (valore2 > 0)
   {
     lcd.setCursor(10, 1);
     lcd.print ( valoreLCD2, decimali );
   }
   
   delay (100);
 }
 
//*********** loop principale **********

void loop()
{

  controlla();
  int modo = modoOperativo();

  switch (modo)
  {
      case MODO_HOLD:
        if (!memorizzato)
        {
          valore = LeggiSensore();
          memorizzato = true;
        }
        visualizza(1, valore, -1);
        break;
        
      case MODO_MINMAX:
        memorizzato = false;
        valore = LeggiSensore();
        if (valore <= valoreMIN)
          valoreMIN = valore;
        if (valore >= valoreMAX)
          valoreMAX = valore;
        visualizza(2, valoreMIN, valoreMAX);

        break;
        
      case MODO_AMBIENTE:
      default:
        memorizzato = false;
        valore = LeggiSensore();
        visualizza(0, valore, -1);        
  }
     
}
// *********** end *****************



scaricate lo sketch 2.2


Questo è un filmato per visualizzare la modalità di funzionamento
Buon lavoro
Sergio Prenleloup








Attenzione!!

L'autore di queste pagine non si ritiene responsabile per eventuali danni diretti o indiretti causati a persone o cose.

Prendete ogni precauzione per evitare anche il minimo rischio di scosse elettriche.
Si avverte che:
Tensioni alternate maggiori di 25 V sono pericolose.
Tensioni continue maggiori di 50 V sono pericolose.

Warning!

The author of these pages will not be liable for any direct or indirect damage caused to persons or property.

Take any precaution to avoid even the slightest risk of electric shock.
Please be aware that:
AC voltages greater than 25 V are dangerous.
CC Voltages greater than 50 V are dangerous.


9 commenti:

  1. Ciao, potresti dirmi su quale numero di Elettronica In hai letto questo articolo?

    RispondiElimina
  2. Ciao, si tratta del numero 174 di Marzo 2013 di Elettronica in.
    L'articolo scritto da Marco Magagnin e " SHIELD DI ESPANSIONE ADC PER RASPBERRYPI COMPATIBILE CON ARDUINO.
    Se hai altre domande scrivi pure.
    Sergio

    RispondiElimina
  3. Grazie per la risposta, gentilissimo.
    In pratica, vorrei misurare i Lux con un LDR mediante Raspberry Pi, non riuscivo a capire la relazione tra resistenza e lumen/m^2 (Lux) che ho trovato su questo bell'articolo da te scritto, se non erro la relazione ce tanto ho cercato è questa "logR = -a log IL + log R1" , sui vari datasheet non sono riuscito a trovarla. Non riesco a capire la formula finale che hai inserito nel codice: "Lux = pow((Ldr/Ldr_1), (1.0/-Pend));" se non erro la funzione "pow" fa parte del set di istruzione "math.h" però non riesco a capirla bene, quella formuletta se non mi sbaglio equivale a scrivere "(LDR/LDR_1)^(1/-Pend)" il mio dubbio, riguarda quel "-Pend", cosa rappresenta nella formula?

    Saluti Pasquale

    RispondiElimina
  4. equivale a scrivere "(LDR/LDR_1)^(1/-Pend)
    giusto!
    pow(x, y) è la funzione che calcola la potenza x^y in diversi linguaggi di programmazione inclusa nella "math.h"

    dalla formula (1) logR = -a log IL + log R1 dove ho indicato

    a= pendenza della retta valore Gamma ( di solito compreso fra 0,6 e 0,8 ) questo è il valore della pendenza della retta

    Purtroppo come ho già detto non si trovano molti dettagli sulle caratteristiche delle LDR cercherò di inserire nel post l'mmagine della retta in questione in x sono indicati i Lux e in y sono è indicata la r
    dai vari punti rilevati si forma una retta la pendenza su descritta è l'inclinazione di questa retta rispetto agli assi questo dato dovrebbe essere fornito dal costruttore ( Magagnin ha utilizzato un valore di 0,7.)

    Cercherò un'mmagine che ti possa spiegare meglio la cosa.

    A presto
    Sergio

    RispondiElimina
  5. Adesso ho capito, Grazie del chiarimento e complimenti, questo è l'articolo migliore che ho visto fin ora in rete su come si possono ricavare i lux da un LDR, gli altri che ho visto si limitano a mostrare solo il valore letto e convertito... invece qui viene impiegata la relazione vera e propria e in oltre hai sviluppato anche diverse funzioni, max/min, hold ecc... davvero un buon lavoro.

    Buona giornata
    Pasquale

    RispondiElimina
  6. Salve , io invece non ho capito come hai ricavato questo valore :R1 = resistenza del fotoresistore in condizioni di luce unitario ( nel mio caso 75K) . Dipende , suppongo , in base alla resistenza che si utilizza.. io come faccio a stabilire il mio? Grazie in anticipo

    RispondiElimina
  7. Scusa Mauro ma per errore ho cancellato la mia risposta, la riscrivo qui.

    R1 è il valore che assume la LDR con 1 Lux ( praticamente buio!).
    Dovresti trovarla fra le caratteristiche nel datasheet della tua, il problema è che a volte non sono identificate (come quella che ho usato io), in questo caso puoi verificare dei valori assunti da LDR simili fra i varii datasheet che si trovano in rete.
    Oppure come ho fatto anche io porti la stanza al buio e leggi sull'ommetro il valore (il mio tester ha la retroilluminazione).
    Ora ho sostituito l'immagine della retta e con un poco di occhio si può stimare il valore in komm in corrispondenza di " 1 Lux".
    Dimmi se sei riuscito.
    Saluti

    RispondiElimina
  8. Ciao Sergio,
    bellissimo tutorial, ho trovato il tuo video pensando di realizzare anche io un luxmetro con una fotoresistenza ed ho scoperto nei titoli di coda di aver contribuito :-)

    Grazie per il tutorial e per la citazione.
    Citerò il tuo articolo tra i miei tutorial :-)

    RispondiElimina
  9. Ti ringrazio io, mi considero un tuo allievo, ho seguito i tuoi articoli su arduino, ho cominciato ad utilizzarlo in ottobre del 2012.
    Conoscevo un poco di elettronica analogica, ma vecchiotta, di elettronica digitale sapevo poco o nulla.
    Trovato Arduino, i Tuoi tutorial, e quelli di Michele Maffucci, mi sono appassionato sempre più ed ho cominciato a pubbilicarli su questo blog ( magari a qualcuno possono servire).
    Effettivamente ho anche il supporto di mio figlio Adriano che conosce la programmazione, e spesso lavoriamo ad un progetto insieme.
    Ora stiamo preparando una stazione meteo molto interessante.
    Ho pubblicato vari articoli degli esperimenti sui sensori ora dobbiamo mettere insieme il tutto.
    A presto.
    Sergio

    RispondiElimina

Vi ringrazio per la lettura e vi invito al prossimo post.
Se il post vi è stato utile, vi è piaciuto oppure no, scrivete un commento.

Un saluto a tutti.
Sergio

Copyright - Condizioni d’uso - Disclaimer
http://avventurarduino.blogspot.it/2012/10/inizia-lavventura-arduino-12-settembre.html