Mar 152015
 

Dopo il precedente articolo sulla rilevazione delle fughe di gas, oggi vediamo come sfruttare i sensori della famiglia DHT per misurare temperatura ed umidità. Dopo questa prima parte vedremo come inviare i dati acquisiti ad una stazione remota sfruttando i moduli NRF24L01 che avevamo studiato già in questo articolo e con cui avevamo creato un progetto più complesso in ques’altro articolo. Ci sono due modelli di sensore DHT che si differenziano essenzialmente per la diversa precisione oltre che ovviamente per il prezzo. Nell’articolo userò un sensore DHT11 che era presente un kit “37 in 1” che avevo già in casa ma non vi sono sostanziali differenze con il più preciso DHT22.

Ho raggruppato nella seguente tabella i due sensori con le principali caratteristiche, si noti che l’involucro plastico bianco o blu rendono molto facile la differenziazione fra i due.

Sensore Caratteristiche Note

DHT11dht11

Temperatura: 0-50 ±2% (risoluzione 1°)

Umidità: 20-90% ± 5% (risoluzione 1%)

Assorbimento: max 2.5 mA

Alimentazione: 3-5.5V

Velocità di campionamento: 1Hz.

E’ il più economico della serie, ma anche il meno preciso e più lento. Non legge temperature inferiori agli zero gradi.

DHT22

dth22

Temperatura: -40-125±0.2% (risoluzione 0.1°)

Umidità: 0-100% ± 2-5% (risoluzione 0.1%)

Assorbimento: max 2.1 mA

Alimentazione: 3.3-6V

Velocità di campionamento: 0.5Hz

Internamente è utilizzato un sensore DS18B20 per la misurazione della temperatura. E’ più preciso del precedente, ad un costo però superiore.

Una cosa a cui prestare estrema attenzione è, come spesso accade in molti sensori, la differenza con cui devono essere connessi visto che i pin non si trovano sempre nella stessa sequenza. Per questo motivo dovete sempre fare riferimento alla documentazione del modello in vostro possesso e, se possibile, verificare anche se la serigrafia stampata sul modulo corrisponde alla documentazione. Diciamo subito che questi moduli utilizzano tre pin, uno per l’alimentazione, una massa ed un pin per il transito dei dati. Se ci sono 4 pin, uno risulterà non collegato. Una volta identificati i 3 pin il cablaggio rasenta la banalità, il 5V andrà collegato all’alimentazione, GND a massa e il pin rimanente ad uno dei pin digitali di Arduino. Viene consigliato l’utilizzo di un resistore da 5K fra il pin dei dati ed i 5V come resistore di pull-up. Questo diventa particolarmente utile con l’incremento della lunghezza del cavo che collega Arduino al sensore stesso, nel caso di cablaggi che vanno oltre i 20 metri potrà essere necessario ridurre il valore di resistenza. Per cablaggi molto corti potete anche omettere il resistore, io ad esempio non l’ho usato e non ho avuto nessun problema. Come per tutti gli integrati, viene consigliato l’uso di un condensatore da 100nF fra 5V e GND per smussare le variazioni di tensione durante il funzionamento del sensore.

Questi sensori comunicano in maniera seriale attraverso il pin dati, con metodologie simili ma non identiche e quindi non compatibili con l’1-wire che abbiamo ampiamente trattato in questo blog. Per una volta mi limiterò ad usare una libreria già pronta senza andare a sviscerare il protocollo di comunicazione; ho seguito il playground ufficiale e sono approdato qui perciò vi consiglio di scaricare la libreria da quel link. Partendo da uno dei semplici esempi ci vuole davvero poco a creare uno sketch in grado di leggere temperatura ed umidità. Lo sketch di base legge i sensori DHT11, ma se seguite le modifiche poste nei commenti in linea potete leggere i sensori DHT22 con la modifica di una sola riga di codice. Nell’esempio ho lasciato il pin numero 5 per la ricezione dei dati dal sensore.

#include <dht.h>
dht DHT;
#define DHT_PIN 5

void setup()
{
  Serial.begin(9600);
  Serial.println("DHT TEST PROGRAM ");
  Serial.print("LIBRARY VERSION: ");
  Serial.println(DHT_LIB_VERSION);
  Serial.println();
  Serial.println("Type,\tstatus,\tHumidity (%),\tTemperature (C)");
}

void loop()
{
  // READ DATA
  Serial.print("dhtXX, \t");
  int chk = DHT.read11(DHT_PIN);  // chk = DHT.read22(DHT_PIN); cambia questa riga se vuoi usare i DHT22
  switch (chk)
  {
    case DHTLIB_OK:  
        Serial.print("OK,\t"); 
        break;
    case DHTLIB_ERROR_CHECKSUM: 
        Serial.print("Checksum error,\t"); 
        break;
    case DHTLIB_ERROR_TIMEOUT: 
        Serial.print("Time out error,\t"); 
        break;
    case DHTLIB_ERROR_CONNECT:
        Serial.print("Connect error,\t");
        break;
    case DHTLIB_ERROR_ACK_L:
        Serial.print("Ack Low error,\t");
        break;
    case DHTLIB_ERROR_ACK_H:
        Serial.print("Ack High error,\t");
        break;
    default: 
        Serial.print("Unknown error,\t"); 
        break;
  }
  // DISPLAY DATA
  Serial.print(DHT.humidity, 1);
  Serial.print(",\t");
  Serial.println(DHT.temperature, 1);

  delay(2000); 
}

Con questo sketch siete già operativi e potete vedere su seriale sia le letture di temperatura ed umidità che eventuali messaggi di errore. 

Invio remoto tramite nrf24

rf24-pinUn utente del blog mi chiedeva come inviare i dati di temperatura ed umidità letti con questi sensori, attraverso i moduli nrf24. Per prima cosa dobbiamo collegare il modulo nrf24, nulla di complicato, riporto però per praticità il pinout del modulo e i principali pin spi delle schede Arduino. Prendo sempre come riferimento il collegamento con Arduino UNO, ma ovviamente dovete adattare i collegamenti in base alla scheda che state utilizzando. Ricordo che il pin IRQ non lo colleghiamo, mentre MISO, MOSI, SCK vanno ai rispettivi pin dell’interfaccia SPI di Arduino (vedi tabella seguente). GND e VCC, vanno collegate alle rispettive linee facendo MOLTA attenzione che l’alimentazione deve essere collegata alla linea a 3.3V e NON a quella 5V. CSN lo mettiamo sul pin 10 e CE (SS) sul pin 9, in questo modo dovreste aver occupato, su Arduino UNO, tutti i pin dal 13 al 9 compresi. Sul pin 5 è sempre connessa la linea dati del sensore, in più ci saranno i rispettivi collegamenti della massa, la linea 5V del sensore e la linea 3.3V del modulo nrf24. Una volta fatti i collegamenti dobbiamo passare al software.  Per semplificarci la vita non cercherò di inventare nuove soluzioni, ma userò lo stesso identico approccio visto nello scorso articolo, con gli ovvi adattamenti del caso. Per cercare di rendere la comprensione il più semplice possibile, eliminerò ogni cosa non indispensabile, perciò facciamo a meno di qualsiasi gestione degli errori e ci limitiamo unicamente ad inviare i dati di temperatura ed umidità. 

Arduino Board MOSI MISO SCK SS (slave) SS (master)
Uno / Duemilanove / Pro / Nano / Fio 11 or ICSP-4 12 or ICSP-1 13 or ICSP-3 10
Mega1280 or Mega2560 51 or ICSP-4 50 or ICSP-1 52 or ICSP-3 53
Leonardo / Micro / YUN ICSP-4 ICSP-1 ICSP-3
Due ICSP-4 ICSP-1 ICSP-3 4, 10, 52
Mini 11 12 13

 E’ prevista una sezione del codice che riceve messaggi dalla controparte remota, nell’esempio sotto riceve ogni 30 secondi il valore di millis() della scheda remota. Questo dato non viene usato in nessun modo nell’esempio ma permette di avere un pezzo di codice già pronto per la gestione degli eventi remoti.

Vediamo il codice da installare sulla scheda con i sensori: 

// facciamo le necessarie inclusioni
#include <dht.h>
#include <SPI.h>
#include <Mirf.h>
#include <MirfHardwareSpiDriver.h>
#include <Time.h>
dht DHT;
#define DHT_PIN 5
unsigned long tempo; // usata per contare il tempo trascorso....
// struct ed union usate per lo scambio di dati su nrf24
union DataMix
{
 char datachar[4];
 int dataint[2];
 float datafloat;
 unsigned long datalong;
} ;
struct McMajanData
{
 char Command;
 union DataMix Data;
} ;
union dataRF24
{
 char databuffer[5];
 struct McMajanData IO;
};
dataRF24 IORF24;
void setup(void)
{
 Serial.begin(9600);// inizializza la porta seriale a 9600
 Mirf.cePin = 9; //SS
 Mirf.csnPin = 10; // CSN
 Mirf.spi = &MirfHardwareSpi;
 Mirf.init();
 Mirf.setRADDR((byte *)"c0001"); //nome del client
 Mirf.payload = 5; // usiamo comandi composti da 5 bytes
 Mirf.channel =90; // canale numero 90
 Mirf.config();
 Mirf.configRegister(RF_SETUP,0x26); //250k
 //Mirf.configRegister(RF_SETUP,0x00); //1mb
 //Mirf.configRegister(RF_SETUP,0x0E); //2mb
 
 tempo=0;
}
void loop(void)
{
 char * data; 
 // riceve comunicazioni via nrf24
 if(!Mirf.isSending() && Mirf.dataReady())
 {
  // queste righe servono ad espandere il software per leggere messaggi di ritorno dall'altra scheda
   Serial.println("Ricezione dati....");
  Mirf.getData((uint8_t *)IORF24.databuffer);
  if(IORF24.IO.Command=='X') // ho ricevuto comando T (che su Arduino remoto è la ricezione termica
  {
   Serial.println("Ricevuto ping remoto ");
   float temporemoto=(float)(IORF24.IO.Data.datafloat); // ... elaborazione dati a proprio piacimento
  }
 }
 
 if(tempo+30000<millis()) // ripete il ciclo ogni 30 secondi
 {
  tempo=millis();
  int chk = DHT.read11(DHT_PIN); // oppure int chk = DHT.read22(DHT_PIN);
  if (chk==DHTLIB_OK) // lettura avvenuta correttamente
  { // invio temperatura
   IORF24.IO.Data.datalong=DHT.temperature;
   IORF24.IO.Command='T'; 
   Mirf.setTADDR((byte *)"s0001");
   Mirf.send((byte *)IORF24.databuffer);
   while(Mirf.isSending()){}
  // .. e umidità
  
  IORF24.IO.Data.datalong=DHT.humidity;
  IORF24.IO.Command='H'; 
  Mirf.setTADDR((byte *)"s0001");
  Mirf.send((byte *)IORF24.databuffer);
  while(Mirf.isSending()){}
  delay(100);
 }
} // millis
}

 Ed ora vediamo la controparte remota che riceve i dati di temperatura ed umidità:

// facciamo le necessarie inclusioni
#include <dht.h>
#include <SPI.h>
#include <Mirf.h>
#include <MirfHardwareSpiDriver.h>
#include <Time.h>
dht DHT;
#define DHT_PIN 5
unsigned long tempo; // usata per contare il tempo trascorso....
// struct ed union usate per lo scambio di dati su nrf24
union DataMix
{
 char datachar[4];
 int dataint[2];
 float datafloat;
 unsigned long datalong;
} ;
struct McMajanData
{
 char Command;
 union DataMix Data;
} ;
union dataRF24
{
 char databuffer[5];
 struct McMajanData IO;
};
dataRF24 IORF24;
void setup(void)
{
 Serial.begin(9600);// inizializza la porta seriale a 9600
 Mirf.cePin = 9; //SS
 Mirf.csnPin = 10; // CSN
 Mirf.spi = &MirfHardwareSpi;
 Mirf.init();
 Mirf.setRADDR((byte *)"s0001"); //nome del client
 Mirf.payload = 5; // usiamo comandi composti da 5 bytes
 Mirf.channel =90; // canale numero 90
 Mirf.config();
 Mirf.configRegister(RF_SETUP,0x26); //250k
 //Mirf.configRegister(RF_SETUP,0x00); //1mb
 //Mirf.configRegister(RF_SETUP,0x0E); //2mb
 
 tempo=0;
}
void loop(void)
{
 char * data; 
 // riceve comunicazioni via nrf24
 if(!Mirf.isSending() && Mirf.dataReady())
 {
 Serial.println("Ricezione dati....");
 Mirf.getData((uint8_t *)IORF24.databuffer);
 if(IORF24.IO.Command=='T') // ho ricevuto comando T (che su Arduino remoto è la ricezione termica
 {
 Serial.print("Ricevuta temperatura remota: ");
 float temperatura=(float)(IORF24.IO.Data.datafloat); // ricavo temperatura
 Serial.println(temperatura, 1);
 }
 if(IORF24.IO.Command=='H') // ho ricevuto comando T (che su Arduino remoto è la ricezione termica
 {
 Serial.print("Ricevuta temperatura remota: ");
 float humidity=(float)(IORF24.IO.Data.datafloat); // ricavo umidità
 Serial.println(humidity, 1);
 } 
 }
 
 if(tempo+30000<millis()) // ripete il ciclo ogni 30 secondi
 {
  tempo=millis();
  IORF24.IO.Data.datalong=tempo; // invio i millis()
  IORF24.IO.Command='X'; 
  Mirf.setTADDR((byte *)"c0001");
  Mirf.send((byte *)IORF24.databuffer);
  while(Mirf.isSending()){}
  delay(100);
 } // millis
}

Ad essere onesto non ho un modulo nrf24 libero per fare i test per cui ho scritto il codice senza testarlo, ma non dovrebbero esserci problemi visto che è lo stesso degli scorsi articoli, adattato per l’occasione. Ho verificato che la compilazione avvenga correttamente e, caso più unico che raro, non ho riscontrato nemmeno un piccolo errore di digitazione. Detto ciò nell’articolo di oggi abbiamo visto come sia abbastanza semplice modificare il software visto in precedenza ed adattarlo a nuove situazioni. Questo era l’intento dell’articolo originale e devo ammettere che passare dall’uso dei ds18b20 ai DHT è stato molto facile. Anche se abbiamo usato temperature ed umidità potete tranquillamente, con poche modifiche, trasmettere qualunque grandezza fisica, che sia essa una velocità, pressione, accelerazione, profondità, distanza, frequenza, etc, etc, etc….

  2 Responses to “Arduino, temperatura, umidità e trasmissione remota – it”

  1.  

    Ciao Stefano lo sketch ricevente puo’ funzionare sul raspberry?
    Hai un email?

    •  

      Se con ricevente intendi la scheda che riceve dati attraverso il modulino nrf allora non ho delle certezze. Per prima cosa dovresti installare Wiring sul RB, ma poi non ho idea di come si comporterebbe la mia libreria, non ho mai provato a compilarla sul RB e dubito che funzionerebbe al primo colpo senza modifiche. Se invece intendevi la parte che “riceve” i dati via web, allora si, basta che sia installato il web server con relativo php e dovrebbe funzionare tutto senza alcuna modifica. Ho da poco cominciato a scrivere un software web decisamente molto complesso che permette la gestione multiutente / multiboaard per raccogliere / gestire dati remoti e che funzionerà anche su RB….ma ci vorrà un bel po’ di tempo prima che possa iniziare ad usarlo, sono ancora allo “scheletro”, per ora è pronta tutta la parte che gestisce utenti / permessi / registrazioni, etc e stò creando il “motore” che genera le pagine web dinamicamente…..ma la strada è lunga e piena di insidie….la mia mail smania2000@gmail.com, è attiva anche info@mcmajan.com ma la leggo solo saltuariamente…. per ora….