BMP180
- Stazione meteo con Arduino -
- Weather Station with Arduino -
- 24/02/2014 -
Con questo post continua la costruzione della "nostra" stazione meteorologica.
This post continue the project for the weather station.
Oggi utilizziamo il sensore di pressione BMP180
Today we use the pressure sensor BMP180
In questo post riporto le modifiche fatte allo sketch che gestiva il sensore DHT22 ( temperatura e umidità relativa).
Ho aggiuto il sensore di pressione BMP180, al precedente schema.
Vale la pena di segnalare che il sensore BMP180 utilizza la seriale I2C.
Vale la pena di segnalare che il sensore BMP180 utilizza la seriale I2C.
Adriano ha integrato lo sketch seguendo le indicazioni del costruttore "sparkfun".
Per quanto riguarda il funzionamento ed i collegamenti alla scheda Arduino abbiamo seguito quanto indicato nel Tutorial bmp180.
Nel Tutorial si trovano le istruzioni per il collegamento, la libreria da utilizzare e lo sketch di esempio. (scaricate la libreria dal tutorial della Sparkfun.)
Quello che abbiamo fatto è stato solo di collegare il sensore , installare la libreria e aggiungere al precedente sketch la parte relativa alla misura della pressione.
Qui sotto parte dello sketch riguardante il funzionamento del sensore BMP180.
Lo sketch completo si può scaricare nel link più in basso
Lo sketch completo si può scaricare nel link più in basso
//------------------------------------------------------------------------------------------
// Metodi lettura dati sensore pressione BMP180 // -------------------------------------------------------------------------------- void setup_BMP() { Serial.print("Inizializzazione BMP..."); lcd.print("Configurazione..."); // Inizializza il sensore di pressione // in questa fase il sensore recupera dei valori memorizzati al suo interno che usa per la sua calibrazione if (pressure.begin()) { Serial.println("OK"); Serial.print("Altitudine sensore: "); Serial.println(ALTITUDINE); } else { // L'inizializzazione puo' fallire a causa di problemi di connessione con il bus Serial.println("ERRORE!! "); while(1); // Attesa infinita --> resettare arduino } } // legge i valori di temperatura e pressione interrogando il sensore BMP boolean leggi_temperatura_e_pressione(double& temp, double& pres, double& pr, double& alt) { boolean res = false; double T, P, p0, a; // Prima di poter leggere la pressione e' necessario effettuare una lettura della // temperatura // Invia il comando per iniziare la lettura della temperatura // Se il comando ha successo ritorna il numero di millisecondi da attendere prima di ricevere il dato // In caso di errore ritorna 0 int stat = pressure.startTemperature(); if (stat != 0) { // Attende il completamento della lettura della temperatura delay(stat); // Adesso si puo' recuperare il valore, il valore è salvato in T stat = pressure.getTemperature(T); if (stat != 0) { // si ripete il procedimento per la lettura della pressione // Il parametro 3 indica la precisione (lettura piu' lenta) stat = pressure.startPressure(3); if (stat != 0) { delay(stat); // Si legge il valore della pressione assoluta e si salva in P // la funzione richiede la temperatura corrente stat = pressure.getPressure(P, T); // calcola la pressione relativa, compensando con l'altitudine locale p0 = pressure.sealevel(P, ALTITUDINE); // Infine calcola l'altitudine in base alla pressione misurata e alla pressione al livello del mare a = pressure.altitude(P, p0); // la lettura ha avuto successo, si aggiornano le variabili res = true; pres = P; temp = T; pr = p0; alt = a; } } } return res; }
Come potete leggere nei commenti prima si deve eseguire l'inizializzazione del sensore, successivamente si esegue la misura della temperatura, e solo dopo questa si può misurare la pressione.
Il sensore ha i suoi tempi tutta la procedura non è molto veloce, nell'uso del pulsante per il cambio della visualizzazione sull'LCD si nota un ritardo fra la pressione del pulsante e il risultato mostrato.
Lo scopo dello sketch attuale è solo di verificare l'uso del sensore di pressione, nell'uso definitivo i dati verrano registrati.
Nello sketch si utilizzano le seguenti librerie:
LiquidCrystal.h // libreria LCD
dht.h // libreria sensore temperatura e umidita
SFE_BMP180.h // libreria sensore pressione
Wire.h // wire per comunicazione bus I2C.
==============================
Lo sketch
==============================
/*
*** Sergio & Adriano Prenleloup ****
***** Stazione Meteo *********
*** Temperatura, Umidità ****
*** pressione atmosferica ****
*** Versione 1.01 ************
****** 22/02/2014 **********
******************************
**sensore DHT22 *************
**sensore BMP180 ************
* Rileva Temperatura e Umidità mediante il sensore DHT22
* e mostra i dati su display LCD 2002A (20 caratteri, 2righe)
* Inoltre gestisce con pulsante la lettura
* di temperatura minima e massima e lo switch
* per mostrare le informazioni sul display
*
* schema e ulteriori informazioni
* sul sito http://avventurarduino.blogspot.it
* Circuito
* LCD GND -> blu -> pin 14
* LCD RS -> marrone -> pin 13
* LCD ENABLE -> giallo -> pin 12
* LCD D4 (11) -> marrone -> pin 10
* LCD D5 (12) -> rosso -> pin 9
* LCD D6 (13) -> verde -> pin 11
* LCD D7 (14) -> arancio -> pin 8
* LCD 5v -> rosso -> pin 5v
*
* Pin DHT 22 -> pin 5
* Pin bottone switch -> pin 2
*
* Sensore pressione BMP180
* SDA -> A4
* SCL -> A5
*/
#include <LiquidCrystal.h> // libreria LCD
#include <dht.h> // libreria sensore temperatura e umidita
#include <SFE_BMP180.h> // libreria sensore pressione
#include <Wire.h> // wire per comunicazione bus
// Configurazione PIN
// --------------------------------------------------------------------------------
#define MIN_MAX_BUTTON_PIN 2 //pulsante
#define DHT22_PIN 5 // piedino dati sensore DHT
// pin digitali utilizzati per il display LCD
#define LCD_RS_PIN 13
#define LCD_EN_PIN 12
#define LCD_D4_PIN 10
#define LCD_D5_PIN 9
#define LCD_D6_PIN 11
#define LCD_D7_PIN 8
#define SDA_PIN 4
#define SCL_PIN 5
// Dichiarazione classi lcd e dht e chiamate costruttori
// --------------------------------------------------------------------------------
// Inizializa la libreria per la gestione dell'LCD
// LiquidCrystal(rs, enable, d4, d5, d6, d7)
LiquidCrystal lcd(LCD_RS_PIN, LCD_EN_PIN, LCD_D4_PIN, LCD_D5_PIN, LCD_D6_PIN, LCD_D7_PIN);
// Inizializza la libreria per comunicare con il sensore DHT22
dht DHT;
// Inizializza la libreria per lettura dati pressione
SFE_BMP180 pressure;
// Costanti e variabili gestione stato corrente dei bottoni
// --------------------------------------------------------------------------------
const int MODO_AMBIENTE = 0; // questo stato visualizza Temp. ambiente ed umidità
const int MODO_MINMAX = 1; // questo stato visualizza Temp MIN e Temp. MAX
const int MODO_PRESSIONE = 2; // questo stato visualizza Pressione atmosferica
const int MODO_ALTITUDINE = 3; // questo stato visualizza Pressione atmosferica
int stato_bottoni[3];
boolean stato_switch[3];
int stato_menu[0];
int switch_counter[0];
int modo_corrente = MODO_AMBIENTE;
// Array contenente tutti i dati raccolti
// --------------------------------------------------------------------------------
double dati[8];
// Costanti e variabili gestione temp max e temp min
// --------------------------------------------------------------------------------
double temp_Max = 0.0;
double temp_Min = 99.0;
// Variabili gestione temp e umidita
// --------------------------------------------------------------------------------
double temp_old = -1.0;
double umid_old = -1.0;
double temp_corrente = 0.0;
double umid_corrente = 0.0;
// Variabili gestione pressione e altitudine
// --------------------------------------------------------------------------------
#define ALTITUDINE 234.3 // Altitude del luogo dove si trova il sensore (in metri)
double t_corrente = 0.0;
double t_old = 0.0;
double p_corrente = 0.0;
double p_old = 0.0;
double pr_corrente = 0.0;
double pr_old = 0.0;
double a_corrente = 0.0;
double a_old = 0.0;
// Variabili gestione lettura
// --------------------------------------------------------------------------------
const int DELAY_LETTURE = 10000; //tempo tra le letture in millisecondi
unsigned long ora_lettura = millis();
// --------------------------------------------------------------------------------
// Metodi gestione bottoni
// --------------------------------------------------------------------------------
void setup_bottoni()
{
pinMode (MIN_MAX_BUTTON_PIN, INPUT);
stato_bottoni[0] = 0;
stato_switch[0] = false;
switch_counter[0] = 0;
stato_menu[0] = MODO_AMBIENTE;
}
void aggiorna_stato_bottone(int bottone, int& statoBottoneVecchio, boolean& statoSwitch, int& switchCounter)
{
//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;
switchCounter++;
}
//il nuovo stato diventa lo stato corrente
statoBottoneVecchio = statoBottoneCorrente;
}
}
void controlla_bottone()
{
switch_counter[0] = modo_corrente;
aggiorna_stato_bottone(MIN_MAX_BUTTON_PIN, stato_bottoni[0], stato_switch[0], switch_counter[0]);
if (switch_counter[0] == 4) switch_counter[0] = 0;
stato_menu[0] = switch_counter[0];
}
int modo_operativo_menu()
{
if (stato_menu[0] == MODO_ALTITUDINE) return MODO_ALTITUDINE;
if (stato_menu[0] == MODO_PRESSIONE) return MODO_PRESSIONE;
if (stato_menu[0] == MODO_MINMAX) return MODO_MINMAX;
return MODO_AMBIENTE;
}
// Metodi gestione aggiornamento e Min, Max temp
// --------------------------------------------------------------------------------
// Aggiorna le temperature minime e massime solo se necessario
void aggiorna_min_max(double temp)
{
if (temp > temp_Max)
{
temp_Max = temp;
}
if (temp < temp_Min)
{
temp_Min = temp;
}
}
// ritorna true se una tra le due (temperatura o umidità) è cambiata rispetto all'ultima lettura effettuata
boolean da_aggiornare(double temp_corrente, double umid_corrente, double temp_old, double umid_old)
{
return temp_corrente != temp_old || umid_corrente != umid_old;
}
// ritorna true se una tra le due (temperatura o umidità) è cambiata rispetto all'ultima lettura effettuata
boolean da_aggiornare_pressione(double p_corrente, double p_old)
{
return p_corrente != p_old;
}
// Metodi lettura dati sensore
// --------------------------------------------------------------------------------
void setup_DHT()
{
Serial.print("Inizializzazione DHT...");
lcd.print("Configurazione...");
// All'avvio il sensore DHT e' disponibile dopo due secondi
delay(2000);
lcd.clear();
Serial.println("OK");
Serial.println("Umid (%),\tTemp (C),\tTemp MIN (C),\tTemp MAX (C)");
}
// legge i valori di temperatura e umidità interrogando il sensore
// ritorna true se la lettura ha avuto successo false in caso di errore
boolean leggi_temperatura_e_umidita(double& temp, double& umidita)
{
// Avvia la lettura e legge lo stato
int chk = DHT.read22(DHT22_PIN);
switch (chk)
{
case DHTLIB_OK:
//Serial.print("OK,\t");
break;
case DHTLIB_ERROR_CHECKSUM:
Serial.println("Checksum error,\t");
return false;
case DHTLIB_ERROR_TIMEOUT:
Serial.println("Time out error,\t");
return false;
default:
Serial.println("Unknown error,\t");
return false;
}
// se la lettura ha avuto successo, i due valori sono disponibili nelle
// due variabili corrispondenti
temp = DHT.temperature;
umidita = DHT.humidity;
return true;
}
// Metodi lettura dati sensore pressione BMP180
// --------------------------------------------------------------------------------
void setup_BMP()
{
Serial.print("Inizializzazione BMP...");
lcd.print("Configurazione...");
// Inizializza il sensore di pressione
// in questa fase il sensore recupera dei valori memorizzati al suo interno che usa per la sua calibrazione
if (pressure.begin())
{
Serial.println("OK");
Serial.print("Altitudine sensore: ");
Serial.println(ALTITUDINE);
}
else
{
// L'inizializzazione puo' fallire a causa di problemi di connessione con il bus
Serial.println("ERRORE!! ");
while(1); // Attesa infinita --> resettare arduino
}
}
// legge i valori di temperatura e pressione interrogando il sensore BMP
boolean leggi_temperatura_e_pressione(double& temp, double& pres, double& pr, double& alt)
{
boolean res = false;
double T, P, p0, a;
// Prima di poter leggere la pressione e' necessario effettuare una lettura della
// temperatura
// Invia il comando per iniziare la lettura della temperatura
// Se il comando ha successo ritorna il numero di millisecondi da attendere prima di ricevere il dato
// In caso di errore ritorna 0
int stat = pressure.startTemperature();
if (stat != 0)
{
// Attende il completamento della lettura della temperatura
delay(stat);
// Adesso si puo' recuperare il valore, il valore è salvato in T
stat = pressure.getTemperature(T);
if (stat != 0)
{
// si ripete il procedimento per la lettura della pressione
// Il parametro 3 indica la precisione (lettura piu' lenta)
stat = pressure.startPressure(3);
if (stat != 0)
{
delay(stat);
// Si legge il valore della pressione assoluta e si salva in P
// la funzione richiede la temperatura corrente
stat = pressure.getPressure(P, T);
// calcola la pressione relativa, compensando con l'altitudine locale
p0 = pressure.sealevel(P, ALTITUDINE);
// Infine calcola l'altitudine in base alla pressione misurata e alla pressione al livello del mare
a = pressure.altitude(P, p0);
// la lettura ha avuto successo, si aggiornano le variabili
res = true;
pres = P;
temp = T;
pr = p0;
alt = a;
}
}
}
return res;
}
// Gestione LCD
// --------------------------------------------------------------------------------
void setup_LCD()
{
lcd.begin(20, 2);
}
// funzioni di utilità per stampare i valori su lcd (min e max)
void print_min_max_lcd(double t_min, double t_max)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("T MAX: ");
lcd.print(t_max, 1);
lcd.print(" C");
lcd.setCursor(0, 1);
lcd.print("T MIN: ");
lcd.print(t_min, 1);
lcd.print(" C");
}
// funzioni di utilità per stampare i valori su lcd (temp e umid)
void print_temp_umid_lcd(double temp, double umid)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Temp : ");
lcd.print(temp, 1);
lcd.print(" C");
lcd.setCursor(0, 1);
lcd.print("Umid : ");
lcd.print(umid, 1);
lcd.print(" %");
}
void print_temp_press_lcd(double temp, double pres)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Temp : ");
lcd.print(temp, 1);
lcd.print(" C");
lcd.setCursor(0, 1);
lcd.print("Pres : ");
lcd.print(pres, 1);
lcd.print(" mb");
}
void print_pr_altitudine_lcd(double pr, double alt)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Pres. rel. : ");
lcd.print(pr, 1);
lcd.print(" mb");
lcd.setCursor(0, 1);
lcd.print("Altitudine : ");
lcd.print(alt, 1);
lcd.print(" m");
}
// in base al modo operativo stampa le info ambiente o min e max registrati
// il modo operativo si cambia agendo sullo switch
void print_dati_lcd2(double dati[])
{
int modo = modo_operativo_menu();
if (modo == MODO_MINMAX)
{
print_min_max_lcd(dati[2], dati[3]);
}
else if (modo == MODO_PRESSIONE)
{
print_temp_press_lcd(dati[4], dati[5]);
}
else if (modo == MODO_ALTITUDINE)
{
print_pr_altitudine_lcd(dati[6], dati[7]);
}
else
{
print_temp_umid_lcd(dati[0], dati[1]);
}
}
void print_dati_consoleA(double temp, double umid, double t_min, double t_max)
{
Serial.println("Dati rilevati DHT22");
Serial.println("===================");
Serial.print ("Umidita' (%) : "); Serial.println(umid, 1);
Serial.print ("Temp. (C) : "); Serial.println(temp, 1);
Serial.print ("Temp. MIN (C) : "); Serial.println(t_min, 1);
Serial.print ("Temp. MAX (C) : "); Serial.println(t_max, 1);
}
void print_dati_consoleB(double temp, double pa, double pr, double alt)
{
Serial.println("Dati rilevati BMP180");
Serial.println("====================");
Serial.print ("Temperatura (C) : "); Serial.println(temp, 1);
Serial.print ("Pr. assoluta (mb) : "); Serial.println(pa, 1);
Serial.print ("Pr. relativa (mb) : "); Serial.println(pr, 1);
Serial.print ("Altitudine (m) : "); Serial.println(alt, 1);
}
// Logica per lettura e aggiornamento dati
// --------------------------------------------------------------------------------
// ritorna true se dall'ultima lettura è trascorso il tempo fissato
boolean check_timeout()
{
unsigned long ora_corrente = millis();
return ora_corrente > ora_lettura;
}
void effettua_lettura()
{
// si leggono i dati dal sensore di umidita'
if (leggi_temperatura_e_umidita(temp_corrente, umid_corrente))
{
// se la lettura ha avuto successo e i dati sono cambiati...
if (da_aggiornare(temp_corrente, umid_corrente, temp_old, umid_old))
{
//... si aggiornano con i nuovi valori
temp_old = temp_corrente;
umid_old = umid_corrente;
//..si aggiorna il vettore con tutti i dati
dati[0] = temp_corrente;
dati[1] = umid_corrente;
dati[2] = temp_Min;
dati[3] = temp_Max;
// e si mostrano su lcd e console
//print_dati_lcd(temp_corrente, umid_corrente, temp_Min, temp_Max);
print_dati_lcd2(dati);
print_dati_consoleA(temp_corrente, umid_corrente, temp_Min, temp_Max);
}
// si controlla se min e max sono cambiati
aggiorna_min_max(temp_corrente);
}
// si leggono i dati dal sensore di pressione
if (leggi_temperatura_e_pressione(t_corrente,p_corrente, pr_corrente, a_corrente))
{
if (da_aggiornare_pressione(p_corrente, p_old))
{
p_old = p_corrente;
t_old = t_corrente;
dati[4] = t_corrente;
dati[5] = p_corrente;
dati[6] = pr_corrente;
dati[7] = a_corrente;
//print_dati_lcd(temp_corrente, umid_corrente, temp_Min, temp_Max, p_corrente);
print_dati_lcd2(dati);
print_dati_consoleB(t_corrente, p_corrente, pr_corrente, a_corrente);
}
}
//imposta l'ora della prossima lettura, da ora a "DELAY_LETTURE" millisecondi
ora_lettura = millis() + DELAY_LETTURE;
}
// setup generale
// e loop principale sketch
//
// --------------------------------------------------------------------------------
void setup()
{
Serial.begin(9600);
setup_bottoni();
setup_LCD();
setup_DHT();
setup_BMP();
}
void loop()
{
controlla_bottone();
int modo = modo_operativo_menu();
// si controlla se è giunto il momento di effettuare le letture
if (check_timeout())
{
// se si, allora si recuperano i dati e si imposta l'ora della prossima lettura
effettua_lettura();
}
else if (modo != modo_corrente)
{
// se è stato premuto il bottone ed è cambiato il modo si fa refresh dell'lcd
//print_dati_lcd(temp_corrente, umid_corrente, temp_Min, temp_Max);
print_dati_lcd2(dati);
modo_corrente = modo;
}
// delay(10);
}
// END
==================================
Il bus I2C
Questo sistema di comunicazione seriale, che utilizza 2 fili, è molto interessante e prossimamente farò un post con esperimenti che utilizzano questo bus, e soprattutto la libreria che Arduino mette a disposizione per un facile utilizzo,( la libreria Wire.)
Al centro il sensore DHT22 (bianco) a destra il BMP180 (rosso).
Sul mio canale un breve filmato.
continua.....
Non è che si può avere lo schema di montaggio??
RispondiEliminaSi sul post Stazione meteo v.103 trovi lo schema realizzato con friz. dovrebbe essere molto chiaro.
EliminaIn caso contrario contattatemi ancora e pubblicherò altro.
Sergio
si potrebbe avere lo schema di montaggio
RispondiEliminaSi sul post Stazione meteo v.103 trovi lo schema realizzato con friz. dovrebbe essere molto chiaro.
EliminaIn caso contrario contattatemi ancora e pubblicherò altro.
Sergio
è possibile avere lo schema friz.. solo di sti componenti invece che di tutto
RispondiEliminaCiao!
EliminaDovrebbe essere semplice basterà cancellare ciò che non si vuole.
Quali sono i componenti che dovrebbero rimanere?
Lo schema completo comprende:
Arduino uno --> SI
Lcd --> SI ?
DHT22 --> SI ?
BMP180 --> SI ?
Anemometro --> No?
Pluviometro --> No?
Direz. Vento --> No?
Ditemi come e vedo se trovo il tempo per sistemarlo.
In ogni caso il BMP180 in realtà nello schema è sostituito dal bmp085 in quanto nel mio friz il 180 non c'è fra quelli selezionabili.
Sergio
ciao invece i collegamenti con un i2c lcd seriale ?
RispondiEliminaCiao!
EliminaGrazie per la lettura.
Ho pubblicato su questo blog 2 post relativi alla I2C.
Ho pubblicato Rfid, e calcolatrice che fanno uso di un lettore LCD I2C.
Ricordati che in caso di più elementi sulla linea si dovrebbero mettere 2 resistenze, in ogni caso controlla la documentazione ufficiale del dispositivi che colleghi.
Anche per selezionare l'indirizzo diverso per ogni dispositivo sulla linea.
Con LCD e BMP non dovrebbero esserci conflitti in ogni caso è spesso possibile configurare il dispositivo con dei ponticelli ( vedi la documentazione del tuo dispositivo).
Fai sapere ai lettori se sei riuscito a fare il collegamento.
Cordiali saluti
Sergio.