Termostato e sensore di livello con Arduino

Una sezione dedicata ai vostri progetti.
Se avete inventato o costruito qualcosa e lo volete condividere con la community ecco il posto che far per voi

Termostato e sensore di livello con Arduino

Messaggioda Step » 27 dic 2012, 14:15

Salve, volevo farvi vedere un oggettino che ho fatto per un'esigenza personale, quindi vi spiego un attimo la mia situazione prima di entrare in dettaglio.
Prima cosa: ho avuto la possibilità di allargare casa mia e con le nuove normative edilizie ho dovuto fare uno scavo per la fondazione piuttosto profondo, in bratica sono circa 30 cm più basso della fondazione originale.
Seconda cosa: sotto casa mia c'è una falda a cui attingo con un pozzo artesiano ed un motore pompa.
Due + due fa quattro, se il livello del pozzo sale oltre un certo limite (cosa che può succedere in periodi di intense piogge) mi entrano circa 10 / 15 cm di acqua nelle fondazioni nuove adibite a rimessa, sono troppo basse per essere utilizzabili in altro modo. Facendo delle prove ho scoperto che se mantengo il livello del pozzo ad un massimo 165 cm dal livello stradale la rimnessa non si allaga. Per un po' di tempo ho fatto questa operazione a mano, poi mi sono detto perché non faccio un sistema automatico? Quindi ho pensato semplicemente ad una elettrovalvola (il motore parte grazie ad un pressostato) e ad una sonda di livello, poi mi è venuto in mente che dalle mie parti in inverno ghiaccia facilmente e quindi non posso lasciare il motore collegato e fermo con il ciruito idraulico pieno, normalmente in invermo svuotiamo l'impianto del pozzo.
Per trovare la soluzione che per adesso sta già funzionando mi è venuto in aiuto Arduino, con questo ho realizzato un termostato con ciclo di controllo ogni 10 minuti e gestione della sonda di livello.
In pratica ho utilizzato un LM35 come sensore termico collegato meccanicamente al corpo motore e direttamente ad arduino, il sensore LM35 è un sensore lineare che misura anche temperature negative, ma al quale non ho applicato la necessaria elettronica per farlo perché non mi serviva, comunque il mio campione misura fino a 0 e per un termostato antigelo misurare fino a zero basta :wink: . poi ho preso uno shield con 4 relay per arduino iun modo da avere un'uscita di potenza per l'elettrovalvola che funziona a 220 Vac, due pulsanti per poter variare la temperatura di soglia, un display per vedere quello che sto facendo e ovviamente un semplice sensore di livello a galleggiante. Si potrebbe pensare che il sensore di livello crei dei problemi di accensioni e spegnimenti continui, ma non è così, con l'elettrovalvola ed il motore a pressostato ci sono delle notevoli inerzie (ed in ogni modo il codice è sempre pronto ad essere sottoposto a revisioni).
Qui sotto trovate il programma che ho realizzato (ovviamente non sono un programmatore, quindi ho preso un po' di spunti in rete e ho studiato qualcosa su alcuni manuali di C )
Codice: Seleziona tutto
/*Termostatino antigelo:
  Lettura sensore termico LM35dz, visualizzazione su display 16x2,
  modifica soglia con 2 pulsanti + e - su ingressi analogici,
  visualizzazione soglia durante la modifica,
  Sensore di livello ad immersione tramite ingresso analogico e
  comando relay via uscite digital1 5, 6, 7 e 8
*/

#include <swRTC.h>                      //libreria per RTC
#include <LiquidCrystal.h>              //libreria per lcd
LiquidCrystal lcd(12, 11, 10, 4, 3, 2); //stabilisco le uscite digitali per lcd 4 bit
swRTC rtc;                              //creo un'istanza della libreria

  int rele_out1 = 5;    //stabilisco l'uscita digitale per il relay 1
  int rele_out2 = 6;    //stabilisco l'uscita digitale per il relay 2
  int rele_out3 = 7;    //stabilisco l'uscita digitale per il relay 3
  int rele_out4 = 8;    //stabilisco l'uscita digitale per il relay 4
  int pulsantepiu;       //pulsante incremento temperatura di soglia
  int pulsantemeno;      //pulsante diminuisco temperatura di soglia
  int tx;                //temperatura di soglia
  int cont;              //contatore usato per ottenere un valore medio di temperatura
  int tempmed;           //temperatura media
  int durata;            //conteggio minuti per temporizzazione
  int livello;           //ingresso sonda livello 170 cm
 
  byte grado[8] = {      //creo i dati per il carattere °
  0b00010,
  0b00101,
  0b00010,
  0b00000,
  0b00000,
  0b00000,
  0b00000,
  0b00000,
};

void setup(){

  Serial.begin(9600);           //inizializzo la seriale
  lcd.createChar(0, grado);     //associo i dati del ° al carattere custom 0
  lcd.begin(16, 2);             //dichiaro il tipo di lcd
  pinMode(rele_out1, OUTPUT);   //assegno il modo uscita digitale al pin 5
  pinMode(rele_out2, OUTPUT);   //assegno il modo uscita digitale al pin 6
  pinMode(rele_out3, OUTPUT);   //assegno il modo uscita digitale al pin 7
  pinMode(rele_out4, OUTPUT);   //assegno il modo uscita digitale al pin 8
  tx = 5;                       //temperatura di soglia iniziale
  pulsantepiu = 0;              //assegno valore 0 iniziale al pulsantepiù
  pulsantemeno = 0;             //assegno valore 0 iniziale al pulsantemeno
  livello = 0;               //assegno valore 0 iniziale alla sonda di livello
  tempmed = 15;         //assegno un valore iniziale di temperatura prima di ottenere la media
 
  rtc.stopRTC();                //blocco RTC per inserire i valori iniziali
  rtc.setTime(0, 00, 00);       //metto valori a zero perché
  rtc.setDate(01, 01, 2012);    //devo usare RTC solo come timer
  rtc.startRTC();               //avvio RTC

}

void loop() {

   int durata = rtc.getMinutes();  //acquisisco i minuti
 
   if (durata > 10){                //se durata è maggiore di 10 minuti
     rtc.stopRTC();                  //blocco RTC
     rtc.setTime(0, 00, 00);         //azzero i valori
     rtc.setDate(01, 01, 2012);      //per poter riconteggiare da zero
     rtc.startRTC();                 //riavvio rtc
   }
 
   int pulsantepiu = analogRead(A1);    //lettura ingresso analogico 1 e assegnazione del valore a pulsantepiù
   int pulsantemeno = analogRead(A2);   //lettura ingresso analogico 2 e assegnazione del valore a pulsantemeno
   
   if (pulsantepiu == 0){                        //se il pulsantepiù vieno premuto verso il negativo
     tx = tx ++;                                 //la variabile temperatura di soglia tx incrementa di una unita
     lcd.clear();                  //cancello il display
     lcd.print("Temperatura di");            //scrivo un testo
     lcd.setCursor(0, 1);                         //riposiziono il cursore
     lcd.print("soglia: ");            //scrivo di nuovo un testo
     lcd.print(tx,DEC);               //scrivo il valore impostato della temperatura di soglia
     lcd.write((byte)0);               //scrivo il °
     lcd.print ("C");                            //scrivo il C di Celsius
     delay(1000);                                //ritardo di 1 secondi per la lettura
   }

   if (pulsantemeno == 0){                       //se il pulsantemeno vieno premuto verso il negativo
     tx = tx --;                                 //la variabile temperatura di soglia tx decrementa di una unità
     lcd.clear();                  //cancello il display
     lcd.print("Temperatura di");            //scrivo un testo
     lcd.setCursor(0, 1);                         //riposiziono il cursore
     lcd.print("soglia: ");            //scrivo di nuovo un testo
     lcd.setCursor(10, 1);               //riposiziono il cursore
     lcd.print(tx,DEC);               //scrivo il valore impostato della temperatura di soglia
     lcd.write((byte)0);               //scrivo il °
     lcd.print ("C");                            //scrivo il C di Celsius
     delay(1000);                                //ritardo di 1 secondi per la lettura
   }
   
   Serial.println("temperatura di soglia:");   //invio le inforamazioni anche
   Serial.println(tx,DEC);                     //al serial monitor della IDE


        while (analogRead(A3) == 0) {         //lettura ingresso analogico A3 e confronto con valore 0 (CONTATTO CHIUSO)
     lcd.clear();               //con il livello troppo alto avviso su display
     lcd.print ("! Livello Alto !");      //che il livello  è alto e
     lcd.print(" Valvola Aperta ");      //che apro la valvola
     digitalWrite(rele_out1, HIGH);      //comando anche il relay 1 di apertura valvola
          digitalWrite(rele_out2, HIGH);      //comando anche il relay 2 di apertura valvola
          //digitalWrite(rele_out3, HIGH);      //comando anche il relay 3 di apertura valvola
          //digitalWrite(rele_out4, HIGH);      //comando anche il relay 4 di apertura valvola
          delay (60000);                                         //mantengo il contatto chiuso per 60 secondi prima di ripartire con il ciclo
   }
   


   for(cont = 0; cont < 10; cont++){            //inizio il conteggio per la campionatura dei valori di temperatura

      int temperatura = analogRead(A0);         //lettura ingresso analogico 0 e assegnazione del valore alla variabile temperatura
      temperatura = (5.0 * (temperatura + 9) * 10.0)/1024.0; //converto il valore analogico in gradi centigradi e correggo la lettura
      tempmed += temperatura;                     //sommatoria dei valori
      delay(300);                  //ritardo tra due campioni per stabilizzare la lettura

      if(cont == 10){                              //quando ho sommato i dieci valori campionati si
         cont = 0;                                  //azzera il contatore, per far ripartire il successivo campionamento
         tempmed = tempmed / 10;                    //faccio il valore medio
      }
      
   }
 
   if(tempmed <= tx && durata == 10){          //se la temperatura rilevata è minore o uguale rispetto
     lcd.clear();                   //alla temperatura di soglia e il tempo
     lcd.print("Temperatura ");             //trascorso dall'ultimo ciclo è di 10 minutì      
     lcd.print(tempmed,DEC);                      //scrivo sul display il valore e          
     lcd.write((byte)0);                          //avviso che il contatto è chiuso
     lcd.print("C");                                               
     lcd.setCursor(0, 1);                          //con la scritta " Valvola Aperta "
     lcd.print(" Valvola Aperta ");                //per finire
     digitalWrite(rele_out1, HIGH);           //comando anche il relay 1 di apertura valvola
          digitalWrite(rele_out2, HIGH);      //comando anche il relay 2 di apertura valvola
          //digitalWrite(rele_out3, HIGH);      //comando anche il relay 3 di apertura valvola
          //digitalWrite(rele_out4, HIGH);      //comando anche il relay 4 di apertura valvola
     delay(60000);                                 // e comando i relay per un minuto
   }else{                  //altrimenti scrivo
     lcd.clear();               //sempre sul display
     lcd.print("  Temperatura");         //il valore
     lcd.setCursor(0, 1);
     lcd.print("rilevata:  ");
     lcd.print(tempmed,DEC);                       
     lcd.write((byte)0);
     lcd.print("C");
     digitalWrite(rele_out1, LOW);      //mantengo bassa l'uscita digitale 5
     digitalWrite(rele_out2, LOW);      //mantengo bassa l'uscita digitale 6
     //digitalWrite(rele_out3, LOW);      //mantengo bassa l'uscita digitale 7
     //digitalWrite(rele_out4, LOW);      //mantengo bassa l'uscita digitale 8
   }

   tempmed = 0;                                  //azzero la media per un nuovo conteggio
   Serial.println("durata");
   Serial.println(durata,DEC);
   Serial.println(rtc.getSeconds(),DEC);
}



Questo invece è lo schema del circuito, le tre resistenze di pull-up sono da 10 Kohm e il trimmer per il contrasto del display è da 22 Kohm. Il display è un normalissimo 16 colonne x 2 righe con chip equivalente al Hitachi HD44780 facimelte gestibile con le librerie LiquidCrystal.

Immagine

Qui sotto trovate il datasheet del modulo relay che ho utilizzato.

Immagine
Immagine


Non allego anche il datasheet del LM35, perché è veramente banale, basta guardare il collegamento nel circuito.


Mi aspetto suggerimenti da chi ne sa più di me, sappiate che secondo me tutto si può ottimizzare, tra l'altro mi hanno già amichevolmente "brontolato" per il consumo inutile di energia che ho avendo le resistenze di pull-up, se avessi fatto un pull-down avrei avuto un consumo solo durante la chiusura dei contatti, ma per ora questo non è un problema, anzi mi mantiene "caldo il circuito e non mi si bloccano i relays :D .
Step
Avatar utente
Amministratore
 
Messaggi: 2242
Iscritto il: 9 nov 2010, 19:36
Località: Una galassia lontana anni luce, dietro l'angolo!
    Windows 7 Firefox
Immagine
Tutto questo non vale per il wasabese.....
....è proprio un'altra lingua!

Re: Termostato e sensore di livello con Arduino

Messaggioda zoomx » 27 dic 2012, 19:35

Per adesso l'unico dubbio riguarda proprio il collegamento dell'LM35. Poiché il sensore fornisce 10mV per grado centigrado significa che a 0° dovrebbe fornire 0V ma c'è il problema delle interferenze per cui già nel datasheet scrivono che questo collegamento va bene dai 2° in su.
Ma a te funziona, quindi....

Per il resto i miei complimenti.
zoomx
Avatar casuale
 
    Windows 7 Chrome

Re: Termostato e sensore di livello con Arduino

Messaggioda Step » 28 dic 2012, 0:21

Altro che complimenti...Oggi RyujiAndy ha esaminato il mio codice e mi ha fatto avere un listato fatto da lui dove veramente si vedono le differenze tra un dilettante ed un programmatore vero, ci sono solo un paio di problemi di compilazione, appena sarà funzionante al 100% lo posto così capirete meglio di cosa sto parlando...


Per il discorso del LM35 (che in realtà è un LM35DZ, quindi legge da 0°C a 100°C ) io mi sono accorto empiricamente che il mio campione non rispettava realmente gli standard (non so se è un componente di prima scelta o meno, o se ha qualche altro problema, probabilmente lo sostituirò), fatto sta che se vedi il codice c'è una correzione di temperatura, per rilevarla ho fatto diverse letture con questo LM35 e con un altro termometro digitale, e ti posso assicurare che da 25°C fino al cubetto di ghiaccio ho ottenuto dei mV e per il mio scopo questo è stato sufficente!

Questa sotto è la foto della sonda di livello, abbiamo relizzato una gabbia attorno al galleggiante per evitare che il tubo di pescaggio possa in qualche modo disturbare il movimento del galleggiante stesso.

Immagine
Step
Avatar utente
Amministratore
 
Messaggi: 2242
Iscritto il: 9 nov 2010, 19:36
Località: Una galassia lontana anni luce, dietro l'angolo!
    Windows 7 Firefox
Immagine
Tutto questo non vale per il wasabese.....
....è proprio un'altra lingua!

Re: Termostato e sensore di livello con Arduino

Messaggioda zoomx » 28 dic 2012, 0:54

Su una rivista diversi anni fa vidi un sensore di livello fatto con una specie di fibra ottica. Un led spara la luce nella fibra che si riflette sul fondo e torna indietro ma, se la fibra è immersa in acqua, la riflessione non avviene più.

Gli LM35 non dovrebbero sgarrare più di un grado (dipende dalle versioni), non è che hai disturbi? Io invece sto giocando con il DS1820 che è invece digitale.

Aspetto il nuovo sorgente.
zoomx
Avatar casuale
 
    Windows 7 Chrome

Re: Termostato e sensore di livello con Arduino

Messaggioda student » 28 dic 2012, 0:59

Lodi lodi lodi ! Sei passato di livello boss !
student
Avatar casuale
 
    Windows 7 Chrome

Re: Termostato e sensore di livello con Arduino

Messaggioda RyujiAndy » 28 dic 2012, 9:11

ho cercato di ripulirti il codice e correggere il calcolo della media per il rivelamento della temperatura, senza contare che il confronto della temperatura avveniva solo dopo un ciclo di 10 min.
rivedró il codice non appena ho finito di sistemare il mio nuovo laboratorio.

P.S. Rivisto e corretto i 2 errori di battitur che ho fatto..
Codice: Seleziona tutto
/*Termostatino antigelo:
  Lettura sensore termico LM35dz, visualizzazione su display 16x2,
  modifica soglia con 2 pulsanti + e - su ingressi analogici,
  visualizzazione soglia durante la modifica,
  Sensore di livello ad immersione tramite ingresso analogico e
  comando rel� via uscite digital1 5, 6, 7 e 8
*/

#include <swRTC.h>                      //libreria per RTC
#include <LiquidCrystal.h>              //libreria per lcd

#define livello_alto   1
#define   cambio_soglia   2
#define temp_bassa   3

LiquidCrystal lcd(12, 11, 10, 4, 3, 2); //stabilisco le uscite digitali per lcd 4 bit
swRTC rtc;                              //creo un'istanza della libreria

  int rele_out1 = 5;    //stabilisco l'uscita digitale per il relè 1
  int rele_out2 = 6;    //stabilisco l'uscita digitale per il relè 2
  int rele_out3 = 7;    //stabilisco l'uscita digitale per il relè 3
  int rele_out4 = 8;    //stabilisco l'uscita digitale per il relè 4
  int pulsantepiu;       //pulsante incremento temperatura di soglia
  int pulsantemeno;      //pulsante diminuisco temperatura di soglia
  int tx;                //temperatura di soglia
  int cont;              //contatore usato per ottenere un valore medio di temperatura
  int tempmed;           //temperatura media
  int durata;            //conteggio minuti per temporizzazione
  int livello;           //ingresso sonda livello 170 cm
 
  byte grado[8] = {      //creo i dati per il carattere °
  0b00010,
  0b00101,
  0b00010,
  0b00000,
  0b00000,
  0b00000,
  0b00000,
  0b00000,
};

void setup(){

  Serial.begin(9600);           //inizializzo la seriale
  lcd.createChar(0, grado);     //associo i dati del ° al carattere custom 0
  lcd.begin(16, 2);             //dichiaro il tipo di lcd
  pinMode(rele_out1, OUTPUT);   //assegno il modo uscita digitale al pin 5
  pinMode(rele_out2, OUTPUT);   //assegno il modo uscita digitale al pin 6
  pinMode(rele_out3, OUTPUT);   //assegno il modo uscita digitale al pin 7
  pinMode(rele_out4, OUTPUT);   //assegno il modo uscita digitale al pin 8
  tx = 5;                       //temperatura di soglia iniziale
  pulsantepiu = 0;              //assegno valore 0 iniziale al pulsantepi�
  pulsantemeno = 0;             //assegno valore 0 iniziale al pulsantemeno
  livello = 0;               //assegno valore 0 iniziale alla sonda di livello
  tempmed = 15;         //assegno un valore iniziale di temperatura prima di ottenere la media
 
  settimer(0);         //azzero il timer

}

void loop() {

   int durata = rtc.getMinutes();  //acquisisco i minuti
 
   if (durata > 10){                //se durata è maggiore di 10 minuti
     settimer(30);          //fermo il timer
     durata = 30;          //setto valore per dare il via libera all'apertura della valvola
   }
 
   int pulsantepiu = analogRead(A1);    //lettura ingresso analogico 1 e assegnazione del valore a pulsantepi�
   int pulsantemeno = analogRead(A2);   //lettura ingresso analogico 2 e assegnazione del valore a pulsantemeno
   
   if (pulsantepiu == 0){                        //se il pulsantepi� vieno premuto verso il negativo
     tx = tx ++;                                 //la variabile temperatura di soglia tx incrementa di una unita
     stampalcd(cambio_soglia);            //stampo su lcd
     delay(1000);                                //ritardo di 1 secondi per la lettura
   }

   if (pulsantemeno == 0){                       //se il pulsantemeno vieno premuto verso il negativo
     tx = tx --;                                 //la variabile temperatura di soglia tx decrementa di una unit�
     stampalcd(cambio_soglia);            //stampo su lcd
     delay(1000);                                //ritardo di 1 secondi per la lettura
   }
   
   Serial.println("temperatura di soglia:");   //invio le inforamazioni anche
   Serial.println(tx,DEC);                     //al serial monitor della IDE


        while (analogRead(A3) == 0) {         //lettura ingresso analogico A3 e confronto con valore 0 (CONTATTO CHIUSO)
     lcd.clear();               //con il livello troppo alto avviso su display
     stampalcd(livello_alto);         //stampo su lcd
     digitalWrite(rele_out1, HIGH);      //comando anche il rele 1 di apertura valvola
          digitalWrite(rele_out2, HIGH);      //comando anche il rele 2 di apertura valvola
          //digitalWrite(rele_out3, HIGH);      //comando anche il rele 3 di apertura valvola
          //digitalWrite(rele_out4, HIGH);      //comando anche il rele 4 di apertura valvola
   }
   


   for(cont = 0; cont < 10; cont++){            //inizio il conteggio per la campionatura dei valori di temperatura

      int temperatura = analogRead(A0);   //lettura ingresso analogico 0 e assegnazione del valore alla variabile temperatura
      temperatura = (5.0 * (temperatura + 9) * 10.0)/1024.0; //converto il valore analogico in gradi centigradi e correggo la lettura
      tempmed = (tempmed + temperatura) / 2;        //media
      delay(300);                  //ritardo tra due campioni per stabilizzare la lettura
      
   }
 
   if(tempmed <= tx && durata == 30){           //se la temperatura rilevata � minore o uguale rispetto
     stampalcd(temp_bassa);         //stampo su lcd
     digitalWrite(rele_out1, HIGH);           //comando anche il rele 1 di apertura valvola
          digitalWrite(rele_out2, HIGH);      //comando anche il rele 2 di apertura valvola
          //digitalWrite(rele_out3, HIGH);      //comando anche il rele 3 di apertura valvola
          //digitalWrite(rele_out4, HIGH);      //comando anche il rele 4 di apertura valvola
     delay(60000);                                 // e comando i rel� per un minuto
     settimer(0);               //azzero il timer
   }else{                  //altrimenti scrivo
     stampalcd(0);               //stampa su lcd
     digitalWrite(rele_out1, LOW);      //mantengo bassa l'uscita digitale 5
     digitalWrite(rele_out2, LOW);      //mantengo bassa l'uscita digitale 6
     //digitalWrite(rele_out3, LOW);      //mantengo bassa l'uscita digitale 7
     //digitalWrite(rele_out4, LOW);      //mantengo bassa l'uscita digitale 8
   }

   tempmed = 0;                                  //azzero la media per un nuovo conteggio
   Serial.println("durata");
   Serial.println(durata,DEC);
   Serial.println(rtc.getSeconds(),DEC);
}
void settimer(int valo) {
   if (valo == 0) {
     rtc.stopRTC();                  //blocco RTC
     rtc.setTime(0, 00, 00);         //azzero i valori
     rtc.setDate(01, 01, 2012);      //per poter riconteggiare da zero
     rtc.startRTC();         //riavvio rtc
   } else if ( valo == 30) {
     rtc.stopRTC();
     rtc.setTime(0, 30, 00);
   }
}

void stampalcd(int valor) {
   switch(valor){
     case livello_alto:
       lcd.clear();               //con il livello troppo alto avviso su display
       lcd.print ("! Livello Alto !");      //che il livello  è alto e
       lcd.print(" Valvola Aperta ");      //che apro la valvola
       break;
     case cambio_soglia:
       lcd.clear();                  //cancello il display
       lcd.print("Temperatura di");            //scrivo un testo
       lcd.setCursor(0, 1);                         //riposiziono il cursore
       lcd.print("soglia: ");            //scrivo di nuovo un testo
         lcd.print(tx,DEC);               //scrivo il valore impostato della temperatura di soglia
         lcd.write((byte)0);               //scrivo il °
         lcd.print ("C");                            //scrivo il C di Celsius
       break;
     case temp_bassa:
       lcd.clear();                   //alla temperatura di soglia e il tempo
       lcd.print("Temperatura ");             //trascorso dall'ultimo ciclo è di 10 minutì      
       lcd.print(tempmed,DEC);                      //scrivo sul display il valore e          
       lcd.write((byte)0);                          //avviso che il contatto è chiuso
       lcd.print("C");                                               
       lcd.setCursor(0, 1);                          //con la scritta " Valvola Aperta "
       lcd.print(" Valvola Aperta ");                //per finire
       break;
     default:
       lcd.clear();               //sempre sul display
       lcd.print("  Temperatura");         //il valore
       lcd.setCursor(0, 1);
       lcd.print("rilevata:  ");
       lcd.print(tempmed,DEC);                       
       lcd.write((byte)0);
       lcd.print("C");
       break;
   }
}
RyujiAndy
Avatar casuale
 
    Mozilla

Re: Termostato e sensore di livello con Arduino

Messaggioda Step » 29 dic 2012, 20:35

Come avevo detto c'è una bella differenza di codice, io da buon ignorante l'ho scritto in modo lineare, cioè nell'ordine che mi è venuto in mente, Ryuji ha fatto invece una lavoro da programmatore, ha riordinato il codice e diviso a sezioni in modo che sia più semplice andare a metterci le mani e personalmente mi sembra anche più "elegante"! :wow:

Comunque oggi l'ho compilato e caricato su Arduino, però ci deve essere qualcosa che non va nella lettura della temperatura o meglio nel calcolo della media, all'esterno c'era una temperatura di circa 9 o 10 gradi e il display mi variava tra 0 e 1 e non si schiodava di li, invece con il sistema per calcolare la media che avevo utilizzato io ottenevo temperature più coerenti (variazioni tra 8 e 10 gradi). Però come avevi fatto te mi piace di più perché tieni conto anche della misura precedente e questo migliora la stabilità della lettura finale.

Per adesso ho rimesso il mio codice, che bene o male il suo lavoro lo fa, intanto cercherò di capire cosa succede e soprattutto ho ordinato un po' di sensori termici (quello che ho trovato in giro) però digitali...Forse otterrò risultati migliori :sigh:
Step
Avatar utente
Amministratore
 
Messaggi: 2242
Iscritto il: 9 nov 2010, 19:36
Località: Una galassia lontana anni luce, dietro l'angolo!
    Windows 7 Firefox
Immagine
Tutto questo non vale per il wasabese.....
....è proprio un'altra lingua!

Re: Termostato e sensore di livello con Arduino

Messaggioda Step » 11 gen 2013, 0:43

Come dicevo sopra mi sono arrivati un po' di sensori termici e tra questi ho scelto di provare il DS18B20.
Probabilmente l'ho scelto grazie alla frase di Zoomx:
zoomx ha scritto:...Io invece sto giocando con il DS1820 che è invece digitale...


Comunque mi sono messo al pc e ho trovato le librerie per usarlo, i listati d'esempio e il datasheet, quindi mi sono messo all'opera e devo dire che con le librerie giuste (e corrette...) è semplicissimo da usare.
Il listato che ho buttato giù è questo:
Codice: Seleziona tutto
/*
Termostatino antigelo:
Lettura sensore termico ds18b20, visualizzazione su display 16x2,
modifica soglia con 2 pulsanti + e - su ingressi analogici,
visualizzazione soglia durante la modifica,
Sensore di livello ad immersione tramite ingresso analogico e
comando relais.
Pin Analogico 1 = pulsante incremento temperatura soglia
Pin Analogico 2 = pulsante riduzione temperatura soglia
Pin Analogico 3 = sonda di livello
Pin Digitali 2, 3, 4, 10, 11, 12 = lcd DB7, DB6, DB5, DB4, E, RS
Pin digitali 5, 6, 7, 8 = modulo relais
Pin Digital 13 = linea dati sensore DS18B20
Piedinatura DS18B20: pin 1 = GND, pin 2 = DQ, pin 3 = Vdd (Valida tra 3,3V e 5V)
*/

#include <OneWire.h>         //libreria per ds18b20
#include <DallasTemperature.h>      //libreria per conversione valore
#include <swRTC.h>                      //libreria per RTC
#include <LiquidCrystal.h>              //libreria per lcd
#define ONE_WIRE_BUS 13                   // Il terminale data del sensore è connesso alla porta 13 di Arduino

OneWire oneWire(ONE_WIRE_BUS);           // Imposto la comunicazione oneWire per il ds18b20
DallasTemperature sensors(&oneWire);   // Passo le info di oneWire alla DallasTemperature
LiquidCrystal lcd(12, 11, 10, 4, 3, 2); //stabilisco le uscite digitali per lcd 4 bit
swRTC rtc;                              //creo un'istanza della libreria RTC

  int rele_out1 = 5;     //stabilisco l'uscita digitale per il relè 1
  int rele_out2 = 6;     //stabilisco l'uscita digitale per il relè 2
  int rele_out3 = 7;     //stabilisco l'uscita digitale per il relè 3
  int rele_out4 = 8;     //stabilisco l'uscita digitale per il relè 4
  int pulsantepiu;       //pulsante incremento temperatura di soglia
  int pulsantemeno;      //pulsante diminuisco temperatura di soglia
  int tx;                //temperatura di soglia
  int cont;              //contatore usato per ottenere un valore medio di temperatura
  int temperatura;       //temperatura rilevata
  int durata;            //conteggio minuti per temporizzazione
  int livello;       //ingresso sonda livello 170 cm
   
  byte grado[8] = {      //creo i dati per il carattere °
  0b00010,
  0b00101,
  0b00010,
  0b00000,
  0b00000,
  0b00000,
  0b00000,
  0b00000,
};

void setup(){

  Serial.begin(9600);           //inizializzo la seriale
  sensors.begin();      //inizializzo la libreria per leggere il sensore
  lcd.createChar(0, grado);     //associo i dati del ° al carattere custom 0
  lcd.begin(16, 2);             //dichiaro il tipo di lcd
  pinMode(rele_out1, OUTPUT);   //assegno il modo uscita digitale al pin 5
  pinMode(rele_out2, OUTPUT);   //assegno il modo uscita digitale al pin 6
  pinMode(rele_out3, OUTPUT);   //assegno il modo uscita digitale al pin 7
  pinMode(rele_out4, OUTPUT);   //assegno il modo uscita digitale al pin 8

  tx = 1;                       //temperatura di soglia iniziale (valore di sicurezza in caso di interruzioni di alimentazione)
  pulsantepiu = 0;              //assegno valore 0 iniziale al pulsantepiù
  pulsantemeno = 0;             //assegno valore 0 iniziale al pulsantemeno
  livello = 0;         //assegno valore 0 iniziale alla sonda di livello
 
  rtc.stopRTC();                //blocco RTC per inserire i valori iniziali
  rtc.setTime(0, 00, 00);       //metto valori a zero perché
  rtc.setDate(01, 01, 2012);    //devo usare RTC solo come timer
  rtc.startRTC();               //avvio RTC

}

void loop() {

   sensors.requestTemperatures();    // Invia il comando di lettura delle temperatura
   int durata = rtc.getMinutes();    //acquisisco i minuti
   
   if (durata > 10){                       //se durata è maggiore di 10 minuti
      rtc.stopRTC();                  //blocco RTC
      rtc.setTime(0, 00, 00);         //azzero i valori
      rtc.setDate(01, 01, 2012);      //per poter riconteggiare da zero
      rtc.startRTC();                 //riavvio rtc
   }
 
   int pulsantepiu = analogRead(A1);    //lettura ingresso analogico 1 e assegnazione del valore a pulsantepiù
   int pulsantemeno = analogRead(A2);   //lettura ingresso analogico 2 e assegnazione del valore a pulsantemeno
   
   if (pulsantepiu == 0){                        //se il pulsantepiù vieno premuto verso il negativo
      tx = tx ++;                           //la variabile temperatura di soglia tx incrementa di una unita
      lcd.clear();               //cancello il display
      lcd.print("Temperatura di");         //scrivo un testo
      lcd.setCursor(0, 1);                 //riposiziono il cursore
      lcd.print("soglia: ");            //scrivo di nuovo un testo
      lcd.print(tx,DEC);            //scrivo il valore impostato della temperatura di soglia
      lcd.write((byte)0);            //scrivo il °
      lcd.print ("C");                      //scrivo il C di Celsius
      delay(1000);                          //ritardo di 1 secondi per la lettura
   }

   if (pulsantemeno == 0){                       //se il pulsantemeno vieno premuto verso il negativo
      tx = tx --;                           //la variabile temperatura di soglia tx decrementa di una unità
      lcd.clear();               //cancello il display
      lcd.print("Temperatura di");         //scrivo un testo
      lcd.setCursor(0, 1);                 //riposiziono il cursore
      lcd.print("soglia: ");            //scrivo di nuovo un testo
      lcd.setCursor(10, 1);            //riposiziono il cursore
      lcd.print(tx,DEC);            //scrivo il valore impostato della temperatura di soglia
      lcd.write((byte)0);            //scrivo il °
      lcd.print ("C");                      //scrivo il C di Celsius
      delay(1000);                          //ritardo di 1 secondi per la lettura
   }


    while (analogRead(A3) == 0) {         //lettura ingresso analogico A3 e confronto con valore 0 (CONTATTO CHIUSO)
      lcd.clear();            //con il livello troppo alto avviso su display
      lcd.print ("! Livello Alto !");      //che il livello  è alto e
      lcd.print(" Valvola Aperta ");      //che apro la valvola
      digitalWrite(rele_out1, HIGH);      //comando anche il rele 1 di apertura valvola
      digitalWrite(rele_out2, HIGH);      //comando anche il rele 2 di apertura valvola
      digitalWrite(rele_out3, HIGH);      //comando anche il rele 3 di apertura valvola
      digitalWrite(rele_out4, HIGH);      //comando anche il rele 4 di apertura valvola
   }
   
/*Lettura temperatura con ds18b20 */
    int temperatura = sensors.getTempCByIndex(0);   //lettura ingresso digitale 13 e assegnazione del valore alla variabile temperatura

   if(temperatura <= tx && durata == 10){           //se la temperatura rilevata è minore o uguale rispetto
      lcd.clear();            //alla temperatura di soglia e il tempo
      lcd.print("Temperatura ");      //trascorso dall'ultimo ciclo è di 10 minutì      
      lcd.print(temperatura,DEC);             //scrivo sul display il valore e          
      lcd.write((byte)0);                     //avviso che il contatto è chiuso
      lcd.print("C");                                             
      lcd.setCursor(0, 1);                    //con la scritta " Valvola Aperta "
      lcd.print(" Valvola Aperta ");          //per finire
      digitalWrite(rele_out1, HIGH);           //comando anche il rele 1 di apertura valvola
                digitalWrite(rele_out2, HIGH);           //comando anche il rele 2 di apertura valvola
      digitalWrite(rele_out3, HIGH);      //comando anche il rele 3 di apertura valvola
                digitalWrite(rele_out4, HIGH);          //comando anche il rele 4 di apertura valvola
      delay(60000);                           // e comando i relè per un minuto
   }else{                  //altrimenti scrivo
      lcd.clear();            //sempre sul display
      lcd.print("  Temperatura");      //il valore
      lcd.setCursor(0, 1);
      lcd.print("rilevata:  ");
      lcd.print(temperatura,DEC);                       
      lcd.write((byte)0);
      lcd.print("C");
      digitalWrite(rele_out1, LOW);      //mantengo bassa l'uscita digitale 5
      digitalWrite(rele_out2, LOW);      //mantengo bassa l'uscita digitale 6
      digitalWrite(rele_out3, LOW);      //mantengo bassa l'uscita digitale 7
      digitalWrite(rele_out4, LOW);      //mantengo bassa l'uscita digitale 8
   

        }
/*invio le inforamazioni anche al serial monitor della IDE*/

        Serial.print ("temperatura di soglia = ");
   Serial.println (tx, DEC);                   
        Serial.println (" ");
        Serial.print ("Temperatura rilevata = ");
        Serial.println (temperatura, DEC);
        Serial.println (" ");
        Serial.println (" ");
   Serial.println("durata");
   Serial.println(durata,DEC);
   Serial.println(rtc.getSeconds(),DEC);
        Serial.println (" ");
        Serial.println (" ");
}



Questo sotto è invece lo schema del circuito con il collegamento del DS18B20, come si vede sia dal codice che dallo schema non mi sono scostato tanto dal progetto originale con LM35.

Immagine


Prima ho parlato di libreria corretta, perché in realtà la OneWire che si trova in giro, anche sul sito di Arduino, contiene due errori, uno per età, fa ancora riferimento alla libreria core di arduino chiamata WConstant.h che invece è stata sostituita dalla Arduino.h ed in più contiene una variabile r unsignent int che crea problemi per la lettura delle temperature negative, basta trasformarla in signed, bisogna modificare la linea 88 e sostituire uint8_t r; con int8_t r;. Ovviamente non sono un pazzo che ha studiato anni di linguaggio C condensato in 2 ore, visto che ricevevo errori di compilazione ho fatto delle ricerche e questo è il risultato.
Ho già sostituito la sonda, riprogrammato arduino, testato anche in frigo, rimontato sul pozzo e per ora tutto funziona...quindi speriamo che duri!
Step
Avatar utente
Amministratore
 
Messaggi: 2242
Iscritto il: 9 nov 2010, 19:36
Località: Una galassia lontana anni luce, dietro l'angolo!
    Windows 7 Firefox
Immagine
Tutto questo non vale per il wasabese.....
....è proprio un'altra lingua!

Re: Termostato e sensore di livello con Arduino

Messaggioda student » 11 gen 2013, 12:30

Bravo boss !
student
Avatar casuale
 
    Windows 7 Chrome

Re: Termostato e sensore di livello con Arduino

Messaggioda Step » 11 gen 2013, 16:54

IL termostatino è stato linkato e citato da un amico che ne ha parlato nel suo blog:
I link sono visibili solamente agli utenti registrati. Per favore registrati o effettua il login.
Step
Avatar utente
Amministratore
 
Messaggi: 2242
Iscritto il: 9 nov 2010, 19:36
Località: Una galassia lontana anni luce, dietro l'angolo!
    Windows 7 Firefox
Immagine
Tutto questo non vale per il wasabese.....
....è proprio un'altra lingua!

Prossimo

Torna a Progetti

Chi c’è in linea

Visitano il forum: Nessuno e 1 ospite

cron