sábado, 3 de diciembre de 2016

Sensor de presión atmosférica BMP180

El sensor BMP180 es un sensor de presión atmosférica de alta precisión diseñado para ser conectado directamente a un microcontrolador a través de un bus I2C. 

La presión atmosférica es la fuerza que ejerce el aire (atmósfera) sobre la superficie de la tierra por lo que a mayor altura la presión atmosférica es menor. La presión atmosférica también varía con el clima, principalmente con la temperatura, pues esta hace cambiar la densidad del aire, que se ve reflejado en un cambio en el peso y por consiguiente en un cambio de presión. Otros factores que influyen es la humedad y el viento que también influye en la presión pero su influencia es mucho menor y se suele discriminar.

El sensor BMP180 es capaz de leer presión barométrica (absoluta) y temperatura. Por medio de cálculos matemáticos es capaz de detectar diferencias de alturas ya que, como mencionamos, la presión atmosférica es inversamente proporcional a la altura sobre el nivel del mar, es decir, a medida que nos elevamos decrece la presión. 




Este sensor vine en diversos módulos que nos ayudan en su conexión, el que usaremos para este tutorial es el módulo de la figura anterior.

Características del Sensor BMP180
  • Digital interfaz de dos cables (I2C)
  • Amplio rango de medición de presión barométrica
  • Ultra-bajo consumo de energía
  • Bajo ruido
  • Completamente calibrado
  • Medición de temperatura incluida
  • Ultraplano y pequeño tamaño
  • Alimentación: 1.8V – 3.6V
  • Rango de medición: 300 – 1100hPa
  • Velocidad del protocolo máxima: 3.4 MHz.
La distribución de los pines es la siguiente:


Este módulo cuenta con la electrónica necesaria para conectarlo directamente a los módulos Arduino/ESP8266 sin utilizar componentes adicionales.

El bus I2C

A principio de los 80 Phillips propuso una norma de comunicación digital, entre los diferentes componentes de una sistema electrónico, una norma que especificaba la velocidad, niveles de tensión,  y el protocolo a seguir para conseguir esa comunicación y la hizo abierta.

Esa norma se llamó Inter Integrated Circuits bus, o IIC, y pronto se convirtió en un estándar de facto en la industria. Las especificaciones han ido mejorando con los años, pero la idea básica sigue siendo la misma:
  • Protocolo de dos hilos de control, uno para transmitir los datos, SDA y otro, el reloj asíncrono que indica cuando leer los datos SCL. Mas GND y 5V (cuando se requiera).
  • Cada dispositivo conectado al bus I2C tiene su dirección exclusiva, de 7 bits asi que, en teoría, podemos conectar hasta 128, dispositivos.
  • Uno de estos componentes, debe actuar como master, es decir controla el reloj.
  • No se requiere una velocidad de reloj estricta, ya que es el master quien controla el reloj.
  • Es multi master, es decir, el master puede cambiar pero solo uno puede estar activo a la vez, y proporciona un protocolo de arbitraje y detección de colisiones
La idea es que todos los componentes se conecten en paralelo a las dos líneas del Bus, SDA y SCL. En cada momento solo puede haber un master (en nuestro caso el ESP8266) y los demás se configuran como esclavos.

Puede haber más de un master. La norma propone un sistema de arbitraje, para transferir el control de uno a otro, pero en un instante dado, solo uno puede ser el master.

Además hay unas resistencias de pull-up conectadas a SDA y SCL. Estas son necesarias, ya que el bus es activo a nivel bajo (la señal activa es un 0, no un 1). Cuando vayas a conectar algo al busI2C, es imprescindible leer el manual para saber si las resistencias pull-ups los tienes que poner tú, o vienen puestos en el componente (en el caso delmódulo  BMP180 que vamos a usar incluye dichas resistencias).

Arduino soporta de fábrica con una librería estándar, que utiliza dos de los pines analógicos para las funciones SDA (Datos) y SCL (Clock).
  • En el Arduino UNO, los pines I2C están en los pines analógicos A4 (SDA) y A5 (SCL).
  • En el Arduino Mega y DUE, son el 20 (SDA) y en el 21(SCL).
  • En el ESP8266, D1 - GPIO05 (SCL) y D2 - GPIO04 (SDA) 
Se utiliza la librería Wire.h para gestionar el puerto i2C

Librería para el sensor de presión  BMP180

Para este tutorial utilizaremos la librería desarrollada por Sparkfun. Hacemos click en el menú Programa - Incluir librería - Gestionar librerías y buscamos por bmp180. Instalaremos la librería. Con esta librería nos ahorramos todo el cálculo matemático necesario para obtener los diferentes parámetros.


Estas librerías Unified de Adafruit necesitan tambien la instalación de la librería Adafruit Unified Sensor que se instalará como en el caso anterior

Conexiones entre el módulo ESP8266 y el sensor BMP180:
  • VIN: 3.3v
  • GND: 0v
  • SCL (Clk): D1 - GPIO05
  • SDA (Tx): D2 - GPIO04

Medidas de altitud

Dado que sabemos que la presión cae a medida que ganamos altura (es por eso que el aire es tan delgado en las cumbres de las montañas) podemos calcular la altitud actual sabiendo la presión y la temperatura. La librería se encarga de realizar estos cálculos.


Para realizar un cálculo exacto de la altitud deberíamos conocer exactamente la presión a nivel del mar de la zona en que nos encontramos. Cada 1 hPa de presión del nivel del mar que nos equivoquemos equivale a unos 8,5 m de error en los cálculos de altitud. En mi caso, la presión atmosférica a nivel del mar es de 1009.4 hPa que lo he obtenido en el siguiente enlace que es el de una estación a nivel del mar en las Islas Canarias y, según he leido en el ejemplo que viene con la librería, el valor que utiliza la librería es de 1013.25 hPa (indica que este valor se define en SENSORS_PRESSURE_SEALEVELHPA en sensors.h).

En el ejemplo originalmente se utilizaba la sentencia:
float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA;

pero yo lo podría modificar para ajustarlo a mi zona:
float seaLevelPressure = 1009.40;

De todas formas, en el ejemplo utilizaré el valor SENSORS_PRESSURE_SEALEVELHPA

Nota: La presión se mide en hectoPascales (hPa). Un milibar tiene exactamente el mismo valor que un hectopascal, por ello el uso de ambas unidades es intercambiable. (1 mbar = 1 hPa), múltiplo (×100) del pascal.

Código

Debemos incluir las siguientes librerías:
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP085_U.h>


Creamos una instancia de la librería:
Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10085);

Para inicializar el sensor:
if (!bmp.begin()) {...}

Podemos obtener las características del sensor y lo enviamos al puerto serie:
sensor_t sensor; // Crea un instancia del tipo sensor_t
bmp.getSensor(&sensor);

Serial.print....

Para realizar una medición:
sensors_event_t event;
bmp.getEvent(&event);


Para obtener la presión:
if (event.pressure) {...}

Para obtener la temperatura:
float temperature;
bmp.getTemperature(&temperature);


Por útltimo, para obtener la altitud referenciamos la presión obtenida con la presión a nivel del mar:
float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA;
bmp.pressureToAltitude(seaLevelPressure, event.pressure));

El código completo es el siguiente:
 

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP085_U.h>

Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10085);

// Muestra las características del sensor
void displaySensorDetails(void){
  sensor_t sensor;

  bmp.getSensor(&sensor);
  Serial.println("------------------------------------");
  Serial.print  ("Sensor: ");
  Serial.println(sensor.name);
  Serial.print  ("Driver: ");
  Serial.println(sensor.version);
  Serial.print  ("ID: ");
  Serial.println(sensor.sensor_id);
  Serial.print  ("Max Valor: ");
  Serial.print(sensor.max_value);
  Serial.println(" hPa");
  Serial.print  ("Min Valor: ");
  Serial.print(sensor.min_value);
  Serial.println(" hPa");
  Serial.print  ("Resolucion: ");
  Serial.print(sensor.resolution);
  Serial.println(" hPa");
  Serial.println("------------------------------------");
  Serial.println("");
  delay(1000);
}

void setup(void) {
  Serial.begin(9600);
  Serial.println("\nPrueba del sensor de presión");
  Serial.println("");
  if (!bmp.begin()) { // Initicializa el sensor
    // Error en la detección del sensor
    Serial.print("Ooops, BMP085 no detectado ... Comprueba las conexiones!");
    while (1); // Bucle infinito
  }
    displaySensorDetails();
}

void loop(void) {
  // Obtiene un nuevo evento del sensor
  sensors_event_t event;
  bmp.getEvent(&event);

  // Muestra los resultados
  if (event.pressure) {
    // Muestra la presión atmosférica en hPa
    Serial.print("Presion: ");
    Serial.print(event.pressure);
    Serial.println(" hPa");
    // Obtenemos la temperatura
    float temperature;
    bmp.getTemperature(&temperature);
    Serial.print("Temperatura: ");
    Serial.print(temperature);
    Serial.println(" C");
    // Cálculo de la altura
    float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA;
    Serial.print("Altitud: ");
    Serial.print(bmp.pressureToAltitude(seaLevelPressure, event.pressure));
    Serial.println(" m");
    Serial.println("");
  }
  else {
    Serial.println("Error en el sensor");
  }
  delay(20000); // Muestras cada 20 seg.
}



Como en artículos anteriores, vamos a modificar el programa para enviar los datos a ThingSpeak:

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP085_U.h>
#include <ThingSpeak.h>
#include <ESP8266WiFi.h>

const char* ssid = "SSID";
const char* password = "PASSWORD";
WiFiClient  client;
unsigned long myChannelNumber = ID_CHANNEL;
const char* myWriteAPIKey = "API_KEY"; // API Key ThinkSpeak

// Creamos una instancia de la librería
Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10085);

// Muestra las características del sensor
void displaySensorDetails(void){
  sensor_t sensor; // Crea un instancia del tipo sensor_t
  bmp.getSensor(&sensor);
  Serial.println("------------------------------------");
  Serial.print  ("Sensor: ");
  Serial.println(sensor.name);
  Serial.print  ("Driver: ");
  Serial.println(sensor.version);
  Serial.print  ("ID: ");
  Serial.println(sensor.sensor_id);
  Serial.print  ("Max Valor: ");
  Serial.print(sensor.max_value);
  Serial.println(" hPa");
  Serial.print  ("Min Valor: ");
  Serial.print(sensor.min_value);
  Serial.println(" hPa");
  Serial.print  ("Resolucion: ");
  Serial.print(sensor.resolution);
  Serial.println(" hPa");
  Serial.println("------------------------------------");
  Serial.println("");
  delay(1000);
}

void setup(void) {
  Serial.begin(9600);
  WiFi.mode(WIFI_STA); //Establece el módulo como cliente wifi
  WiFi.disconnect(); //Se desconecta de cualquier WiFi conectado
  delay(100);
  Serial.println();
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {   // wait for WiFi
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  Serial.println();

  ThingSpeak.begin(client);

  Serial.println("\nPrueba del sensor de presion");
  Serial.println("");
  if (!bmp.begin()) { // Initicializa el sensor
    // Error en la detección del sensor
    Serial.print("Ooops, BMP085 no detectado ... Comprueba las conexiones!");
    while (1); // Bucle infinito
  }
  // Muestra información básica del sensor
  displaySensorDetails();
}

void loop(void) {
  // Obtiene un nuevo evento del sensor
  sensors_event_t event;
  bmp.getEvent(&event);

  // Muestra los resultados
  if (event.pressure) {
    // Muestra la presión atmosférica en hPa
    Serial.print("Presion: ");
    Serial.print(event.pressure);
    Serial.println(" hPa");
    // Obtenemos la temperatura
    float temperature;
    bmp.getTemperature(&temperature);
    Serial.print("Temperatura: ");
    Serial.print(temperature);
    Serial.println(" C");
    // Cálculo de la altura
    float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA;
    Serial.print("Altitud: ");
    Serial.print(bmp.pressureToAltitude(seaLevelPressure, event.pressure));
    Serial.println(" m");
    Serial.println("");

    ThingSpeak.setField(1, (float)event.pressure);
    ThingSpeak.setField(2, (float)temperature);
    ThingSpeak.setField(3, (float)bmp.pressureToAltitude(seaLevelPressure, event.pressure));
    ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);

  }
  else {
    Serial.println("Error en el sensor");
  }
  delay(20000); // Muestras cada 20 seg.
}





Fuentes:
Tutorial Sensor BMP180 con Arduino
Tutorial sensor de presión barométrica BMP180
El bus i2C
BMP085. Overview

No hay comentarios:

Publicar un comentario

Nota: solo los miembros de este blog pueden publicar comentarios.