luni, 22 aprilie 2013

Ministatie meteo cu senzorul DHT11 si.. Arduino

   Desi o statie meteo ofera mai multe date decat temperatura si umiditatea, am considerat ca si aceste date sunt "bune" pentru o "ministatie meteo"...
   Totul se bazeaza pe un senzor dedicat DHT11, care nu are o precize uimitoare, dar pentru aplicatii casnice este  acceptabil (domeniu de temperatura 0..50oC cu precizie de +2oC, respectiv umiditate 20..90%RH cu o precizie de +5%RH).
   Inainte de a face vreo proba, m-am documentat un pic si primele adrese relevante ar fi:
http://www.hobbyist.co.nz/?q=taxonomy/term/10
http://learn.adafruit.com/dht/connecting-to-a-dhtxx-sensor
http://playground.arduino.cc/main/DHT11Lib
http://stigern.net/blog/?p=373
http://arduino-info.wikispaces.com/PROJECT-Temp-Humidity-Display
http://dalxxdht11.blogspot.ro/2012/12/dht11-library-for-arduino-uno.html

   Prima proba s-a facut cu senzorul DHT11 avand pinul conectat la A2 (analog 2) de la Arduino, iar afisajul cu cristale lichide cu 16 coloane si 2 randuri LCD1602 conectat ca in exemplele de pe site-ul Arduino,

sketck-ul folosit fiind:


// LCD1602A 
// * LCD RS pin to digital pin 12
// * LCD Enable pin to digital pin 11
// * LCD D4 pin to digital pin 5
// * LCD D5 pin to digital pin 4
// * LCD D6 pin to digital pin 3
// * LCD D7 pin to digital pin 2
// * LCD R/W pin to ground
// * 10K resistor:
// * ends to +5V and ground
// * wiper to LCD VO pin (pin 3)

//Celsius to Fahrenheit conversion
double Fahrenheit(double celsius)
{
        return 1.8 * celsius + 32;
}

double Kelvin(double celsius)
{
        return celsius + 273.15;
}

double dewPoint(double celsius, double humidity)
{
        double RATIO = 373.15 / (273.15 + celsius);  // RATIO was originally named A0, possibly confusing in Arduino context
        double SUM = -7.90298 * (RATIO - 1);
        SUM += 5.02808 * log10(RATIO);
        SUM += -1.3816e-7 * (pow(10, (11.344 * (1 - 1/RATIO ))) - 1) ;
        SUM += 8.1328e-3 * (pow(10, (-3.49149 * (RATIO - 1))) - 1) ;
        SUM += log10(1013.246);
        double VP = pow(10, SUM - 3) * humidity;
        double T = log(VP/0.61078);   // temp var
        return (241.88 * T) / (17.558 - T);
}

// delta max = 0.6544 wrt dewPoint()
// 5x faster than dewPoint()
// reference: http://en.wikipedia.org/wiki/Dew_point
double dewPointFast(double celsius, double humidity)
{
        double a = 17.271;
        double b = 237.7;
        double temp = (a * celsius) / (b + celsius) + log(humidity/100);
        double Td = (b * temp) / (a - temp);
        return Td;
}

#include <dht11.h>
dht11 DHT11;
#define DHT11PIN A2 // sensor pin is at A2
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup()
{
  Serial.begin(9600);
  Serial.println("DHT11 TEST PROGRAM ");
  Serial.print("LIBRARY VERSION: ");
  Serial.println(DHT11LIB_VERSION);
  Serial.println();
    // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("ministatie meteo");
}

void loop()
{
  Serial.println("\n");

  int chk = DHT11.read(DHT11PIN);

  Serial.print("Read sensor: ");
  switch (chk)
  {
    case DHTLIB_OK: 
                Serial.println("OK"); 
                break;
    case DHTLIB_ERROR_CHECKSUM: 
                Serial.println("Checksum error"); 
                break;
    case DHTLIB_ERROR_TIMEOUT: 
                Serial.println("Time out error"); 
                break;
    default: 
                Serial.println("Unknown error"); 
                break;
  }

  Serial.print("Humidity (%): ");
  Serial.println((float)DHT11.humidity, 2);

  Serial.print("Temperature (oC): ");
  Serial.println((float)DHT11.temperature, 2);

  Serial.print("Temperature (oF): ");
  Serial.println(Fahrenheit(DHT11.temperature), 2);

  Serial.print("Temperature (K): ");
  Serial.println(Kelvin(DHT11.temperature), 2);

  Serial.print("Dew Point (oC): ");
  Serial.println(dewPoint(DHT11.temperature, DHT11.humidity));

  Serial.print("Dew PointFast (oC): ");
  Serial.println(dewPointFast(DHT11.temperature, DHT11.humidity));

  delay(2000);

 // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(1, 1);
  // print the number of seconds since reset:
  lcd.print((float)DHT11.temperature, 1);
  lcd.write(0b11011111);
  lcd.print("C H=");

  lcd.print((float)DHT11.humidity, 1);
  lcd.print("%");
}




   Am facut si un filmulet numit ministatie meteo cu DHT11, LCD1602 si Arduino (I):

   Am conectat apoi afisajul LCD 1602A cu interfata i2c cu sketch-ul gasit la http://blog.gotencool.com/2012_03_01_archive.html modificand adresa de la 0x27 la 0x20

#include <Wire.h>
  
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x20,16,2); // 0x27 es la direccion del LCD 16x2
void setup(){
    lcd.init(); 
    lcd.backlight(); //enciende la iluminacion
    lcd.setCursor(0, 0);
    lcd.print("Probando i2c");
}
void loop(){
    delay(1000);
}



apoi am combinat cele 2 sketch-uri:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x20,16,2); // 0x27 es la direccion del LCD 16x2
//Celsius to Fahrenheit conversion
double Fahrenheit(double celsius)
{
        return 1.8 * celsius + 32;
}

double Kelvin(double celsius)
{
        return celsius + 273.15;
}

double dewPoint(double celsius, double humidity)
{
        double RATIO = 373.15 / (273.15 + celsius);  // RATIO was originally named A0, possibly confusing in Arduino context
        double SUM = -7.90298 * (RATIO - 1);
        SUM += 5.02808 * log10(RATIO);
        SUM += -1.3816e-7 * (pow(10, (11.344 * (1 - 1/RATIO ))) - 1) ;
        SUM += 8.1328e-3 * (pow(10, (-3.49149 * (RATIO - 1))) - 1) ;
        SUM += log10(1013.246);
        double VP = pow(10, SUM - 3) * humidity;
        double T = log(VP/0.61078);   // temp var
        return (241.88 * T) / (17.558 - T);
}

// delta max = 0.6544 wrt dewPoint()
// 5x faster than dewPoint()
double dewPointFast(double celsius, double humidity)
{
        double a = 17.271;
        double b = 237.7;
        double temp = (a * celsius) / (b + celsius) + log(humidity/100);
        double Td = (b * temp) / (a - temp);
        return Td;
}


si 

#include <dht11.h>
dht11 DHT11;
#define DHT11PIN A2 // sensor pin is at A2

void setup()
{
  Serial.begin(9600);
  Serial.println("DHT11 TEST PROGRAM ");
  Serial.print("LIBRARY VERSION: ");
  Serial.println(DHT11LIB_VERSION);
  }

void loop()
{
  Serial.println("\n");
  int chk = DHT11.read(DHT11PIN);
  Serial.print("Read sensor: ");
  switch (chk)
  {
    case DHTLIB_OK: 
                Serial.println("OK"); 
                break;
    case DHTLIB_ERROR_CHECKSUM: 
                Serial.println("Checksum error"); 
                break;
    case DHTLIB_ERROR_TIMEOUT: 
                Serial.println("Time out error"); 
                break;
    default: 
                Serial.println("Unknown error"); 
                break;
  }

  Serial.print("Humidity (%): ");
  Serial.println((float)DHT11.humidity, 2);

  Serial.print("Temperature (oC): ");
  Serial.println((float)DHT11.temperature, 2);

  Serial.print("Temperature (oF): ");
  Serial.println(Fahrenheit(DHT11.temperature), 2);

  Serial.print("Temperature (K): ");
  Serial.println(Kelvin(DHT11.temperature), 2);

  Serial.print("Dew Point (oC): ");
  Serial.println(dewPoint(DHT11.temperature, DHT11.humidity));

  Serial.print("Dew PointFast (oC): ");
  Serial.println(dewPointFast(DHT11.temperature, DHT11.humidity));
  delay(2000);

 //LCD16x2 with i2c control - see http://www.tehnic.go.ro
  lcd.init(); 
  lcd.backlight(); //voi aprinde si led-ul de fundal
  // set up the LCD's number of columns and rows: 
  //lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("ministatie meteo");
  lcd.setCursor(1, 1);
  // print the number of seconds since reset:
  lcd.print((float)DHT11.temperature, 1);
  lcd.write(0b11011111);
  lcd.print("C H=");
  lcd.print((float)DHT11.humidity, 1);
  lcd.print("%");
  delay(2000);
}




   Un filmulet, care prezinta modul de functionare, se numeste ministatie meteo cu DHT11, LCD1602 si Arduino (II)



    Am schimbat un pic aranjamentul din sketch:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x20,16,2); // 0x27 es la direccion del LCD 16x2

//Celsius to Fahrenheit conversion
double Fahrenheit(double celsius)
{
        return 1.8 * celsius + 32;
}

double Kelvin(double celsius)
{
        return celsius + 273.15;
}

double dewPoint(double celsius, double humidity)
{
        double RATIO = 373.15 / (273.15 + celsius);  // RATIO was originally named A0, possibly confusing in Arduino context
        double SUM = -7.90298 * (RATIO - 1);
        SUM += 5.02808 * log10(RATIO);
        SUM += -1.3816e-7 * (pow(10, (11.344 * (1 - 1/RATIO ))) - 1) ;
        SUM += 8.1328e-3 * (pow(10, (-3.49149 * (RATIO - 1))) - 1) ;
        SUM += log10(1013.246);
        double VP = pow(10, SUM - 3) * humidity;
        double T = log(VP/0.61078);   // temp var
        return (241.88 * T) / (17.558 - T);
}

// delta max = 0.6544 wrt dewPoint()
// 5x faster than dewPoint()
// reference: http://en.wikipedia.org/wiki/Dew_point
double dewPointFast(double celsius, double humidity)
{
        double a = 17.271;
        double b = 237.7;
        double temp = (a * celsius) / (b + celsius) + log(humidity/100);
        double Td = (b * temp) / (a - temp);
        return Td;
}

#include <dht11.h>
dht11 DHT11;
#define DHT11PIN A2 // sensor pin is at A2

void setup()
{
  Serial.begin(9600);
  Serial.println("DHT11 TEST PROGRAM ");
  Serial.print("LIBRARY VERSION: ");
  Serial.println(DHT11LIB_VERSION);
  
lcd.init(); 
  lcd.backlight(); //voi aprinde si led-ul de fundal
  // set up the LCD's number of columns and rows: 
  //lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("ministatie meteo");
}
void loop()
{
  Serial.println("\n");
  int chk = DHT11.read(DHT11PIN);
  Serial.print("Read sensor: ");
  switch (chk)
  {
    case DHTLIB_OK: 
                Serial.println("OK"); 
                break;
    case DHTLIB_ERROR_CHECKSUM: 
                Serial.println("Checksum error"); 
                break;
    case DHTLIB_ERROR_TIMEOUT: 
                Serial.println("Time out error"); 
                break;
    default: 
                Serial.println("Unknown error"); 
                break;
  }

  Serial.print("Humidity (%): ");
  Serial.println((float)DHT11.humidity, 2);

  Serial.print("Temperature (oC): ");
  Serial.println((float)DHT11.temperature, 2);

  Serial.print("Temperature (oF): ");
  Serial.println(Fahrenheit(DHT11.temperature), 2);

  Serial.print("Temperature (K): ");
  Serial.println(Kelvin(DHT11.temperature), 2);

  Serial.print("Dew Point (oC): ");
  Serial.println(dewPoint(DHT11.temperature, DHT11.humidity));

  Serial.print("Dew PointFast (oC): ");
  Serial.println(dewPointFast(DHT11.temperature, DHT11.humidity));
  delay(2000);

 //LCD16x2 with i2c control - see http://www.tehnic.go.ro
  
  lcd.setCursor(0, 1);
  lcd.print("t=");
  lcd.print((float)DHT11.temperature, 1);
  lcd.write(0b11011111);
  lcd.print("C H=");
  lcd.print((float)DHT11.humidity, 1);
  lcd.print("%");
  delay(2000);
}

   Am introdus si partea de "reclama": "www.tehnic.go.ro creat de niq_ro", apoi "ministatie meteo versiunea 1m1" pastrand si posibilitatea monitorizarii seriale pe ecranul monitorului.



#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x20,16,2); // 0x20 is adress my I2C adapter
#include <dht11.h>
dht11 DHT11;
#define DHT11PIN A2 // sensor pin is at A2

void setup()
{
  Serial.begin(9600);
  Serial.println("DHT11 TEST PROGRAM ");
  Serial.print("LIBRARY VERSION: ");
  Serial.println(DHT11LIB_VERSION);
  
lcd.init(); 
  lcd.backlight(); //voi aprinde si led-ul de fundal
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  // Print a logo message to the LCD.
  lcd.print("www.tehnic.go.ro");  
  lcd.setCursor(0, 1);
  lcd.print("creat de niq_ro");
  delay (2500);
  lcd.clear();
   
  // Print a permanent message to the LCD.
  lcd.print("ministatie meteo");
  lcd.setCursor(2, 1);
  lcd.print("versiunea 1m1");
  delay (2500);
}
void loop()
{
  Serial.println("\n");
  int chk = DHT11.read(DHT11PIN);
  Serial.print("Read sensor: ");
  switch (chk)
  {
    case DHTLIB_OK: 
                Serial.println("OK"); 
                break;
    case DHTLIB_ERROR_CHECKSUM: 
                Serial.println("Checksum error"); 
                break;
    case DHTLIB_ERROR_TIMEOUT: 
                Serial.println("Time out error"); 
                break;
    default: 
                Serial.println("Unknown error"); 
                break;
  }

  Serial.print("Humidity (%): ");
  Serial.println((float)DHT11.humidity, 2);

  Serial.print("Temperature (oC): ");
  Serial.println((float)DHT11.temperature, 2);

 //LCD16x2 with i2c control - see http://www.tehnic.go.ro
  lcd.setCursor(0, 1);
  lcd.print("t=");
  lcd.print((float)DHT11.temperature, 1);
  lcd.write(0b11011111);
  lcd.print("C H=");
  lcd.print((float)DHT11.humidity, 1);
  lcd.print("%");
  delay(2000);
}

   Filmuletul care prezinta cum se numeste ministatie meteo cu DHT11, LCD1602 si Arduino (III)
15.mai.2013
   Am refacut sketch-ul, cu versiunea 2m0, folosind alte biblioteci, obtinand:
 



#include "DHT.h"
#define DHTPIN A2     // what pin we're connected to
#define DHTTYPE DHT11   // DHT 11 
DHT dht(DHTPIN, DHTTYPE);

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x20,16,2); // 0x20 is adresss for LCC 16x2

void setup(){
  dht.begin();
  lcd.init(); 
  lcd.backlight(); //backlight is now ON
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  // Print a logo message to the LCD.
  lcd.print("www.tehnic.go.ro");  
  lcd.setCursor(0, 1);
  lcd.print(" creat de niq_ro");
  delay (2500);
  lcd.clear();
   
  lcd.print(" senzor DHT11 +");
  lcd.setCursor(0, 1);
  lcd.print("i2c pt. LCD 16x2");
  delay (2500);
  lcd.clear();
  
  lcd.print("ministatie meteo");
  lcd.setCursor(0, 1);
  lcd.print("  versiune 2m0");
  delay (2500);
  lcd.clear();
}
void loop(){
  int h = dht.readHumidity();
  int t = dht.readTemperature();
  // check if returns are valid, if they are NaN (not a number) then something went wrong!
  if (isnan(t) || isnan(h)) {
    lcd.clear();
    lcd.print(" eroare senzor");
    lcd.setCursor(5, 1);
    lcd.print("DHT11");
  } else {
    //lcd.clear();
    lcd.print("temperatura="); 
    lcd.print(t);
    lcd.write(0b11011111);
    lcd.print("C");
    lcd.setCursor(0, 1);
    lcd.print("  umiditate="); 
    lcd.print(h);
    lcd.print("% ");
    }
    delay (2000);
    }

   Un filmulet cu noul mod de prezentare se numeste ministatie meteo cu DHT11, LCD1602 si Arduino (IV).

   Deoarece parametrii masurati nu se modifica prea repede, avand in vedere ca masurarea nu se face cu zecimale, iar eroarea de masura e mare (+2 grade Celsius, ca sa nu mai zic la umiditate de +5 procente) am "pus" un punct care se aprinde cu intermitenta pe randul al doilea, sketch-ul devenind versiunea 2m1:
#include "DHT.h"
#define DHTPIN A2     // what pin we're connected to
#define DHTTYPE DHT11   // DHT 11 
DHT dht(DHTPIN, DHTTYPE);

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x20,16,2); // 0x20 is adresss for LCC 16x2

void setup(){
  dht.begin();
  lcd.init(); 
  lcd.backlight(); //backlight is now ON
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  // Print a logo message to the LCD.
  lcd.print("www.tehnic.go.ro");  
  lcd.setCursor(0, 1);
  lcd.print(" creat de niq_ro");
  delay (2500);
  lcd.clear();
   
  lcd.print(" senzor DHT11 +");
  lcd.setCursor(0, 1);
  lcd.print("i2c pt. LCD 16x2");
  delay (2500);
  lcd.clear();
  
  lcd.print("ministatie meteo");
  lcd.setCursor(0, 1);
  lcd.print("  versiune 2m1");
  delay (2500);
  lcd.clear();
}
void loop(){
  int h = dht.readHumidity();
  int t = dht.readTemperature();
  // check if returns are valid, if they are NaN (not a number) then something went wrong!
  if (isnan(t) || isnan(h)) {
    lcd.clear();
    lcd.print(" eroare senzor");
    lcd.setCursor(5, 1);
    lcd.print("DHT11");
  } else {
    //lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("temperatura="); 
    lcd.print(t);
    lcd.write(0b11011111);
    lcd.print("C");
    lcd.setCursor(2, 1);
    lcd.print("umiditate="); 
    lcd.print(h);
    lcd.print("%");
    }
    delay (2000);
    lcd.setCursor(0, 1);
    lcd.print(".");
    delay(250);
    lcd.setCursor(0, 1);
    lcd.print(" ");
}

8 comentarii:

  1. buna ziua, ma intereseaza daca pot cumpara de la dumneavoastra acest proiect. ma refer la partea hardware gata facuta + software . Multumesc

    RăspundețiȘtergere
    Răspunsuri
    1. Buna ziua.
      teoretic da, practic, daca ne intelegem..
      astept un mail pe nicu.florica@gmail.com ...

      Ștergere
  2. salutare , ce sansa e sa postezi aceasta schema pentru atmega8 cu tot cu hex?
    am mai multe atmega care stau degeaba si nu vreau sa folosesc arduino

    RăspundețiȘtergere
    Răspunsuri
    1. Salut, salut, sigur ca se poate, trebuie sa te hotarasti ce sa afiseze... eu o sa testez pe Arduino si apoi complilez pentru ATmega8 si iti dau sa testezi... astept mail

      Ștergere
    2. pai ce sa afiseze?
      Temperatura - xx C
      Umiditate - xx %
      momentan astept senzorul sa vina( de abia l-am comandat)
      problema e ca eu chiar daca extrag hexul nu stiu ce fusebiti trebuie setati pt atmega
      ms

      Ștergere
  3. ok, sa vad ce ATmega8 pot folosi (oscilator intern, cuart si ce frecventa) si apoi sa calculam fusebit-ii...

    RăspundețiȘtergere
    Răspunsuri
    1. daca e problema de spatiu se poate folosi si 328 , oricum in functie ce timp liber aveti
      ms

      Ștergere
  4. intra in ATmega8 sigur... daca vrei mai multa precizie, ia AM2302 (DHT22)... dar facem test cu DHT11 si apoi modificam...

    RăspundețiȘtergere