Rassegna dettagliata di sensori di temperatura per Arduino – Misurare la temperatura con Arduino

Ho recentemente iniziato a costruire un termostato WiFi basato su NodeMCU (ESP8266) controllabile attraverso Telegram.

[TUTORIAL] 1 – Interfacciare NodeMCU (esp8266) con un BOT Telegram – Domotica con Telegram

 

Qui Trovate la guida per poterlo programmare con L’IDE di Arduino

Qui Trovate la guida per interfacciarlo con Telegram

Ma non divaghiamo troppo! Uno dei punti che ho trovato più difficili nella realizzazione del termostato è la scelta del sensore di temperatura. Lo scenario dei sensori di temperatura supportati dalle librerie di Arduino è tutto sommato abbastanza ampio, andiamo però ad analizzare effettivamente la precisione, l’accuratezza a la precisione (parametri con i quali spesso facciamo confusione).


Iscriviti al nostro canale YouTube per saperne di più! 🙂
Facciamo innanzitutto brevemente chiarezza su questi tre parametri che caratterizzano un sensore. Non utilizzerò termini troppo complicati, proverò invece a spiegare in maniera molto grossolana i significati in modo da rendere l’idea.

La PRECISIONE quantifica quanto, ripetendo con lo stesso sensore la stessa misura più volte, i risultati saranno gli stessi. Più i risultati saranno differenti, meno il sensore si può ritenere preciso. Effettuado più misure i valori avranno quindi una dispersione legata alla precisione del sensore, e una media. Da qui partiamo per parlare di ACCURATEZZA.

L’ACCURATEZZA rappresenta, in pochissime parole, quanto la media dei valori misurati si discosta dal VALORE VERO o VALORE DI RIFERIMENTO. Ecco una figura che rappresenta, secondo me chiaramente, il concetto.accuracy_and_precisionPer quanto invece riguarda la RISOLUZIONE, è la capacità, nella misura di una grandezza fisica, di rilevare piccole variazioni della grandezza fisica in esame. Penso che con un esempio tutto questo si chiarifichi molto meglio. Supponiamo di pesare 1kg di sale con una bilancia con risoluzione 0,1kg. Mettiamo sulla bilancia 1kg esatto sulla bilancia, il display ci indicherà 1kg. Aggiungendo 40g di sale la bilancia continuerà a indicare 1,0kg. Continuando ad aggiungere sale fino ad arrivare a 1,050kg la bilancia continuerà a indicare 1,0kg. Possiamo quindi dire che una bilancia con una RISOLUZIONE di 0,1kg, segnerà 1,0kg se sopra di essa metteremo una quantità che va da da 0,950kg a 1,050kg, non riuscendo a rilevare quindi le variazioni di peso all’interno di questo “GAP”.

Dopo aver divagato un po’, arriviamo al sodo! Avevamo iniziato a parlare di sensori….

I sensori che ho avuto modo di provare sono:

DHT11 (OneWire)  –  Datasheet

DHT22 (OneWire)  –  Datasheet

DS18B20 (Onewire)  –  Datasheet

MPU6050  (I2C)  –  Datasheet  (oltre a essere Accelerometro e Giroscopio è anche sensore di temperatura)

Senza stare a fare troppi discorsi vi riporto in una tabella le caratteristiche principali di questi sensori.

SensoreAlimeentazione [V]Range T [°C]Precisione [°C]Accuratezza [°C]Risoluz.   
DHT113.3 - 5.50/+50±0.5±2±1
DHT223.3 - 5.5-40/+80±0.2±0.5±0.1
DS18B203.3 - 6-10/+85±0.1±0.5±0.0625 (configurabile)
MPU-60502.375 - 3.46-40/+85±0.2±1±0.5
#include <dht11.h>
dht11 DHT;
#define DHT11_PIN 4
 
void setup(){
  Serial.begin(9600);
  Serial.println("DHT TEST PROGRAM ");
  Serial.print("LIBRARY VERSION: ");
  Serial.println(DHT11LIB_VERSION);
  Serial.println();
  Serial.println("Type,\tstatus,\tHumidity (%),\tTemperature (C)");
}
 
void loop(){
  int chk;
  Serial.print("DHT11, \t");
  chk = DHT.read(DHT11_PIN);    // READ DATA
  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;
    default: 
                Serial.print("Unknown error,\t"); 
                break;
  }
 // DISPLAT DATA
  Serial.print(DHT.humidity,1);
  Serial.print(",\t");
  Serial.println(DHT.temperature,1);
 
  delay(1000);
}

DHT22

#include <dht.h>

dht DHT;

#define DHT11_PIN 4
#define DHT21_PIN 5
#define DHT22_PIN 6

void setup()
{
  Serial.begin(115200);
  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("DHT22, \t");
  int chk = DHT.read22(DHT22_PIN);
  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;
    default: 
		Serial.print("Unknown error,\t"); 
		break;
  }
  // DISPLAY DATA
  Serial.print(DHT.humidity, 1);
  Serial.print(",\t");
  Serial.println(DHT.temperature, 1);

  delay(1000);


    // READ DATA
  Serial.print("DHT21, \t");
  chk = DHT.read21(DHT21_PIN);
  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;
    default: 
		Serial.print("Unknown error,\t"); 
		break;
  }
  // DISPLAY DATA
  Serial.print(DHT.humidity, 1);
  Serial.print(",\t");
  Serial.println(DHT.temperature, 1);

  delay(1000);

  // READ DATA
  Serial.print("DHT11, \t");
  chk = DHT.read11(DHT11_PIN);
  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;
    default: 
		Serial.print("Unknown error,\t"); 
		break;
  }
 // DISPLAY DATA
  Serial.print(DHT.humidity,1);
  Serial.print(",\t");
  Serial.println(DHT.temperature,1);

  delay(1000);
}

MPU6050

#include<Wire.h>
const int MPU_addr=0x68;  // I2C address of the MPU-6050
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;
void setup(){
  Wire.begin();
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x6B);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
  Serial.begin(9600);
}
void loop(){
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_addr,14,true);  // request a total of 14 registers
  AcX=Wire.read()<<8|Wire.read();  // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)    
  AcY=Wire.read()<<8|Wire.read();  // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  AcZ=Wire.read()<<8|Wire.read();  // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  Tmp=Wire.read()<<8|Wire.read();  // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
  GyX=Wire.read()<<8|Wire.read();  // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  GyY=Wire.read()<<8|Wire.read();  // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  GyZ=Wire.read()<<8|Wire.read();  // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
  Serial.print("AcX = "); Serial.print(AcX);
  Serial.print(" | AcY = "); Serial.print(AcY);
  Serial.print(" | AcZ = "); Serial.print(AcZ);
  Serial.print(" | Tmp = "); Serial.print(Tmp/340.00+36.53);  //equation for temperature in degrees C from datasheet
  Serial.print(" | GyX = "); Serial.print(GyX);
  Serial.print(" | GyY = "); Serial.print(GyY);
  Serial.print(" | GyZ = "); Serial.println(GyZ);
  delay(333);
}

DS18B20

#include <OneWire.h>
#include <LiquidCrystal.h>

#define BUTTON A0

int DS18B20_Pin = 2;

OneWire ds(DS18B20_Pin);
LiquidCrystal lcd(8,9,4,5,6,7);

void setup(void) {
  Serial.begin(9600);

  lcd.begin(16, 2);

  lcd.setCursor(0,0);
  lcd.print("  DS18B20 LCD  ");
  lcd.setCursor(0,1);
  lcd.print("mauroalfieri.it");

  delay( 3000 );
}

void loop(void) {
  float temperature = getTemp();
  Serial.println(temperature);

  lcd.clear(); 
  lcd.setCursor(0,0);
  lcd.print("Temperatura:   ");
  lcd.setCursor(0,1);
  lcd.print(temperature);

  delay(1000); //just here to slow down the output so it is easier to read

}

float getTemp(){
  //returns the temperature from one DS18B20 in DEG Celsius

  byte data[12];
  byte addr[8];

  if ( !ds.search(addr)) {
      //no more sensors on chain, reset search
      ds.reset_search();
      return -1000;
  }

  if ( OneWire::crc8( addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return -1000;
  }

  if ( addr[0] != 0x10 && addr[0] != 0x28) {
      Serial.print("Device is not recognized");
      return -1000;
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44,1); // start conversion, with parasite power on at the end

  byte present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE); // Read Scratchpad

  for (int i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds.read();
  }

  ds.reset_search();

  byte MSB = data[1];
  byte LSB = data[0];

  float tempRead = ((MSB << 8) | LSB); //using two's compliment
  float TemperatureSum = tempRead / 16;

  return TemperatureSum;

}

Ecco un video dove illustro l’utilizzo del DHT11